diff --git a/build.sh b/build.sh
index c63d810..d7951c6 100755
--- a/build.sh
+++ b/build.sh
@@ -42,7 +42,7 @@ echo ""
echo "$ cd" $(pwd)/demo/simple
echo "$ docker-compose up"
echo ""
-echo "(for complex demo)"
+echo "(for Grouper integration demo)"
echo ""
-echo "$ cd" $(pwd)/demo/complex
+echo "$ cd" $(pwd)/demo/grouper
echo "$ docker-compose up --build"
diff --git a/demo/grouper/.env b/demo/grouper/.env
new file mode 100644
index 0000000..75949b1
--- /dev/null
+++ b/demo/grouper/.env
@@ -0,0 +1,14 @@
+AUTHENTICATION=internal
+ENV=demo
+REPO_DATABASE_TYPE=mariadb
+REPO_JDBC_URL=default
+REPO_HOST=midpoint_data
+REPO_PORT=default
+REPO_DATABASE=registry
+REPO_USER=registry_user
+REPO_MISSING_SCHEMA_ACTION=create
+REPO_UPGRADEABLE_SCHEMA_ACTION=stop
+MP_MEM_MAX=2048m
+MP_MEM_INIT=1024m
+SSO_HEADER=uid
+TIMEZONE=UTC
diff --git a/demo/grouper/README.md b/demo/grouper/README.md
new file mode 100644
index 0000000..9b7f0f6
--- /dev/null
+++ b/demo/grouper/README.md
@@ -0,0 +1,9 @@
+This is a demonstration of using midPoint dockerization for TIER environment in a broader context. It is a work in progress.
+
+# Building and execution
+```
+$ ../../build.sh
+$ docker-compose up --build
+```
+
+Please see a detailed description [here](https://spaces.at.internet2.edu/display/MID/Complex+midPoint+integration+demo).
diff --git a/demo/grouper/add-ref-groups.gsh b/demo/grouper/add-ref-groups.gsh
new file mode 100644
index 0000000..7697f99
--- /dev/null
+++ b/demo/grouper/add-ref-groups.gsh
@@ -0,0 +1,26 @@
+
+def addGroups(gs,stem,owner,regexp) {
+ for (group in stem.childGroups) {
+ if (!group.name.endsWith('_includes') &&
+ !group.name.endsWith('_excludes') &&
+ !group.name.endsWith('_systemOfRecord') &&
+ !group.name.endsWith('_systemOfRecordAndIncludes') &&
+ (regexp == null || group.extension ==~ regexp)) {
+ println 'Adding: ' + group
+ def s = SubjectFinder.findById(group.getId(), 'group', 'g:gsa')
+ owner.addMember(s, false)
+ } else {
+ println 'Ignoring: ' + group
+ }
+ }
+}
+
+gs = GrouperSession.startRootSession()
+def supergroup = GroupFinder.findByName(gs, "etc:midpointGroups", true)
+def cs = GroupFinder.findByName(gs, "app:cs", true)
+
+addGroups(gs, StemFinder.findByName(gs, 'ref:affiliation'), supergroup, null)
+addGroups(gs, StemFinder.findByName(gs, 'ref:dept'), supergroup, null)
+addGroups(gs, StemFinder.findByName(gs, 'ref:course'), supergroup, null)
+
+addGroups(gs, StemFinder.findByName(gs, 'ref:course'), cs, /CS.*/)
diff --git a/demo/grouper/add-ref-groups.sh b/demo/grouper/add-ref-groups.sh
new file mode 100755
index 0000000..bfb93cf
--- /dev/null
+++ b/demo/grouper/add-ref-groups.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+source ../../library.bash
+
+execute_gsh grouper_grouper_daemon_1 add-ref-groups.gsh
diff --git a/demo/grouper/after-installation.sh b/demo/grouper/after-installation.sh
new file mode 100755
index 0000000..aefe3b1
--- /dev/null
+++ b/demo/grouper/after-installation.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+B='\033[1;33m'
+N='\033[0m'
+
+echo -e "${B} * Uploading objects...${N}"
+$(dirname "$0")/upload-objects.sh
+
+echo -e "${B} * Testing resources...${N}"
+$(dirname "$0")/test-resources.sh
+
+echo -e "${B} * Recomputing Grouper admin group and user object...${N}"
+$(dirname "$0")/recompute.sh
+
+echo -e "${B} * Done${N}"
diff --git a/demo/grouper/configs-and-secrets/grouper/application/database_password.txt b/demo/grouper/configs-and-secrets/grouper/application/database_password.txt
new file mode 100644
index 0000000..e69de29
diff --git a/demo/grouper/configs-and-secrets/grouper/application/grouper-loader.properties b/demo/grouper/configs-and-secrets/grouper/application/grouper-loader.properties
new file mode 100644
index 0000000..62ef5f0
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/application/grouper-loader.properties
@@ -0,0 +1,71 @@
+#################################
+## LDAP connections
+#################################
+# specify the ldap connection with user, pass, url
+# the string after "ldap." is the ID of the connection, and it should not have
+# spaces or other special chars in it. In this case is it "personLdap"
+
+#note the URL should start with ldap: or ldaps: if it is SSL.
+#It should contain the server and port (optional if not default), and baseDn,
+#e.g. ldaps://ldapserver.school.edu:636/dc=school,dc=edu
+ldap.demo.url = ldap://directory:389/dc=internet2,dc=edu
+
+#optional, if authenticated
+ldap.demo.user = cn=admin,dc=internet2,dc=edu
+#ldap.demo.user = cn=admin
+
+#optional, if authenticated note the password can be stored encrypted in an external file
+#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')}
+ldap.demo.pass = password
+
+#optional, if you are using tls, set this to true. Generally you will not be using an SSL URL to use TLS...
+ldap.demo.tls = false
+
+#optional, if using sasl
+#ldap.personLdap.saslAuthorizationId =
+#ldap.personLdap.saslRealm =
+
+#optional (note, time limit is for search operations, timeout is for connection timeouts),
+#most of these default to vt-ldap defaults. times are in millis
+#validateOnCheckout defaults to true if all other validate methods are false
+#ldap.personLdap.batchSize =
+#ldap.personLdap.countLimit =
+#ldap.personLdap.timeLimit =
+#ldap.personLdap.timeout =
+#ldap.personLdap.minPoolSize =
+#ldap.personLdap.maxPoolSize =
+#ldap.personLdap.validateOnCheckIn =
+#ldap.personLdap.validateOnCheckOut =
+#ldap.personLdap.validatePeriodically =
+#ldap.personLdap.validateTimerPeriod =
+#ldap.personLdap.pruneTimerPeriod =
+#if connections expire after a certain amount of time, this is it, in millis, defaults to 300000 (5 minutes)
+#ldap.personLdap.expirationTime =
+
+#make the paths fully qualified and not relative to the loader group.
+loader.ldap.requireTopStemAsStemFromConfigGroup=false
+
+
+db.sis.user = sis_user
+db.sis.pass = 49321420423
+db.sis.url = jdbc:mysql://sources:3306/sis
+db.sis.driver = com.mysql.jdbc.Driver
+
+
+#####################################
+## Messaging integration with change log
+#####################################
+changeLog.consumer.rabbitMqMessagingSample.quartzCron = 0 * * * * ?
+
+# note, change "messagingSample" in key to be the name of the consumer. e.g. changeLog.consumer.someNameAnyName.class
+changeLog.consumer.rabbitMqMessagingSample.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer
+
+changeLog.consumer.rabbitMqMessagingSample.publisher.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbMessagingPublisher
+changeLog.consumer.rabbitMqMessagingSample.publisher.messagingSystemName = rabbitmq
+# note, routingKey property is valid only for rabbitmq. For other messaging systems, it is ignored.
+changeLog.consumer.rabbitMqMessagingSample.publisher.routingKey =
+## queue or topic
+changeLog.consumer.rabbitMqMessagingSample.publisher.messageQueueType = queue
+changeLog.consumer.rabbitMqMessagingSample.publisher.queueOrTopicName = sampleQueue
+## this is optional if not using "id" for subjectId, need to be a subject attribute in the sources.xml
+#changeLog.consumer.rabbitMqMessagingSample.publisher.addSubjectAttributes = email
diff --git a/demo/grouper/configs-and-secrets/grouper/application/grouper.client.properties b/demo/grouper/configs-and-secrets/grouper/application/grouper.client.properties
new file mode 100644
index 0000000..d25ad96
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/application/grouper.client.properties
@@ -0,0 +1,112 @@
+#
+# 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 client configuration
+# $Id: grouper.client.example.properties,v 1.24 2009-12-30 04:23:02 mchyzer Exp $
+#
+
+# The grouper client uses Grouper Configuration Overlays (documented on wiki)
+# By default the configuration is read from grouper.client.base.properties
+# (which should not be edited), and the grouper.client.properties overlays
+# the base settings. See the grouper.client.base.properties for the possible
+# settings that can be applied to the grouper.client.properties
+
+########################################
+## LDAP connection settings
+########################################
+
+# url of directory, including the base DN (distinguished name)
+# e.g. ldap://server.school.edu/dc=school,dc=edu
+# e.g. ldaps://server.school.edu/dc=school,dc=edu
+grouperClient.ldap.url =
+
+# kerberos principal used to connect to ldap
+grouperClient.ldap.login =
+
+# password for shared secret authentication to ldap
+# or you can put a filename with an encrypted password
+grouperClient.ldap.password =
+
+########################################
+## Web service Connection settings
+########################################
+
+# url of web service, should include everything up to the first resource to access
+# e.g. http://groups.school.edu:8090/grouper-ws/servicesRest
+# e.g. https://groups.school.edu/grouper-ws/servicesRest
+grouperClient.webService.url = https://grouper_ws/grouper-ws/servicesRest
+
+# kerberos principal used to connect to web service
+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.elConfig = ${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') }
+
+
+################################
+## Grouper Messaging System
+################################
+
+# name of messaging system which is the default
+grouper.messaging.default.name.of.messaging.system = rabbitmq
+
+# name of a messaging system. note, "grouperBuiltinMessaging" can be arbitrary
+# grouper.messaging.system.grouperBuiltinMessaging.name = grouperBuiltinMessaging
+
+# class that implements edu.internet2.middleware.grouperClient.messaging.GrouperMessagingSystem
+# grouper.messaging.system.grouperBuiltinMessaging.class = edu.internet2.middleware.grouper.messaging.GrouperBuiltinMessagingSystem
+
+# name of a messaging system. note, "grouperBuiltinMessaging" can be arbitrary
+grouper.messaging.system.rabbitmqSystem.name = rabbitmqSystem
+
+# class that implements edu.internet2.middleware.grouperClient.messaging.GrouperMessagingSystem
+grouper.messaging.system.rabbitmqSystem.class = edu.internet2.middleware.grouperMessagingRabbitmq.GrouperMessagingRabbitmqSystem
+
+# host address of rabbitmq queue
+grouper.messaging.system.rabbitmqSystem.host = mq
+
+# virtual host of rabbitmq queue
+grouper.messaging.system.rabbitmqSystem.virtualhost =
+
+# port of rabbitmq queue
+grouper.messaging.system.rabbitmqSystem.port =
+
+grouper.messaging.system.rabbitmqSystem.defaultPageSize = 10
+
+grouper.messaging.system.rabbitmqSystem.maxPageSize = 50
+
+
+# name of a messaging system, required
+grouper.messaging.system.rabbitmq.name = rabbitmq
+
+# default system settings to this messaging system, note, there is only one level of inheritance
+grouper.messaging.system.rabbitmq.defaultSystemName = rabbitmqSystem
+
+grouper.messaging.system.rabbitmq.user = guest
+
+#pass
+grouper.messaging.system.rabbitmq.password.elConfig = ${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
+
+# path to trust store file
+#grouper.messaging.system.rabbitmqSystem.pathToTrustStore =
+
+# trust passphrase
+#grouper.messaging.system.rabbitmqSystem.trustPassphrase =
diff --git a/demo/grouper/configs-and-secrets/grouper/application/grouper.hibernate.properties b/demo/grouper/configs-and-secrets/grouper/application/grouper.hibernate.properties
new file mode 100644
index 0000000..deb0d75
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/application/grouper.hibernate.properties
@@ -0,0 +1,29 @@
+#
+# Grouper Hibernate Configuration
+# $Id: grouper.hibernate.example.properties,v 1.9 2009-08-11 20:18:09 mchyzer Exp $
+#
+
+# The grouper hibernate config uses Grouper Configuration Overlays (documented on wiki)
+# By default the configuration is read from grouper.hibernate.base.properties
+# (which should not be edited), and the grouper.hibernate.properties overlays
+# the base settings. See the grouper.hibernate.base.properties for the possible
+# settings that can be applied to the grouper.hibernate.properties
+
+########################################
+## DB settings
+########################################
+
+# e.g. mysql: jdbc:mysql://localhost:3306/grouper
+# e.g. p6spy (log sql): [use the URL that your DB requires]
+# e.g. oracle: jdbc:oracle:thin:@server.school.edu:1521:sid
+# e.g. hsqldb (a): jdbc:hsqldb:dist/run/grouper;create=true
+# e.g. hsqldb (b): jdbc:hsqldb:hsql://localhost:9001/grouper
+# e.g. postgres: jdbc:postgresql://localhost:5432/database
+# e.g. mssql: jdbc:sqlserver://localhost:3280;databaseName=grouper
+hibernate.connection.url = jdbc:mysql://grouper_data:3306/grouper?CharSet=utf8&useUnicode=true&characterEncoding=utf8
+
+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.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/demo/grouper/configs-and-secrets/grouper/application/grouper.properties b/demo/grouper/configs-and-secrets/grouper/application/grouper.properties
new file mode 100644
index 0000000..c931287
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/application/grouper.properties
@@ -0,0 +1,25 @@
+#
+# Grouper Configuration
+# $Id: grouper.example.properties,v 1.48 2009-12-16 06:02:30 mchyzer Exp $
+#
+
+# Grouper uses Grouper Configuration Overlays (documented on wiki)
+# By default the configuration is read from grouper.base.properties
+# (which should not be edited), and the grouper.properties overlays
+# the base settings. See the grouper.base.properties for the possible
+# settings that can be applied to the grouper.properties
+
+#if groups like the wheel group should be auto-created for convenience (note: check config needs to be on)
+configuration.autocreate.system.groups = true
+
+# A wheel group allows you to enable non-GrouperSystem subjects to act
+# like a root user when interacting with the registry.
+groups.wheel.use = true
+
+# Set to the name of the group you want to treat as the wheel group.
+# The members of this group will be treated as root-like users.
+groups.wheel.group = etc:sysadmingroup
+
+# Used to allow Include Exclude groups
+grouperIncludeExclude.use = true
+grouperIncludeExclude.requireGroups.use = true
diff --git a/demo/grouper/configs-and-secrets/grouper/application/rabbitmq_password.txt b/demo/grouper/configs-and-secrets/grouper/application/rabbitmq_password.txt
new file mode 100644
index 0000000..158f675
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/application/rabbitmq_password.txt
@@ -0,0 +1 @@
+guest
\ No newline at end of file
diff --git a/demo/grouper/configs-and-secrets/grouper/application/subject.properties b/demo/grouper/configs-and-secrets/grouper/application/subject.properties
new file mode 100644
index 0000000..577db03
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/application/subject.properties
@@ -0,0 +1,78 @@
+#subject.sources.xml.location =
+
+subjectApi.source.ldap.param.ldapServerId.value = demo
+
+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://directory: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.VTLDAP_VALIDATOR.value = ConnectLdapValidator
+
+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.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
+
+#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
+
+# 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
+
+subjectApi.source.ldap.attributes = givenName, sn, uid, mail, employeeNumber
+subjectApi.source.ldap.internalAttributes = searchAttribute0
diff --git a/demo/grouper/configs-and-secrets/grouper/httpd/cachain-cer.pem b/demo/grouper/configs-and-secrets/grouper/httpd/cachain-cer.pem
new file mode 100644
index 0000000..e69de29
diff --git a/demo/grouper/configs-and-secrets/grouper/httpd/host-cert.pem b/demo/grouper/configs-and-secrets/grouper/httpd/host-cert.pem
new file mode 100644
index 0000000..9cc228a
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/httpd/host-cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPDCCAiQCCQDNZe8r0hVtuTANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJV
+UzELMAkGA1UECAwCTUkxEjAQBgNVBAcMCUFubiBBcmJvcjEXMBUGA1UECgwOSW50
+ZXJuZXQyL1RJRVIxFzAVBgNVBAMMDnNwLmV4YW1wbGUub3JnMB4XDTE3MDkyMjE5
+NTAzNVoXDTI3MDkyMDE5NTAzNVowYDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1J
+MRIwEAYDVQQHDAlBbm4gQXJib3IxFzAVBgNVBAoMDkludGVybmV0Mi9USUVSMRcw
+FQYDVQQDDA5zcC5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAMTNJmsNpTpR4NrDJwOgK/o3UYlNdi1c6xBflt+liLAsQc160QReV4dS
+SGK8LZvN58a/BTIsH8dLhQlUQ8qQUY2AfolVrNxb7Waumeh/POzYUTRylnoGpU3W
+bGMEPxE/AdgP5U/adYvyu4XI5epv7wjZJOTqcVag15SalY+aso+ZC/5l+UzRxmWB
+ZxKTsSL1y7PFehY4/Zl3Y3oGVsVl/zspt5lteoZQeeVxUX29S3Af11yHY4xpEp+7
+rvAzY/nlsTiHAsUoCFK/NFQ2evvSRx52B9Fk1cWP1MDVDm2QjQqD9xBGYSnX6bhQ
+ejVx7JUJHlblu2Q5p5XdW0BihgFluoECAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+n/qhYnIviPs4tglCdrw+M7gbqKNWadDC3F9HDYzlJMFeS/ae2turhEUgQPbYPDQQ
+eO3oOILtvCXNFUPM58jf8V5YFRrOqrTgx44kexQDaHO5YYNft5tF5TdvBYE2gOVr
+GdYrH2iSP8WX+Yy7JH5uqkfwWzEntWHJdey39rCWKAUCCB35+/2b4N53Qmlv2+ug
+CpNJYFtXInd4YMmM5HjXLyoWXtjnKiwDqYUCeYPSwAajnCqRqRXUX0gYTFDRiwRP
+HbmO9We0nqoc/71nikmGGoSRMO/zWVMFjwmAx1fGiWdU61sjGX8sHifzmVyJVEBI
+Z75p+JrWYZJYrx/vpWxL8g==
+-----END CERTIFICATE-----
diff --git a/demo/grouper/configs-and-secrets/grouper/httpd/host-key.pem b/demo/grouper/configs-and-secrets/grouper/httpd/host-key.pem
new file mode 100644
index 0000000..1b0b579
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/httpd/host-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEzSZrDaU6UeDa
+wycDoCv6N1GJTXYtXOsQX5bfpYiwLEHNetEEXleHUkhivC2bzefGvwUyLB/HS4UJ
+VEPKkFGNgH6JVazcW+1mrpnofzzs2FE0cpZ6BqVN1mxjBD8RPwHYD+VP2nWL8ruF
+yOXqb+8I2STk6nFWoNeUmpWPmrKPmQv+ZflM0cZlgWcSk7Ei9cuzxXoWOP2Zd2N6
+BlbFZf87KbeZbXqGUHnlcVF9vUtwH9dch2OMaRKfu67wM2P55bE4hwLFKAhSvzRU
+Nnr70kcedgfRZNXFj9TA1Q5tkI0Kg/cQRmEp1+m4UHo1ceyVCR5W5btkOaeV3VtA
+YoYBZbqBAgMBAAECggEAA/5t0ypZug9DUu0283niqpdIzlKGHXGPS6vE8hD37ytW
+wobFiyMm/5YJ5gcPnePV2lCyGEyQ8Ih10LSnE4tOPGLpLnxQn8A11ymf8fnzEJNr
+Qnc42o0b+bJqTLAfX4g5z1qzOqWiUQ7CA3sKP3G6FiHh/8tKNYnaFif09Q8cpJFb
+YDDkvm48NJgsrIoCgmaFIQIn+yDzGQKWwTNMIks+RByWpc67j1x1kiyQM1RfrEev
+Yyq/ZkP66IYZzmZKpFCWGs5qbRZdxyXNpq85DjwA99lAH7vxtMJHQM4z1h1eDH4L
+Ma5hEnmmHu4D5lF2GDQYflvuFdDGH5tThO6MV0IrSQKBgQD+kvEtNxJCMxLOVFyV
+NWF3pk/i2nkD+53t/VPXjMPtW7IesouEGzU82I/fT2wUTkNwFdkVpv37qoLypKZm
+npJFxr6abQNjiDh2Fsh8/iuJfvdZUFJbCEY6NS58qgjix8XCQKRD06EugK7uekIZ
+zJnttF3qVBBD8Z8Uwxz8i+jF1wKBgQDF51y/5XB6Bz47cdxw7P8NsfnTz2V3H0HU
+OnlEBANbhmBadjU8dqbM54Nxbn7VOdooXPuSnAKJ9vPDg1n5Y/GO+lgldNzfyK6g
+HnbldSu0zBvAaGvmAjLjetEtOkBqYkrHJlT6JAems/Kc/YX5uooAz9/jNJFXP9++
+KbjH3CzHZwKBgQC6ppxEDZPKi83nD/2NvMTIyFzcNFj0LaEepFW7vc7NkiSn0zrt
+0lEXWqUqEv5oaPWTEcHH2VdxFRTLuSL0LKGMnWqUqQcKDA9xrcSzuFvNhRTwHC81
+5XwwI1wBNV4sgFKj2WdW/6y2/szDt0oNxnC50zvkmlwOpPKBc4kmNaKmowKBgBmC
+uXIDIXyZcmw3QTNNWZNqXcnv8iRo4xN4dilOWyBxMfp3QmWI5feD4G2+0Jqr2nNZ
+iRRdB/bA3qtVQ0PinkDQBIzPg6lVNS1uv+TUNc4YgXtL+pyrq+Om8U/jMmqEQR9q
+0YltG49houSZyatnYGK6aSHgpNuaYD0jI66fsyYBAoGAMefyD0I/ncArjuf58hVQ
+zSjxfcvlja9okrC8ZgqsVluezcm4rQNcSjBnESGTCjJC7O29AofGLHkvnsBQDiGk
+hE38IRisd+okXdApr41ifWDhmtASud5q6wlhOpMmQxg+OALf1rTvFYhbnFEXV/KY
+e5A4iXLRIbxbmXZDa35Rebw=
+-----END PRIVATE KEY-----
diff --git a/demo/grouper/configs-and-secrets/grouper/shibboleth/idp-metadata.xml b/demo/grouper/configs-and-secrets/grouper/shibboleth/idp-metadata.xml
new file mode 100644
index 0000000..4fa67a7
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/shibboleth/idp-metadata.xml
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+ example.org
+
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUS9SuTXwsFVVG+LjOEAbLqqT/el0wDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMjZaFw0zNTEy
+MTEwMjIwMjZaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCMAoDHx8xCIfv/6QKqt9mcHYmEJ8y2dKprUbpdcOjH
+YvNPIl/lHPsUyrb+Nc+q2CDeiWjVk1mWYq0UpIwpBMuw1H6+oOqr4VQRi65pin0M
+SfE0MWIaFo5FPvpvoptkHD4gvREbm4swyXGMczcMRfqgalFXhUD2wz8W3XAM5Cq2
+03XeJbj6TwjvKatG5XPdeUe2FBGuOO2q54L1hcIGnLMCQrg7D31lR13PJbjnJ0No
+5C3k8TPuny6vJsBC03GNLNKfmrKVTdzr3VKp1uay1G3DL9314fgmbl8HA5iRQmy+
+XInUU6/8NXZSF59p3ITAOvZQeZsbJjg5gGDip5OZo9YlAgMBAAGjWzBZMB0GA1Ud
+DgQWBBRPlM4VkKZ0U4ec9GrIhFQl0hNbLDA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAIZ0a1ov3my3ljJG588I/PHx+TxAWONWmpKbO9c/qI3Drxk4oRIffiac
+ANxdvtabgIzrlk5gMMisD7oyqHJiWgKv5Bgctd8w3IS3lLl7wHX65mTKQRXniG98
+NIjkvfrhe2eeJxecOqnDI8GOhIGCIqZUn8ShdM/yHjhQ2Mh0Hj3U0LlKvnmfGSQl
+j0viGwbFCaNaIP3zc5UmCrdE5h8sWL3Fu7ILKM9RyFa2ILHrJScV9t623IcHffHP
+IeaY/WtuapsrqRFxuQL9QFWN0FsRIdLmjTq+00+B/XnnKRKFBuWfjhHLF/uu8f+E
+t6Lf23Kb8yD6ZR7dihMZAGHnYQ/hlhM=
+
+
+
+
+
+
+
+
+
+MIIDFDCCAfygAwIBAgIVAN3vv+b7KN5Se9m1RZsCllp/B/hdMA0GCSqGSIb3DQEB
+CwUAMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwHhcNMTUxMjExMDIyMDE0WhcNMzUx
+MjExMDIyMDE0WjAVMRMwEQYDVQQDDAppZHB0ZXN0YmVkMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAh91caeY0Q85uhaUyqFwP2bMjwMFxMzRlAoqBHd7g
+u6eo4duaeLz1BaoR2XTBpNNvFR5oHH+TkKahVDGeH5+kcnIpxI8JPdsZml1srvf2
+Z6dzJsulJZUdpqnngycTkGtZgEoC1vmYVky2BSAIIifmdh6s0epbHnMGLsHzMKfJ
+Cb/Q6dYzRWTCPtzE2VMuQqqWgeyMr7u14x/Vqr9RPEFsgY8GIu5jzB6AyUIwrLg+
+MNkv6aIdcHwxYTGL7ijfy6rSWrgBflQoYRYNEnseK0ZHgJahz4ovCag6wZAoPpBs
+uYlY7lEr89Ucb6NHx3uqGMsXlDFdE4QwfDLLhCYHPvJ0uwIDAQABo1swWTAdBgNV
+HQ4EFgQUAkOgED3iYdmvQEOMm6u/JmD/UTQwOAYDVR0RBDEwL4IKaWRwdGVzdGJl
+ZIYhaHR0cHM6Ly9pZHB0ZXN0YmVkL2lkcC9zaGliYm9sZXRoMA0GCSqGSIb3DQEB
+CwUAA4IBAQBIdd4YWlnvJjql8+zKKgmWgIY7U8DA8e6QcbAf8f8cdE33RSnjI63X
+sv/y9GfmbAVAD6RIAXPFFeRYJ08GOxGI9axfNaKdlsklJ9bk4ducHqgCSWYVer3s
+RQBjxyOfSTvk9YCJvdJVQRJLcCvxwKakFCsOSnV3t9OvN86Ak+fKPVB5j2fM/0fZ
+Kqjn3iqgdNPTLXPsuJLJO5lITRiBa4onmVelAiCstI9PQiaEck+oAHnMTnC9JE/B
+DHv3e4rwq3LznlqPw0GSd7xqNTdMDwNOWjkuOr3sGpWS8ms/ZHHXV1Vd22uPe70i
+s00xrv14zLifcc8oj5DYzOhYRifRXgHX
+
+
+
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUG6Nn1rlERS1vsi88tcdzSYX0oqAwDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMTRaFw0zNTEy
+MTEwMjIwMTRaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCBXv0o3fmT8iluyLjJ4lBAVCW+ZRVyEXPYQuRi7vfD
+cO4a6d1kxiJLsaK0W88VNxjFQRr8PgDkWr28vwoH1rgk4pLsszLD48DBzD942peJ
+l/S6FnsIJjmaHcBh4pbNhU4yowu63iKkvttrcZAEbpEro6Z8CziWEx8sywoaYEQG
+ifPkr9ORV6Cn3txq+9gMBePG41GrtZrUGIu+xrndL0Shh4Pq0eq/9MAsVlIIXEa8
+9WfH8J2kFcTOfoWtIc70b7TLZQsx4YnNcnrGLSUEcstFyPLX+Xtv5SNZF89OOIxX
+VNjNvgE5DbJb9hMM4UAFqI+1bo9QqtxwThjc/sOvIxzNAgMBAAGjWzBZMB0GA1Ud
+DgQWBBStTyogRPuAVG6q7yPyav1uvE+7pTA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAFMfoOv+oISGjvamq7+Y4G7ep5vxlAPeK3RATYPYvAmyH946qZXh98ni
+QXyuqZW5P5eEt86toY45IwDU5r09SKwHughEe99iiEkxh0mb2qo84qX9/qcg+kyN
+jeLd/OSyolpUCEFNwOFcog7pj7Eer+6AHbwTn1Mjb5TBsKwtDMJsaxPvdj0u7M5r
+xL/wHkFhn1rCo2QiojzjSlV3yLTh49iTyhE3cG+RxaNKDCxhp0jSSLX1BW/ZoPA8
++PMJEA+Q0QbyRD8aJOHN5O8jGxCa/ZzcOnYVL6AsEXoDiY3vAUYh1FUonOWw0m9H
+p+tGUbGS2l873J5PrsbpeKEVR/IIoKo=
+
+
+
+
+
+
+ urn:mace:shibboleth:1.0:nameIdentifier
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+
+
+
+
+
+
+
+
+ localhost
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUS9SuTXwsFVVG+LjOEAbLqqT/el0wDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMjZaFw0zNTEy
+MTEwMjIwMjZaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCMAoDHx8xCIfv/6QKqt9mcHYmEJ8y2dKprUbpdcOjH
+YvNPIl/lHPsUyrb+Nc+q2CDeiWjVk1mWYq0UpIwpBMuw1H6+oOqr4VQRi65pin0M
+SfE0MWIaFo5FPvpvoptkHD4gvREbm4swyXGMczcMRfqgalFXhUD2wz8W3XAM5Cq2
+03XeJbj6TwjvKatG5XPdeUe2FBGuOO2q54L1hcIGnLMCQrg7D31lR13PJbjnJ0No
+5C3k8TPuny6vJsBC03GNLNKfmrKVTdzr3VKp1uay1G3DL9314fgmbl8HA5iRQmy+
+XInUU6/8NXZSF59p3ITAOvZQeZsbJjg5gGDip5OZo9YlAgMBAAGjWzBZMB0GA1Ud
+DgQWBBRPlM4VkKZ0U4ec9GrIhFQl0hNbLDA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAIZ0a1ov3my3ljJG588I/PHx+TxAWONWmpKbO9c/qI3Drxk4oRIffiac
+ANxdvtabgIzrlk5gMMisD7oyqHJiWgKv5Bgctd8w3IS3lLl7wHX65mTKQRXniG98
+NIjkvfrhe2eeJxecOqnDI8GOhIGCIqZUn8ShdM/yHjhQ2Mh0Hj3U0LlKvnmfGSQl
+j0viGwbFCaNaIP3zc5UmCrdE5h8sWL3Fu7ILKM9RyFa2ILHrJScV9t623IcHffHP
+IeaY/WtuapsrqRFxuQL9QFWN0FsRIdLmjTq+00+B/XnnKRKFBuWfjhHLF/uu8f+E
+t6Lf23Kb8yD6ZR7dihMZAGHnYQ/hlhM=
+
+
+
+
+
+
+
+
+
+MIIDFDCCAfygAwIBAgIVAN3vv+b7KN5Se9m1RZsCllp/B/hdMA0GCSqGSIb3DQEB
+CwUAMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwHhcNMTUxMjExMDIyMDE0WhcNMzUx
+MjExMDIyMDE0WjAVMRMwEQYDVQQDDAppZHB0ZXN0YmVkMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAh91caeY0Q85uhaUyqFwP2bMjwMFxMzRlAoqBHd7g
+u6eo4duaeLz1BaoR2XTBpNNvFR5oHH+TkKahVDGeH5+kcnIpxI8JPdsZml1srvf2
+Z6dzJsulJZUdpqnngycTkGtZgEoC1vmYVky2BSAIIifmdh6s0epbHnMGLsHzMKfJ
+Cb/Q6dYzRWTCPtzE2VMuQqqWgeyMr7u14x/Vqr9RPEFsgY8GIu5jzB6AyUIwrLg+
+MNkv6aIdcHwxYTGL7ijfy6rSWrgBflQoYRYNEnseK0ZHgJahz4ovCag6wZAoPpBs
+uYlY7lEr89Ucb6NHx3uqGMsXlDFdE4QwfDLLhCYHPvJ0uwIDAQABo1swWTAdBgNV
+HQ4EFgQUAkOgED3iYdmvQEOMm6u/JmD/UTQwOAYDVR0RBDEwL4IKaWRwdGVzdGJl
+ZIYhaHR0cHM6Ly9pZHB0ZXN0YmVkL2lkcC9zaGliYm9sZXRoMA0GCSqGSIb3DQEB
+CwUAA4IBAQBIdd4YWlnvJjql8+zKKgmWgIY7U8DA8e6QcbAf8f8cdE33RSnjI63X
+sv/y9GfmbAVAD6RIAXPFFeRYJ08GOxGI9axfNaKdlsklJ9bk4ducHqgCSWYVer3s
+RQBjxyOfSTvk9YCJvdJVQRJLcCvxwKakFCsOSnV3t9OvN86Ak+fKPVB5j2fM/0fZ
+Kqjn3iqgdNPTLXPsuJLJO5lITRiBa4onmVelAiCstI9PQiaEck+oAHnMTnC9JE/B
+DHv3e4rwq3LznlqPw0GSd7xqNTdMDwNOWjkuOr3sGpWS8ms/ZHHXV1Vd22uPe70i
+s00xrv14zLifcc8oj5DYzOhYRifRXgHX
+
+
+
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUG6Nn1rlERS1vsi88tcdzSYX0oqAwDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMTRaFw0zNTEy
+MTEwMjIwMTRaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCBXv0o3fmT8iluyLjJ4lBAVCW+ZRVyEXPYQuRi7vfD
+cO4a6d1kxiJLsaK0W88VNxjFQRr8PgDkWr28vwoH1rgk4pLsszLD48DBzD942peJ
+l/S6FnsIJjmaHcBh4pbNhU4yowu63iKkvttrcZAEbpEro6Z8CziWEx8sywoaYEQG
+ifPkr9ORV6Cn3txq+9gMBePG41GrtZrUGIu+xrndL0Shh4Pq0eq/9MAsVlIIXEa8
+9WfH8J2kFcTOfoWtIc70b7TLZQsx4YnNcnrGLSUEcstFyPLX+Xtv5SNZF89OOIxX
+VNjNvgE5DbJb9hMM4UAFqI+1bo9QqtxwThjc/sOvIxzNAgMBAAGjWzBZMB0GA1Ud
+DgQWBBStTyogRPuAVG6q7yPyav1uvE+7pTA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAFMfoOv+oISGjvamq7+Y4G7ep5vxlAPeK3RATYPYvAmyH946qZXh98ni
+QXyuqZW5P5eEt86toY45IwDU5r09SKwHughEe99iiEkxh0mb2qo84qX9/qcg+kyN
+jeLd/OSyolpUCEFNwOFcog7pj7Eer+6AHbwTn1Mjb5TBsKwtDMJsaxPvdj0u7M5r
+xL/wHkFhn1rCo2QiojzjSlV3yLTh49iTyhE3cG+RxaNKDCxhp0jSSLX1BW/ZoPA8
++PMJEA+Q0QbyRD8aJOHN5O8jGxCa/ZzcOnYVL6AsEXoDiY3vAUYh1FUonOWw0m9H
+p+tGUbGS2l873J5PrsbpeKEVR/IIoKo=
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/configs-and-secrets/grouper/shibboleth/shibboleth2.xml b/demo/grouper/configs-and-secrets/grouper/shibboleth/shibboleth2.xml
new file mode 100644
index 0000000..0c38f82
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/shibboleth/shibboleth2.xml
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SAML2
+
+
+
+ SAML2 Local
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/configs-and-secrets/grouper/shibboleth/sp-cert.pem b/demo/grouper/configs-and-secrets/grouper/shibboleth/sp-cert.pem
new file mode 100644
index 0000000..9cc228a
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/shibboleth/sp-cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPDCCAiQCCQDNZe8r0hVtuTANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJV
+UzELMAkGA1UECAwCTUkxEjAQBgNVBAcMCUFubiBBcmJvcjEXMBUGA1UECgwOSW50
+ZXJuZXQyL1RJRVIxFzAVBgNVBAMMDnNwLmV4YW1wbGUub3JnMB4XDTE3MDkyMjE5
+NTAzNVoXDTI3MDkyMDE5NTAzNVowYDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1J
+MRIwEAYDVQQHDAlBbm4gQXJib3IxFzAVBgNVBAoMDkludGVybmV0Mi9USUVSMRcw
+FQYDVQQDDA5zcC5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAMTNJmsNpTpR4NrDJwOgK/o3UYlNdi1c6xBflt+liLAsQc160QReV4dS
+SGK8LZvN58a/BTIsH8dLhQlUQ8qQUY2AfolVrNxb7Waumeh/POzYUTRylnoGpU3W
+bGMEPxE/AdgP5U/adYvyu4XI5epv7wjZJOTqcVag15SalY+aso+ZC/5l+UzRxmWB
+ZxKTsSL1y7PFehY4/Zl3Y3oGVsVl/zspt5lteoZQeeVxUX29S3Af11yHY4xpEp+7
+rvAzY/nlsTiHAsUoCFK/NFQ2evvSRx52B9Fk1cWP1MDVDm2QjQqD9xBGYSnX6bhQ
+ejVx7JUJHlblu2Q5p5XdW0BihgFluoECAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+n/qhYnIviPs4tglCdrw+M7gbqKNWadDC3F9HDYzlJMFeS/ae2turhEUgQPbYPDQQ
+eO3oOILtvCXNFUPM58jf8V5YFRrOqrTgx44kexQDaHO5YYNft5tF5TdvBYE2gOVr
+GdYrH2iSP8WX+Yy7JH5uqkfwWzEntWHJdey39rCWKAUCCB35+/2b4N53Qmlv2+ug
+CpNJYFtXInd4YMmM5HjXLyoWXtjnKiwDqYUCeYPSwAajnCqRqRXUX0gYTFDRiwRP
+HbmO9We0nqoc/71nikmGGoSRMO/zWVMFjwmAx1fGiWdU61sjGX8sHifzmVyJVEBI
+Z75p+JrWYZJYrx/vpWxL8g==
+-----END CERTIFICATE-----
diff --git a/demo/grouper/configs-and-secrets/grouper/shibboleth/sp-key.pem b/demo/grouper/configs-and-secrets/grouper/shibboleth/sp-key.pem
new file mode 100644
index 0000000..1b0b579
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/grouper/shibboleth/sp-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEzSZrDaU6UeDa
+wycDoCv6N1GJTXYtXOsQX5bfpYiwLEHNetEEXleHUkhivC2bzefGvwUyLB/HS4UJ
+VEPKkFGNgH6JVazcW+1mrpnofzzs2FE0cpZ6BqVN1mxjBD8RPwHYD+VP2nWL8ruF
+yOXqb+8I2STk6nFWoNeUmpWPmrKPmQv+ZflM0cZlgWcSk7Ei9cuzxXoWOP2Zd2N6
+BlbFZf87KbeZbXqGUHnlcVF9vUtwH9dch2OMaRKfu67wM2P55bE4hwLFKAhSvzRU
+Nnr70kcedgfRZNXFj9TA1Q5tkI0Kg/cQRmEp1+m4UHo1ceyVCR5W5btkOaeV3VtA
+YoYBZbqBAgMBAAECggEAA/5t0ypZug9DUu0283niqpdIzlKGHXGPS6vE8hD37ytW
+wobFiyMm/5YJ5gcPnePV2lCyGEyQ8Ih10LSnE4tOPGLpLnxQn8A11ymf8fnzEJNr
+Qnc42o0b+bJqTLAfX4g5z1qzOqWiUQ7CA3sKP3G6FiHh/8tKNYnaFif09Q8cpJFb
+YDDkvm48NJgsrIoCgmaFIQIn+yDzGQKWwTNMIks+RByWpc67j1x1kiyQM1RfrEev
+Yyq/ZkP66IYZzmZKpFCWGs5qbRZdxyXNpq85DjwA99lAH7vxtMJHQM4z1h1eDH4L
+Ma5hEnmmHu4D5lF2GDQYflvuFdDGH5tThO6MV0IrSQKBgQD+kvEtNxJCMxLOVFyV
+NWF3pk/i2nkD+53t/VPXjMPtW7IesouEGzU82I/fT2wUTkNwFdkVpv37qoLypKZm
+npJFxr6abQNjiDh2Fsh8/iuJfvdZUFJbCEY6NS58qgjix8XCQKRD06EugK7uekIZ
+zJnttF3qVBBD8Z8Uwxz8i+jF1wKBgQDF51y/5XB6Bz47cdxw7P8NsfnTz2V3H0HU
+OnlEBANbhmBadjU8dqbM54Nxbn7VOdooXPuSnAKJ9vPDg1n5Y/GO+lgldNzfyK6g
+HnbldSu0zBvAaGvmAjLjetEtOkBqYkrHJlT6JAems/Kc/YX5uooAz9/jNJFXP9++
+KbjH3CzHZwKBgQC6ppxEDZPKi83nD/2NvMTIyFzcNFj0LaEepFW7vc7NkiSn0zrt
+0lEXWqUqEv5oaPWTEcHH2VdxFRTLuSL0LKGMnWqUqQcKDA9xrcSzuFvNhRTwHC81
+5XwwI1wBNV4sgFKj2WdW/6y2/szDt0oNxnC50zvkmlwOpPKBc4kmNaKmowKBgBmC
+uXIDIXyZcmw3QTNNWZNqXcnv8iRo4xN4dilOWyBxMfp3QmWI5feD4G2+0Jqr2nNZ
+iRRdB/bA3qtVQ0PinkDQBIzPg6lVNS1uv+TUNc4YgXtL+pyrq+Om8U/jMmqEQR9q
+0YltG49houSZyatnYGK6aSHgpNuaYD0jI66fsyYBAoGAMefyD0I/ncArjuf58hVQ
+zSjxfcvlja9okrC8ZgqsVluezcm4rQNcSjBnESGTCjJC7O29AofGLHkvnsBQDiGk
+hE38IRisd+okXdApr41ifWDhmtASud5q6wlhOpMmQxg+OALf1rTvFYhbnFEXV/KY
+e5A4iXLRIbxbmXZDa35Rebw=
+-----END PRIVATE KEY-----
diff --git a/demo/grouper/configs-and-secrets/midpoint/application/database_password.txt b/demo/grouper/configs-and-secrets/midpoint/application/database_password.txt
new file mode 100644
index 0000000..11bff19
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/midpoint/application/database_password.txt
@@ -0,0 +1 @@
+WJzesbe3poNZ91qIbmR7
diff --git a/demo/grouper/configs-and-secrets/midpoint/application/keystore_password.txt b/demo/grouper/configs-and-secrets/midpoint/application/keystore_password.txt
new file mode 100644
index 0000000..1d40192
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/midpoint/application/keystore_password.txt
@@ -0,0 +1 @@
+changeit
diff --git a/demo/grouper/configs-and-secrets/midpoint/httpd/host-cert.pem b/demo/grouper/configs-and-secrets/midpoint/httpd/host-cert.pem
new file mode 100644
index 0000000..9b1021b
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/midpoint/httpd/host-cert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDqDCCApCgAwIBAgIJAMOSkn4oS2aAMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJNSTESMBAGA1UEBwwJQW5uIEFyYm9yMRcwFQYDVQQK
+DA5JbnRlcm5ldDIvVElFUjEgMB4GA1UEAwwXbWlkcG9pbnQuc3AuZXhhbXBsZS5v
+cmcwHhcNMTgwOTE0MDU1OTQ1WhcNMTkwOTE0MDU1OTQ1WjBpMQswCQYDVQQGEwJV
+UzELMAkGA1UECAwCTUkxEjAQBgNVBAcMCUFubiBBcmJvcjEXMBUGA1UECgwOSW50
+ZXJuZXQyL1RJRVIxIDAeBgNVBAMMF21pZHBvaW50LnNwLmV4YW1wbGUub3JnMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApj/b7MEUSfu3oXMfNgRwTse7
+a5UV7Jswf1M/ZN/ZZkAkIxNBevZgozjesvLPWrmsTgONi7XigJUJvCjdjmlW9eDM
+lri/rkD8HuOR1DQCVKL9nvoS2c3D7sq5Emda3V8Tlj82VqfEmePd3sajx7mcTfbH
+8jwAL9NhkC+WMib5IpjLGpG0FEAC0ha7Lxb+7jIiqHVJaqLXJGCyGN4mh6c1Q9S1
+f8RVTiW2a8x22G+9wnZYbkiA2Kxls177imHlhSz8EdvV4IpGw1amrEWhhuDEum7B
+vZ1xQDLatgRqh4qAKLIVYeRnJ8H1FelMa90qB4G08MIPifmTsQwqJyBYaEdgWQID
+AQABo1MwUTAdBgNVHQ4EFgQUqb9BteODF6wv5R57aEON/wGXMiowHwYDVR0jBBgw
+FoAUqb9BteODF6wv5R57aEON/wGXMiowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQsFAAOCAQEAAcKhxI+tSItrXmqC0PSmgWyAYpqbkz6W/cefTutXqhIgY09f
+h0LSv7ogTahoGpyiZk9vy6u3OE9bYwxapEfa4KBjO6HxBMIVBBb3RegVjoPzjElN
+BDwAx0VGFcZTXwMxDWycWdG8ql7rCZBvS50w04uTaIgnGmqXAdWWmBgfJ9cRbxW+
+JwO/mOl1QM1lR/5142NpvuUVWlmZSKEGydE5A1qPz2wpDbBR1ym1BQNS4NEqw6Kp
+GSB8jKyCS1Ve0v2wVze2038Wukz02dq9uKPTIO3T+B+ibZmxn6Op/kFCc1/kK5NS
+Q6JdO1B6KquGAYdGmKAcQ19mv+jqGktqWEEf0g==
+-----END CERTIFICATE-----
diff --git a/demo/grouper/configs-and-secrets/midpoint/httpd/host-key.pem b/demo/grouper/configs-and-secrets/midpoint/httpd/host-key.pem
new file mode 100644
index 0000000..5746e59
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/midpoint/httpd/host-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCmP9vswRRJ+7eh
+cx82BHBOx7trlRXsmzB/Uz9k39lmQCQjE0F69mCjON6y8s9auaxOA42LteKAlQm8
+KN2OaVb14MyWuL+uQPwe45HUNAJUov2e+hLZzcPuyrkSZ1rdXxOWPzZWp8SZ493e
+xqPHuZxN9sfyPAAv02GQL5YyJvkimMsakbQUQALSFrsvFv7uMiKodUlqotckYLIY
+3iaHpzVD1LV/xFVOJbZrzHbYb73CdlhuSIDYrGWzXvuKYeWFLPwR29XgikbDVqas
+RaGG4MS6bsG9nXFAMtq2BGqHioAoshVh5GcnwfUV6Uxr3SoHgbTwwg+J+ZOxDCon
+IFhoR2BZAgMBAAECggEAEIRBpjjceiku6jRUwnoYaks/nIWYQwR8AfpUTwJKR/VR
+Yca097Fokm7A+UhUP3A45RtHQb0VPq8P44iv0kk24YCu8r5yFK7SHYOAZnOwU5ZJ
+2jSAEPF3aM7tKh3okhuzB3dKP7u1NZDE5zAW723KUJiW7sL1RcsbY0bHBj6G+9/H
+NplmsjuGt684vRBB0qOBfKF7EiG7mT69tHuNj4gRza9SMY31UtKbZdt2fNY6mp5V
+HscMba7egZP+Ke0pVX4+go9j7K8GG8hYaQDLjrzlPqrxZ2c5X9cC+CRDI/CHuL/s
+V/2yGZJ6n6UabwZoH83RdFrbQ94rU8Hkli6EvxXvMQKBgQDRpheNW5jDG5TfeJKh
+yfKTDQqH2Tk3BsBYYBN7Hf3m7vbkzlxnAKJAoSLmtRMuoeXvI5MrhzaHGsNIUS76
+LDIZnvB7DLUxhFUZsCPkpAA1QHuTWY96oR3PHnPjpk8lSUvtbOPwDLdzVApeFJgZ
+VqMNArZ7AHsK3Kkyi+f4WVQjbQKBgQDLAWiGb5dx6fAM2W6B6HjNmzjBWOuVEXa2
+76to9jzupBZmETfZgxtWUaWUDuNS+f7dtVUTE+p6v/w8clrHEhEZYkqunIOLo/UA
+LFPiuoTfEsWb1rh+nsCjCgy4uimixj/bSkf7NC6NyKTvCygA1mGnVVJUEPegYlDy
+LXCkaKWxHQKBgQCmyHSKL2lrJkEcOwakEU2acNCE3Gno/cT9SYmV83kvQ8JEqmrW
+QqnRsp9aXIljGscapPmKsmnNt5vNp1AxFAHTYh88NRLczsMIyZj0ZwgHVUI6KhC7
+5Psa78YQQBlMt2/g9TSsnuE+rYgF6mpKFiNm0Vasqeg47uzn2mdzqlUGTQKBgE04
+JutkTUY+h1pL5vYxWKpVDfy19z7H2tFxT1FowPrBneeLSyRI88Ac5I/yLdRlVeY9
+0LOmEr5Igwj3MsKgg7KVKfVLgdo/LrW3Jt2Kt3onKNXDkoBPoNUjwH0QC0Boiue+
+VK0gR0kVdm+bXccbxR+im+NwZNE0NLg6Qqu3RredAoGBALuVoqbPPmTCZXYG328H
+bzOs2aiR7BzPSVByV+qG6jW7w03RAnFPJZp7HMU+ViI5VY0wabUscMSvz5163+gM
+4KwY3v9ZjZzZGukIfLuudkdqtaiVOx/KeAC0n+nG21YU+wpZww8gkfHh1/sa2CME
+CWYCgOnmiTHcj83UaTqEXtmv
+-----END PRIVATE KEY-----
diff --git a/demo/grouper/configs-and-secrets/midpoint/shibboleth/idp-metadata.xml b/demo/grouper/configs-and-secrets/midpoint/shibboleth/idp-metadata.xml
new file mode 100644
index 0000000..4fa67a7
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/midpoint/shibboleth/idp-metadata.xml
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+ example.org
+
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUS9SuTXwsFVVG+LjOEAbLqqT/el0wDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMjZaFw0zNTEy
+MTEwMjIwMjZaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCMAoDHx8xCIfv/6QKqt9mcHYmEJ8y2dKprUbpdcOjH
+YvNPIl/lHPsUyrb+Nc+q2CDeiWjVk1mWYq0UpIwpBMuw1H6+oOqr4VQRi65pin0M
+SfE0MWIaFo5FPvpvoptkHD4gvREbm4swyXGMczcMRfqgalFXhUD2wz8W3XAM5Cq2
+03XeJbj6TwjvKatG5XPdeUe2FBGuOO2q54L1hcIGnLMCQrg7D31lR13PJbjnJ0No
+5C3k8TPuny6vJsBC03GNLNKfmrKVTdzr3VKp1uay1G3DL9314fgmbl8HA5iRQmy+
+XInUU6/8NXZSF59p3ITAOvZQeZsbJjg5gGDip5OZo9YlAgMBAAGjWzBZMB0GA1Ud
+DgQWBBRPlM4VkKZ0U4ec9GrIhFQl0hNbLDA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAIZ0a1ov3my3ljJG588I/PHx+TxAWONWmpKbO9c/qI3Drxk4oRIffiac
+ANxdvtabgIzrlk5gMMisD7oyqHJiWgKv5Bgctd8w3IS3lLl7wHX65mTKQRXniG98
+NIjkvfrhe2eeJxecOqnDI8GOhIGCIqZUn8ShdM/yHjhQ2Mh0Hj3U0LlKvnmfGSQl
+j0viGwbFCaNaIP3zc5UmCrdE5h8sWL3Fu7ILKM9RyFa2ILHrJScV9t623IcHffHP
+IeaY/WtuapsrqRFxuQL9QFWN0FsRIdLmjTq+00+B/XnnKRKFBuWfjhHLF/uu8f+E
+t6Lf23Kb8yD6ZR7dihMZAGHnYQ/hlhM=
+
+
+
+
+
+
+
+
+
+MIIDFDCCAfygAwIBAgIVAN3vv+b7KN5Se9m1RZsCllp/B/hdMA0GCSqGSIb3DQEB
+CwUAMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwHhcNMTUxMjExMDIyMDE0WhcNMzUx
+MjExMDIyMDE0WjAVMRMwEQYDVQQDDAppZHB0ZXN0YmVkMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAh91caeY0Q85uhaUyqFwP2bMjwMFxMzRlAoqBHd7g
+u6eo4duaeLz1BaoR2XTBpNNvFR5oHH+TkKahVDGeH5+kcnIpxI8JPdsZml1srvf2
+Z6dzJsulJZUdpqnngycTkGtZgEoC1vmYVky2BSAIIifmdh6s0epbHnMGLsHzMKfJ
+Cb/Q6dYzRWTCPtzE2VMuQqqWgeyMr7u14x/Vqr9RPEFsgY8GIu5jzB6AyUIwrLg+
+MNkv6aIdcHwxYTGL7ijfy6rSWrgBflQoYRYNEnseK0ZHgJahz4ovCag6wZAoPpBs
+uYlY7lEr89Ucb6NHx3uqGMsXlDFdE4QwfDLLhCYHPvJ0uwIDAQABo1swWTAdBgNV
+HQ4EFgQUAkOgED3iYdmvQEOMm6u/JmD/UTQwOAYDVR0RBDEwL4IKaWRwdGVzdGJl
+ZIYhaHR0cHM6Ly9pZHB0ZXN0YmVkL2lkcC9zaGliYm9sZXRoMA0GCSqGSIb3DQEB
+CwUAA4IBAQBIdd4YWlnvJjql8+zKKgmWgIY7U8DA8e6QcbAf8f8cdE33RSnjI63X
+sv/y9GfmbAVAD6RIAXPFFeRYJ08GOxGI9axfNaKdlsklJ9bk4ducHqgCSWYVer3s
+RQBjxyOfSTvk9YCJvdJVQRJLcCvxwKakFCsOSnV3t9OvN86Ak+fKPVB5j2fM/0fZ
+Kqjn3iqgdNPTLXPsuJLJO5lITRiBa4onmVelAiCstI9PQiaEck+oAHnMTnC9JE/B
+DHv3e4rwq3LznlqPw0GSd7xqNTdMDwNOWjkuOr3sGpWS8ms/ZHHXV1Vd22uPe70i
+s00xrv14zLifcc8oj5DYzOhYRifRXgHX
+
+
+
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUG6Nn1rlERS1vsi88tcdzSYX0oqAwDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMTRaFw0zNTEy
+MTEwMjIwMTRaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCBXv0o3fmT8iluyLjJ4lBAVCW+ZRVyEXPYQuRi7vfD
+cO4a6d1kxiJLsaK0W88VNxjFQRr8PgDkWr28vwoH1rgk4pLsszLD48DBzD942peJ
+l/S6FnsIJjmaHcBh4pbNhU4yowu63iKkvttrcZAEbpEro6Z8CziWEx8sywoaYEQG
+ifPkr9ORV6Cn3txq+9gMBePG41GrtZrUGIu+xrndL0Shh4Pq0eq/9MAsVlIIXEa8
+9WfH8J2kFcTOfoWtIc70b7TLZQsx4YnNcnrGLSUEcstFyPLX+Xtv5SNZF89OOIxX
+VNjNvgE5DbJb9hMM4UAFqI+1bo9QqtxwThjc/sOvIxzNAgMBAAGjWzBZMB0GA1Ud
+DgQWBBStTyogRPuAVG6q7yPyav1uvE+7pTA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAFMfoOv+oISGjvamq7+Y4G7ep5vxlAPeK3RATYPYvAmyH946qZXh98ni
+QXyuqZW5P5eEt86toY45IwDU5r09SKwHughEe99iiEkxh0mb2qo84qX9/qcg+kyN
+jeLd/OSyolpUCEFNwOFcog7pj7Eer+6AHbwTn1Mjb5TBsKwtDMJsaxPvdj0u7M5r
+xL/wHkFhn1rCo2QiojzjSlV3yLTh49iTyhE3cG+RxaNKDCxhp0jSSLX1BW/ZoPA8
++PMJEA+Q0QbyRD8aJOHN5O8jGxCa/ZzcOnYVL6AsEXoDiY3vAUYh1FUonOWw0m9H
+p+tGUbGS2l873J5PrsbpeKEVR/IIoKo=
+
+
+
+
+
+
+ urn:mace:shibboleth:1.0:nameIdentifier
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+
+
+
+
+
+
+
+
+ localhost
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUS9SuTXwsFVVG+LjOEAbLqqT/el0wDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMjZaFw0zNTEy
+MTEwMjIwMjZaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCMAoDHx8xCIfv/6QKqt9mcHYmEJ8y2dKprUbpdcOjH
+YvNPIl/lHPsUyrb+Nc+q2CDeiWjVk1mWYq0UpIwpBMuw1H6+oOqr4VQRi65pin0M
+SfE0MWIaFo5FPvpvoptkHD4gvREbm4swyXGMczcMRfqgalFXhUD2wz8W3XAM5Cq2
+03XeJbj6TwjvKatG5XPdeUe2FBGuOO2q54L1hcIGnLMCQrg7D31lR13PJbjnJ0No
+5C3k8TPuny6vJsBC03GNLNKfmrKVTdzr3VKp1uay1G3DL9314fgmbl8HA5iRQmy+
+XInUU6/8NXZSF59p3ITAOvZQeZsbJjg5gGDip5OZo9YlAgMBAAGjWzBZMB0GA1Ud
+DgQWBBRPlM4VkKZ0U4ec9GrIhFQl0hNbLDA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAIZ0a1ov3my3ljJG588I/PHx+TxAWONWmpKbO9c/qI3Drxk4oRIffiac
+ANxdvtabgIzrlk5gMMisD7oyqHJiWgKv5Bgctd8w3IS3lLl7wHX65mTKQRXniG98
+NIjkvfrhe2eeJxecOqnDI8GOhIGCIqZUn8ShdM/yHjhQ2Mh0Hj3U0LlKvnmfGSQl
+j0viGwbFCaNaIP3zc5UmCrdE5h8sWL3Fu7ILKM9RyFa2ILHrJScV9t623IcHffHP
+IeaY/WtuapsrqRFxuQL9QFWN0FsRIdLmjTq+00+B/XnnKRKFBuWfjhHLF/uu8f+E
+t6Lf23Kb8yD6ZR7dihMZAGHnYQ/hlhM=
+
+
+
+
+
+
+
+
+
+MIIDFDCCAfygAwIBAgIVAN3vv+b7KN5Se9m1RZsCllp/B/hdMA0GCSqGSIb3DQEB
+CwUAMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwHhcNMTUxMjExMDIyMDE0WhcNMzUx
+MjExMDIyMDE0WjAVMRMwEQYDVQQDDAppZHB0ZXN0YmVkMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAh91caeY0Q85uhaUyqFwP2bMjwMFxMzRlAoqBHd7g
+u6eo4duaeLz1BaoR2XTBpNNvFR5oHH+TkKahVDGeH5+kcnIpxI8JPdsZml1srvf2
+Z6dzJsulJZUdpqnngycTkGtZgEoC1vmYVky2BSAIIifmdh6s0epbHnMGLsHzMKfJ
+Cb/Q6dYzRWTCPtzE2VMuQqqWgeyMr7u14x/Vqr9RPEFsgY8GIu5jzB6AyUIwrLg+
+MNkv6aIdcHwxYTGL7ijfy6rSWrgBflQoYRYNEnseK0ZHgJahz4ovCag6wZAoPpBs
+uYlY7lEr89Ucb6NHx3uqGMsXlDFdE4QwfDLLhCYHPvJ0uwIDAQABo1swWTAdBgNV
+HQ4EFgQUAkOgED3iYdmvQEOMm6u/JmD/UTQwOAYDVR0RBDEwL4IKaWRwdGVzdGJl
+ZIYhaHR0cHM6Ly9pZHB0ZXN0YmVkL2lkcC9zaGliYm9sZXRoMA0GCSqGSIb3DQEB
+CwUAA4IBAQBIdd4YWlnvJjql8+zKKgmWgIY7U8DA8e6QcbAf8f8cdE33RSnjI63X
+sv/y9GfmbAVAD6RIAXPFFeRYJ08GOxGI9axfNaKdlsklJ9bk4ducHqgCSWYVer3s
+RQBjxyOfSTvk9YCJvdJVQRJLcCvxwKakFCsOSnV3t9OvN86Ak+fKPVB5j2fM/0fZ
+Kqjn3iqgdNPTLXPsuJLJO5lITRiBa4onmVelAiCstI9PQiaEck+oAHnMTnC9JE/B
+DHv3e4rwq3LznlqPw0GSd7xqNTdMDwNOWjkuOr3sGpWS8ms/ZHHXV1Vd22uPe70i
+s00xrv14zLifcc8oj5DYzOhYRifRXgHX
+
+
+
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUG6Nn1rlERS1vsi88tcdzSYX0oqAwDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMTRaFw0zNTEy
+MTEwMjIwMTRaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCBXv0o3fmT8iluyLjJ4lBAVCW+ZRVyEXPYQuRi7vfD
+cO4a6d1kxiJLsaK0W88VNxjFQRr8PgDkWr28vwoH1rgk4pLsszLD48DBzD942peJ
+l/S6FnsIJjmaHcBh4pbNhU4yowu63iKkvttrcZAEbpEro6Z8CziWEx8sywoaYEQG
+ifPkr9ORV6Cn3txq+9gMBePG41GrtZrUGIu+xrndL0Shh4Pq0eq/9MAsVlIIXEa8
+9WfH8J2kFcTOfoWtIc70b7TLZQsx4YnNcnrGLSUEcstFyPLX+Xtv5SNZF89OOIxX
+VNjNvgE5DbJb9hMM4UAFqI+1bo9QqtxwThjc/sOvIxzNAgMBAAGjWzBZMB0GA1Ud
+DgQWBBStTyogRPuAVG6q7yPyav1uvE+7pTA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAFMfoOv+oISGjvamq7+Y4G7ep5vxlAPeK3RATYPYvAmyH946qZXh98ni
+QXyuqZW5P5eEt86toY45IwDU5r09SKwHughEe99iiEkxh0mb2qo84qX9/qcg+kyN
+jeLd/OSyolpUCEFNwOFcog7pj7Eer+6AHbwTn1Mjb5TBsKwtDMJsaxPvdj0u7M5r
+xL/wHkFhn1rCo2QiojzjSlV3yLTh49iTyhE3cG+RxaNKDCxhp0jSSLX1BW/ZoPA8
++PMJEA+Q0QbyRD8aJOHN5O8jGxCa/ZzcOnYVL6AsEXoDiY3vAUYh1FUonOWw0m9H
+p+tGUbGS2l873J5PrsbpeKEVR/IIoKo=
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/configs-and-secrets/midpoint/shibboleth/shibboleth2.xml b/demo/grouper/configs-and-secrets/midpoint/shibboleth/shibboleth2.xml
new file mode 100644
index 0000000..ee05a97
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/midpoint/shibboleth/shibboleth2.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SAML2
+
+
+
+ SAML2 Local
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-encrypt-cert.pem b/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-encrypt-cert.pem
new file mode 100644
index 0000000..7a66196
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-encrypt-cert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID/TCCAmWgAwIBAgIJAINng1bI63LGMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNV
+BAMTEnNwdGVzdC5leGFtcGxlLmVkdTAeFw0xODEyMjAyMjM4MDJaFw0yODEyMTcy
+MjM4MDJaMB0xGzAZBgNVBAMTEnNwdGVzdC5leGFtcGxlLmVkdTCCAaIwDQYJKoZI
+hvcNAQEBBQADggGPADCCAYoCggGBAOjmPSBzRsjbPBBA6jYVW+QtsYM5fvIuNErG
+VDRvKHyCTNbmdFZ37qEl/fwsrdF4hn4V7fAZ6jW6R1aMGFl1vQyJ289B8l5HOPjf
+GuB2gL9IxulOmrkYVN8nfgjlbFNNktMQJ8NprYEyl3o786xCCxx3AiA5Mgdv400L
+6vlmEfNHIwsOHAUTNRyCwMS9P6jBJ5IIxD0Mef+3oUjAvVsPZu24EJnzTUasZnI0
+F8aC/YzVbxObBNcymtA2Ipec/gLe1B09eDZUduXPL/as57QWvgJrWj8bCK+Ldj0P
+MPSvWzr4BnN58dxaYgCgRH7tnhZudPvCjBakQzkxo/njsRIKtm3lN9UmUYiXbl+e
+bu0DSQFUaFfO2hOOUTNAr/QuC+GQL+U7VAdybTbP+KcH5LbNUSqYkxSwhbFz5aym
+o5KppnYB9K5iySRWvGIhnwXHNv5yFrmUbet2BPJlMzv7NaePaZ76ypobzNjjNBbg
+aNECsQ1ZD9fe2Q8UBe0m2gQP5Yux5QIDAQABo0AwPjAdBgNVHREEFjAUghJzcHRl
+c3QuZXhhbXBsZS5lZHUwHQYDVR0OBBYEFGcLIl5kg+GFIh9HXeZyLzsv5e7qMA0G
+CSqGSIb3DQEBCwUAA4IBgQAf8/iZXUWtWGMBw2OfonDDWbuhgLnNWddpllcVx7v/
+Yu75+wgfIdNXg6XM4WkGkpbhlkpDLRt2c6rMQpxrQtq/5G3OKEXKyjUOl5pZsYkG
+asVENYPSCfuu3rlK85XaW3H1SSJqSax/UKcYXyB1TIW6mNy3OxuvHak6y4LzFnug
+CO7p/W2jvffwmxfqjbO7wQfXUQz3SZS04sHMqQoStOwy2N5xxQ3uTF34EoXBto+n
+XIEOptKPhV2NkEzj+UUIi1588dck8T0SstbSElbTnJ4sNZFriX6JOPFNW08fezot
+izerOHuAFpFQvtugWoZT87YYaFwG+Zr5QNa4fNOcAL+FHvbOfEqIGs+H6GSf0dZV
+lkcJyzWZvuK/4RGqWbLvfAYRm0PAGTQSLdO8QJSYWdJtJvZFEMgddQ2HoIzeO5wo
+B42FKDSHottI9avilApQBdRCtust8XRPtEAzDB/t/1jbO7u2tkzgY3614mX5xgut
+Ileaae5eVCjw4uYbkh+Mt5M=
+-----END CERTIFICATE-----
diff --git a/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-encrypt-key.pem b/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-encrypt-key.pem
new file mode 100644
index 0000000..1622ef3
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-encrypt-key.pem
@@ -0,0 +1,40 @@
+-----BEGIN PRIVATE KEY-----
+MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDo5j0gc0bI2zwQ
+QOo2FVvkLbGDOX7yLjRKxlQ0byh8gkzW5nRWd+6hJf38LK3ReIZ+Fe3wGeo1ukdW
+jBhZdb0MidvPQfJeRzj43xrgdoC/SMbpTpq5GFTfJ34I5WxTTZLTECfDaa2BMpd6
+O/OsQgscdwIgOTIHb+NNC+r5ZhHzRyMLDhwFEzUcgsDEvT+owSeSCMQ9DHn/t6FI
+wL1bD2btuBCZ801GrGZyNBfGgv2M1W8TmwTXMprQNiKXnP4C3tQdPXg2VHblzy/2
+rOe0Fr4Ca1o/Gwivi3Y9DzD0r1s6+AZzefHcWmIAoER+7Z4WbnT7wowWpEM5MaP5
+47ESCrZt5TfVJlGIl25fnm7tA0kBVGhXztoTjlEzQK/0LgvhkC/lO1QHcm02z/in
+B+S2zVEqmJMUsIWxc+WspqOSqaZ2AfSuYskkVrxiIZ8Fxzb+cha5lG3rdgTyZTM7
++zWnj2me+sqaG8zY4zQW4GjRArENWQ/X3tkPFAXtJtoED+WLseUCAwEAAQKCAYBM
+3eCC20kbdbAnNSWX4AjKEIKr6sgJKlK78yVLgPx9y4uMydbPyxmJOj7PgfeEUSEi
+cB5txj/Up7xvxiErNX7FqqJPj1Zs41jcWtZGCxaHC4AK9JSATpWEaUZhrUbJX6r7
+2jMlfbV0FLyF7U+JJOsB5A1hkT7/0V/Vx/8vfQ6jmnDobym0SxiWZlk1Fbjy+30R
+567M71c8nOCwYFyet0CjaMKh7PkuQCw3uRW3wPfqCW91qw438E3ENnnITFpRnDUI
+iZIXJSj3Sqcx/W7Q6xei+y95U4tksT3/SQ7hVXp+BhfyjXdK/k0vNzxZfWk9nCD8
+h7HeiQuLPENzrlOwuWtI+gLDIdFplXUJ+/piK3okdstdHJcWcNUelW8yr7JSpv1I
+a2KMgHI2F4UVcTYLZrevzxd5a0cpvFW7vmvdw2vFrCb5JsVsmqBu5OLeaVGDIbIA
+2SLfJqq12fi2rxk28VtwXXgaCTttSM+8VY7dlT/mPCqX3Sx2eM7EPt6RVHuri4EC
+gcEA+3q6Vht60YXNaw7m4BFISntVm4Z2gGFNswLlrgPRHOacaQVMKhpqt3HmNKAT
+1MD/a5C60HkUjMB95m2nE4k1Iade8EzUPXD1FvFbE9/+ifNx2OrC8pKrEmRiTmCY
+oel45uoXsksNGJynfuRp2TpAVSZrXaIbGKZiMJZv0QZAilVBurZnZyV0jKQYkSFM
+FOt60PDJJEqZzG01dvDJxsIYQURtjNscO0R2ncloLXm7qu1/fcP7CAawWgFYyer2
+WEdVAoHBAO0WAhxCvFoev348Wf33lQi9c6w7WN/WEkhNOJ5p4PKsJphSZbt2bjCt
+RdRmvahSXeiGrDPuaxoWaQqcXprcu3ndFYBcK2xZpIl/mf0wr1QTEHCkRXzfxRjC
+Mmy+yTeKT4L18xKgg6pJn+wC3hwsv2BQPkp+NPJhD2bmVUWorqXq5fiBV2b7lTg0
+q1HHXYtxk22bw7xtstFENGTqa22KwD5Wd6nj9DamLzKhUhOdcJ7yGVu9se7YcGGh
+pg57muigUQKBwQD5feH96Zdo5UFN9GPTavH4ivH8sWNBrMeEUNyDTuAYtyX3/zx4
+DOtRAhwsm5/xFGSTV+wvReDAX3zIroLym85ti/phlyd9qWJOl7cPOcvzGuYZGZe9
+RwuX3KW3MphbEiFTnm1SAqmEgG6gMoZc8DDBCbO9GkWdp/yETcuzaWuAkmL6lVpy
+97LwkSCaY5lyq8iWIDy915FMQhCn5u2YVhnwLq4s73jLx/mSQy4q57nrM2Kn6FZV
+uSUetnVbJdOu810CgcBNCzbaWjF9E7rk2dXguwD6Wx5o3MxPyPAeAMIicIPCOIE+
+RKB8n8rFFLm5gT2mokWUF5eENLknPBsccJ4pswtVWavwD4Oo7SST7hxrc9O1/Y/9
+GtTd9JXHKuxZ/FHFM7QM+cHozrKattw6ROBKxZvXP5xOdt7b2QC5TqZtQZinoELl
+U5rEg4MFRdBafe//LYRcPR8Jb5iJeqGQHcGVUl6Qo2a1lbc5vx1dVaEncKU1cbUd
+4/IbjMhQYchlsnMvn1ECgcEAxwT/UvLwhYeFK6UHRwJ/z1eKGAC8R2B9tlmgddZx
+T93qbVq4lZXKw3osqdi+pgWvvmg9aK9r/dO1E93S11msnoTI+W9xTr+y5y9dN/hx
+5deQMUK+3woLog6LsGiKE2IamCNQBFkgd4VvhXgG+2pTPYJ9nyuEA+na+tfE6bSa
+foJ8KQT1rmRFQYRboBY/xxqtsl6Nh84JK7kCw27NNdhssyuiipfa8NLM4m+yeA6n
+/oz8xKl5PKwOrvk2DH+FwaAg
+-----END PRIVATE KEY-----
diff --git a/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-signing-cert.pem b/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-signing-cert.pem
new file mode 100644
index 0000000..73aaaab
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-signing-cert.pem
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID/TCCAmWgAwIBAgIJAJZqOL69C6nRMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNV
+BAMTEnNwdGVzdC5leGFtcGxlLmVkdTAeFw0xODEyMjAyMjM4NDhaFw0yODEyMTcy
+MjM4NDhaMB0xGzAZBgNVBAMTEnNwdGVzdC5leGFtcGxlLmVkdTCCAaIwDQYJKoZI
+hvcNAQEBBQADggGPADCCAYoCggGBANJ1OC6Ql4te2/7PArBkuM/EF1NcQILv7bJa
+ecJDGYBVoWgL0a2KQ0XMESusgkVmVjj/jcbtvwIiXI/6BEu815OF6eSZIwxWdQBp
+eKbrWTbt07GiGgdXoXot6oMs5a9YXuWLt8pTXrFVMmwXU+ZfWJtuU8OIgm9esAEI
+QBHvDVOJtdKdBMWJFa5nUzkaVvA0Fr8r+/FHUvSCnlKOMaUIfTgtoS9AQnaRQ1dV
+l39Z2KAh87JYvRIxvbaPaKgar2eGQ+PQD8rqsB5K5wgnADAxYM9Vo0YXSpPH+Fvw
+N3EJgURUSEY2E0Jx8JOx368ERNLXx3kfnRxCiZRDkTZF9WP6lBnDwc1WXRwpVCDT
+RnF+SIh6IC1Bj/qpkpCD3nri7tycejoeAtVj1YZHWarf9iqdcLYOAWmeyGbFl3hj
+v6qcXnIfy1KyHLCAdIrg1TymLovXXKW09pEbVLdsHmLz0h+DxPs4FsinK2AQBMn1
+6u8BJJ/+spCzIQ2QNPcGORh6XemBpQIDAQABo0AwPjAdBgNVHREEFjAUghJzcHRl
+c3QuZXhhbXBsZS5lZHUwHQYDVR0OBBYEFPC8rkASWHQxrtCQ4wwtnsJRy6K5MA0G
+CSqGSIb3DQEBCwUAA4IBgQCks2nY7YzdIKV02NHD9STWD3yPtEwPYZZ3NBno0WW2
+0rS6cU+fxFx37nY8ULve4cFQkLR8fOO44e1qIuTgLGCauSGTx/Ts/tbmZXbpGTwV
+7cjZDCfC7yEFAVrfQFOMNKeQEssuLFj+d4STGLorxsM+2YygdOgohJz0e3xOcmCN
+HqEuC9RbzrnLc/A4/mOHKwnwCCg71zA1/Ew9NUoRm2n8IfaONIUaMg9opNiHxX4e
+u3UFaaPmn/mInuWYYMXzbIbdlU/XhKvXrujWYWj7anTDWvGQmNEecsQH92SrO0pf
++9WwcWUQTQiWUdq8/OxjXfzs1PrQnSlp0eizgcdKHDKbCUaSuK1i2wdxfEsu5sbZ
+AIW0+dXJ2IyzM+0sv2g4DOsXsnSvinGqjr82A54mXGSr7edhPdlQhILFkJfhTwLq
++mjnyQSNe3s24VNeGc76jbHIrkEWuA460QGqz1Fa2CsQo5SH1IkxNIKpBZWt+w2L
+dAza/NzYyDruY5IJCrZa9Qw=
+-----END CERTIFICATE-----
diff --git a/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-signing-key.pem b/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-signing-key.pem
new file mode 100644
index 0000000..9e979fe
--- /dev/null
+++ b/demo/grouper/configs-and-secrets/midpoint/shibboleth/sp-signing-key.pem
@@ -0,0 +1,40 @@
+-----BEGIN PRIVATE KEY-----
+MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDSdTgukJeLXtv+
+zwKwZLjPxBdTXECC7+2yWnnCQxmAVaFoC9GtikNFzBErrIJFZlY4/43G7b8CIlyP
++gRLvNeThenkmSMMVnUAaXim61k27dOxohoHV6F6LeqDLOWvWF7li7fKU16xVTJs
+F1PmX1ibblPDiIJvXrABCEAR7w1TibXSnQTFiRWuZ1M5GlbwNBa/K/vxR1L0gp5S
+jjGlCH04LaEvQEJ2kUNXVZd/WdigIfOyWL0SMb22j2ioGq9nhkPj0A/K6rAeSucI
+JwAwMWDPVaNGF0qTx/hb8DdxCYFEVEhGNhNCcfCTsd+vBETS18d5H50cQomUQ5E2
+RfVj+pQZw8HNVl0cKVQg00ZxfkiIeiAtQY/6qZKQg9564u7cnHo6HgLVY9WGR1mq
+3/YqnXC2DgFpnshmxZd4Y7+qnF5yH8tSshywgHSK4NU8pi6L11yltPaRG1S3bB5i
+89Ifg8T7OBbIpytgEATJ9ervASSf/rKQsyENkDT3BjkYel3pgaUCAwEAAQKCAYEA
+kmBxGQH8RTVO8eTtS95iJC+QwavyOp/BxUDkWtbsj7P/NSyzQ25c59jNQIEVgktx
+QOeNpoSJS2S22HTeNAc+MR781MAl/ljLu+OfxQj/3hKAIJZMYDr01tPEvkOl5NUj
++6e3xwNBYzmMfl2jPyGlsUWFAQSbI/bJl44zccXAkQ/A5KHNRc7Yw5qd6aOGQD8a
+axCehOxEqEeI8oZvxQcogMBL0V9yWqEiI0Ymvq6w2n+CzdKmflcWSjloYzNcODbL
+Ef2+8/fBZhHTS0GLCIqQpK+tZxt4K77DK2p2L9dYuHK7vtWn1j0YIwPqD+QVVtuT
+d7BOOmakPj2E7EXq/GvFw8gB/gRLoLuJSq5vvhPrSVuJqWdxDuxSutGgIoN3mQxd
+2AjuBXvqwYaZ3UGHZlBYAQx5ICiAGjxv/1zmKp+9OJHge/a1e6Z8jgQcpS7OWNhU
+dj6qfs+IiWKEaMM7D8dj4ncoArBpE7/BzlVuJ377cqRx35alMcKlawQWF1YqSDrB
+AoHBAPSipCLz4sr3U2jluXehntYsKevWcBtFkEd49Ay5uZTu/aweKWIozjDt7T3L
+mjYi+QGpt28MdNmpoofYOmpt+lrc0HWrv+UB9k/qFxfwgZKaXa1nm/VLfK77L4IB
+8I9dpjvDi724Xg/JJ1jsGM13+jGEfTQTl4Hi0lZwMydUO+O4oWB4kG9qhF8C+yQc
+12CCFH+Da8uwcwM+zCJwRm3qMKceifhEGAuFJ430Rp7cuqlJYfQZ4pVhRxwP6vns
+cLCz+QKBwQDcPB5bCjci/HMe0V19HxPrKh0hGPLIRCPAakT8Mz8N2lVAtWDXFL5q
+eHskl6cf8RQLfrcUiL+jQvD5VV8I7BkolCv0GZT/q36I/Z1QKlQC1O0IGG/hNqwt
+PS85YM6yC84YIKx0rN6O03/nYcslRv19q+MNiR9sZEeN6cScUc6aUINhWjzQ4mb8
+Z9ErguJrq0sCoAVU+t/yRo/YB/d2xdN9XLe+2cgsM6s0TiHo4v2SeFHKewBw+RLp
+yrShY6COzg0CgcEA0EFwt2ylgiGgeSkvhV8qJ6s7GNDZaO4EUEPwhrDJAredbhvT
+IQQZ29+AWl3sbu/AySCgzsFs7CsT+M8jk50CRr26HKJUXvEXrZpbhH6y34nX+5m7
+U8uqXg/ptqROFM4liLUETkMYmBmnDHUY/DmJ3QOrzlxrWyAr7XfgpDd6MHbpsoWQ
+d7jW7UdNYsXGuBqktpS7fJA+qOGZyCuKWWHHf01pKNdXHN+C976fK/g+U4TsBXDP
+ylkgvwvx/kbA/DyJAoHAQxXA/WRYNT0G6B1ISAO+coTKiLlrwtsWtNbqGpSVoWef
+Tm2xiPKVqiL3B8d2LgGmZHX92LBrB5UtiBWcNECOzVCNLvbX7yVTDvGKCNBL9Ozd
+Ivkmo0ifG8ymZOj7LTrxVWImhgfeZ00/icC9O6arMqu4Jvhc7QyCy1SpAiDdOR5L
+Vs1A9zPvwPTyvzlINRnhaHRMC32717XsvRZ4J+LMsEQc6HK4SdaXUQB3zdPO/93M
+tEvRb5g/TZ3kdcC+OKHFAoHAO9R3y6ZjUM8T8/4XcyRD968V4sZIvVQfpSaH86GO
+TrECZp5SqSWUTqAWTJWS0yIctAML60nWF+OPRUlrq0yk2veN9Re6eWfyoyQOFd92
+U+bxh3QEue5LGOwpqrPV/1cJSFdv88eS+F8q7i/dD765Tio6kJjKzXPN3FJqAvNB
+lAnaO4Apbuzob25Qkmm0NVQHap+TJGJMvX2vVX9CjE6haVWq1lJMakkoQOeIlyi5
+iDjt9rDlIwDYeGWk4KFgsKM7
+-----END PRIVATE KEY-----
diff --git a/demo/grouper/create-ref-loaders.gsh b/demo/grouper/create-ref-loaders.gsh
new file mode 100644
index 0000000..0cfdcdf
--- /dev/null
+++ b/demo/grouper/create-ref-loaders.gsh
@@ -0,0 +1,31 @@
+gs = GrouperSession.startRootSession()
+
+group = new GroupSave(gs).assignName("etc:affiliationLoader").assignCreateParentStemsIfNotExist(true).save()
+group.addType(GroupTypeFinder.find("grouperLoader"))
+group.setAttribute("grouperLoaderDbName", "sis")
+group.setAttribute("grouperLoaderType", "SQL_GROUP_LIST")
+group.setAttribute("grouperLoaderScheduleType", "CRON")
+group.setAttribute("grouperLoaderQuartzCron", "0 * * * * ?")
+group.setAttribute("grouperLoaderDbName", "sis")
+group.setAttribute("grouperLoaderGroupTypes", "addIncludeExclude")
+group.setAttribute("grouperLoaderQuery", "SELECT concat('ref:affiliation:',affiliation,'_systemOfRecord') as GROUP_NAME, uid as SUBJECT_ID, 'ldap' as SUBJECT_SOURCE_ID from SIS_AFFILIATIONS")
+
+group = new GroupSave(gs).assignName("etc:deptLoader").assignCreateParentStemsIfNotExist(true).save()
+group.addType(GroupTypeFinder.find("grouperLoader"))
+group.setAttribute("grouperLoaderDbName", "sis")
+group.setAttribute("grouperLoaderType", "SQL_GROUP_LIST")
+group.setAttribute("grouperLoaderScheduleType", "CRON")
+group.setAttribute("grouperLoaderQuartzCron", "0 * * * * ?")
+group.setAttribute("grouperLoaderDbName", "sis")
+group.setAttribute("grouperLoaderQuery", "SELECT concat('ref:dept:',department) as GROUP_NAME, uid as SUBJECT_ID, 'ldap' as SUBJECT_SOURCE_ID from SIS_PERSONS where department is not null")
+
+group = new GroupSave(gs).assignName("etc:coursesLoader").assignCreateParentStemsIfNotExist(true).save()
+group.addType(GroupTypeFinder.find("grouperLoader"))
+group.setAttribute("grouperLoaderDbName", "sis")
+group.setAttribute("grouperLoaderType", "SQL_GROUP_LIST")
+group.setAttribute("grouperLoaderScheduleType", "CRON")
+group.setAttribute("grouperLoaderQuartzCron", "0 * * * * ?")
+group.setAttribute("grouperLoaderDbName", "sis")
+group.setAttribute("grouperLoaderQuery", "SELECT concat('ref:course:',courseId) as GROUP_NAME, uid as SUBJECT_ID, 'ldap' as SUBJECT_SOURCE_ID from SIS_COURSES")
+
+edu.internet2.middleware.grouper.app.loader.GrouperLoaderType.scheduleLoads()
diff --git a/demo/grouper/create-ref-loaders.sh b/demo/grouper/create-ref-loaders.sh
new file mode 100755
index 0000000..c9cd9cc
--- /dev/null
+++ b/demo/grouper/create-ref-loaders.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ../../library.bash
+
+execute_gsh grouper_grouper_daemon_1 create-ref-loaders.gsh
diff --git a/demo/grouper/directory/Dockerfile b/demo/grouper/directory/Dockerfile
new file mode 100644
index 0000000..6e34ead
--- /dev/null
+++ b/demo/grouper/directory/Dockerfile
@@ -0,0 +1,28 @@
+FROM centos:centos7
+
+LABEL author="tier-packaging@internet2.edu "
+
+RUN yum install -y epel-release \
+ && yum update -y \
+ && yum install -y 389-ds-base \
+ && yum clean all \
+ && rm -rf /var/cache/yum
+
+COPY container_files/seed-data/ /seed-data/
+
+RUN useradd ldapadmin \
+ && rm -fr /var/lock /usr/lib/systemd/system \
+ # The 389-ds setup will fail because the hostname can't reliable be determined, so we'll bypass it and then install. \
+ && sed -i 's/checkHostname {/checkHostname {\nreturn();/g' /usr/lib64/dirsrv/perl/DSUtil.pm \
+ # Not doing SELinux \
+ && sed -i 's/updateSelinuxPolicy($inf);//g' /usr/lib64/dirsrv/perl/* \
+ # Do not restart at the end \
+ && sed -i '/if (@errs = startServer($inf))/,/}/d' /usr/lib64/dirsrv/perl/* \
+ && setup-ds.pl --silent --file /seed-data/ds-setup.inf \
+ && /usr/sbin/ns-slapd -D /etc/dirsrv/slapd-dir \
+ && while ! curl -s ldap://localhost:389 > /dev/null; do echo waiting for ldap to start; sleep 1; done; \
+ ldapadd -H ldap:/// -f /seed-data/data.ldif -x -D "cn=Directory Manager" -w password
+
+EXPOSE 389
+
+CMD rm -rf /var/lock/dirsrv/slapd-dir/server/* && /usr/sbin/ns-slapd -D /etc/dirsrv/slapd-dir && sleep infinity
diff --git a/demo/grouper/directory/container_files/seed-data/data.ldif b/demo/grouper/directory/container_files/seed-data/data.ldif
new file mode 100644
index 0000000..1b53642
--- /dev/null
+++ b/demo/grouper/directory/container_files/seed-data/data.ldif
@@ -0,0 +1,51 @@
+dn: cn=admin,dc=internet2,dc=edu
+objectClass: simpleSecurityObject
+objectClass: organizationalRole
+cn: admin
+userPassword: password
+description: LDAP administrator
+
+dn: uid=banderson,ou=People,dc=internet2,dc=edu
+objectClass: eduPerson
+objectClass: inetOrgPerson
+objectClass: organizationalPerson
+objectClass: person
+objectClass: top
+cn: Bob Anderson
+sn: Anderson
+givenName: Bob
+userPassword: password
+description: LDAP administrator
+
+dn: ou=Affiliations,ou=Groups,dc=internet2,dc=edu
+objectClass: top
+objectClass: organizationalUnit
+ou: Affiliations
+
+dn: ou=Courses,ou=Groups,dc=internet2,dc=edu
+objectClass: top
+objectClass: organizationalUnit
+ou: Courses
+
+dn: ou=midpoint,ou=Groups,dc=internet2,dc=edu
+objectClass: top
+objectClass: organizationalUnit
+ou: midpoint
+
+dn: ou=Generic,ou=Groups,dc=internet2,dc=edu
+objectClass: top
+objectClass: organizationalUnit
+ou: Generic
+
+dn: cn=users,ou=Groups,dc=internet2,dc=edu
+objectClass: groupOfUniqueNames
+objectClass: top
+uniqueMember: uid=banderson,ou=People,dc=internet2,dc=edu
+cn: users
+
+dn: cn=sysadmingroup,ou=midpoint,ou=Groups,dc=internet2,dc=edu
+objectClass: groupOfUniqueNames
+objectClass: top
+uniqueMember: uid=banderson,ou=People,dc=internet2,dc=edu
+cn: sysadmingroup
+
diff --git a/demo/grouper/directory/container_files/seed-data/ds-setup.inf b/demo/grouper/directory/container_files/seed-data/ds-setup.inf
new file mode 100644
index 0000000..96c29a1
--- /dev/null
+++ b/demo/grouper/directory/container_files/seed-data/ds-setup.inf
@@ -0,0 +1,28 @@
+[General]
+AdminDomain = internet2.edu
+ConfigDirectoryAdminID = admin
+ConfigDirectoryAdminPwd = admin
+ConfigDirectoryLdapURL = ldap://localhost:389/o=NetscapeRoot
+FullMachineName = localhost
+ServerRoot = /usr/lib64/dirsrv
+SuiteSpotGroup = nobody
+SuiteSpotUserID = nobody
+
+[admin]
+Port = 9830
+ServerAdminID = admin
+ServerAdminPwd = admin
+ServerIpAddress = 0.0.0.0
+SysUser = nobody
+
+[slapd]
+AddOrgEntries = No
+AddSampleEntries = No
+InstallLdifFile = suggest
+RootDN = cn=Directory Manager
+RootDNPwd = password
+ServerIdentifier = dir
+ServerPort = 389
+SlapdConfigForMC = yes
+Suffix = dc=internet2,dc=edu
+UseExistingMC = No
diff --git a/demo/grouper/docker-compose.yml b/demo/grouper/docker-compose.yml
new file mode 100644
index 0000000..eec356d
--- /dev/null
+++ b/demo/grouper/docker-compose.yml
@@ -0,0 +1,302 @@
+version: "3.3"
+
+services:
+ grouper_daemon:
+ build: ./grouper_daemon/
+ command: bash -c "while ! curl -s grouper_data:3306 > /dev/null; do echo waiting for mysql on grouper_data to start; sleep 3; done; while ! curl -s ldap://directory:389 > /dev/null; do echo waiting for ldap on directory to start; sleep 3; done; /usr/local/bin/startup.sh"
+ depends_on:
+ - grouper_data
+ - directory
+ environment:
+ - ENV
+ - USERTOKEN
+ - GROUPER_CLIENT_WEBSERVICE_PASSWORD_FILE=password
+ - GROUPER_DATABASE_PASSWORD_FILE=/run/secrets/g_database_password.txt
+ - RABBITMQ_PASSWORD_FILE=/run/secrets/rabbitmq_password.txt
+ - SUBJECT_SOURCE_LDAP_PASSWORD=password
+ networks:
+ net:
+ aliases:
+ - grouper-daemon
+ secrets:
+ - g_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: subject.properties
+ target: grouper_subject.properties
+ volumes:
+ - type: bind
+ source: ./configs-and-secrets/grouper/application/grouper.properties
+ target: /opt/grouper/conf/grouper.properties
+ - type: bind
+ source: ./configs-and-secrets/grouper/application/grouper.client.properties
+ target: /opt/grouper/conf/grouper.client.properties
+
+ grouper_ui:
+ build: ./grouper_ui/
+ command: bash -c "while ! curl -s grouper_data:3306 > /dev/null; do echo waiting for mysql on grouper_data to start; sleep 3; done; while ! curl -s ldap://directory:389 > /dev/null; do echo waiting for ldap on directory to start; sleep 3; done; exec ui"
+ depends_on:
+ - grouper_data
+ - directory
+ environment:
+ - ENV
+ - USERTOKEN
+ - GROUPER_DATABASE_PASSWORD_FILE=/run/secrets/g_database_password.txt
+ - SUBJECT_SOURCE_LDAP_PASSWORD=password
+ networks:
+ net:
+ aliases:
+ - grouper-ui
+ ports:
+ - 4443:443
+ secrets:
+ - g_database_password.txt
+ - source: grouper.hibernate.properties
+ target: grouper_grouper.hibernate.properties
+ - source: grouper-loader.properties
+ target: grouper_grouper-loader.properties
+ - source: subject.properties
+ target: grouper_subject.properties
+ - source: g_sp-key.pem
+ target: shib_sp-key.pem
+ - source: g_host-key.pem
+ target: host-key.pem
+ volumes:
+ - type: bind
+ source: ./configs-and-secrets/grouper/application/grouper.properties
+ target: /opt/grouper/conf/grouper.properties
+ - type: bind
+ source: ./configs-and-secrets/grouper/application/grouper.client.properties
+ target: /opt/grouper/conf/grouper.client.properties
+ - type: bind
+ source: ./configs-and-secrets/grouper/shibboleth/sp-cert.pem
+ target: /etc/shibboleth/sp-cert.pem
+ - type: bind
+ source: ./configs-and-secrets/grouper/shibboleth/shibboleth2.xml
+ target: /etc/shibboleth/shibboleth2.xml
+ - type: bind
+ source: ./configs-and-secrets/grouper/shibboleth/idp-metadata.xml
+ target: /etc/shibboleth/idp-metadata.xml
+ - type: bind
+ source: ./configs-and-secrets/grouper/httpd/host-cert.pem
+ target: /etc/pki/tls/certs/host-cert.pem
+ - type: bind
+ source: ./configs-and-secrets/grouper/httpd/host-cert.pem
+ target: /etc/pki/tls/certs/cachain.pem
+
+ grouper_ws:
+ build: ./grouper_ws/
+ command: bash -c "while ! curl -s grouper_data:3306 > /dev/null; do echo waiting for mysql to start; sleep 3; done; while ! curl -s ldap://directory:389 > /dev/null; do echo waiting for ldap to start; sleep 3; done; exec ws"
+ depends_on:
+ - grouper_data
+ - directory
+ environment:
+ - ENV
+ - GROUPER_DATABASE_PASSWORD_FILE=/run/secrets/g_database_password.txt
+ - SUBJECT_SOURCE_LDAP_PASSWORD=password
+ - USERTOKEN
+ networks:
+ net:
+ aliases:
+ - grouper-ws
+ ports:
+ - 9443:443
+ secrets:
+ - g_database_password.txt
+ - source: grouper.hibernate.properties
+ target: grouper_grouper.hibernate.properties
+ - source: grouper-loader.properties
+ target: grouper_grouper-loader.properties
+ - source: subject.properties
+ target: grouper_subject.properties
+ - source: g_sp-key.pem
+ target: shib_sp-key.pem
+ - source: g_host-key.pem
+ target: host-key.pem
+ volumes:
+ - type: bind
+ source: ./configs-and-secrets/grouper/application/grouper.properties
+ target: /opt/grouper/conf/grouper.properties
+ - type: bind
+ source: ./configs-and-secrets/grouper/application/grouper.client.properties
+ target: /opt/grouper/conf/grouper.client.properties
+ - type: bind
+ source: ./configs-and-secrets/grouper/httpd/host-cert.pem
+ target: /etc/pki/tls/certs/host-cert.pem
+ - type: bind
+ source: ./configs-and-secrets/grouper/httpd/host-cert.pem
+ target: /etc/pki/tls/certs/cachain.pem
+
+ grouper_data:
+ build: ./grouper_data/
+ networks:
+ net:
+ aliases:
+ - grouper-data
+ ports:
+ - 3306:3306
+ volumes:
+ - grouper_data:/var/lib/mysql
+
+ directory:
+ build: ./directory/
+ ports:
+ - 389:389
+ networks:
+ - net
+ volumes:
+ - ldap:/var/lib/dirsrv
+
+ sources:
+ build: ./sources/
+ ports:
+ - 13306:3306
+ networks:
+ - net
+ volumes:
+ - source_mysql:/var/lib/mysql
+ - source_data:/var/lib/mysqlmounted
+ environment:
+ - CREATE_NEW_DATABASE=if_needed
+
+ midpoint_data:
+ image: tier/mariadb:mariadb10
+ ports:
+ - 33306:3306
+ networks:
+ net:
+ aliases:
+ - midpoint-data
+ volumes:
+ - midpoint_mysql:/var/lib/mysql
+ - midpoint_data:/var/lib/mysqlmounted
+ environment:
+ - CREATE_NEW_DATABASE=if_needed
+
+ midpoint_server:
+ build: ./midpoint_server/
+ depends_on:
+ - midpoint_data
+ ports:
+ - 8443:443
+ environment:
+ - AUTHENTICATION
+ - ENV
+ - USERTOKEN
+ - REPO_DATABASE_TYPE
+ - REPO_JDBC_URL
+ - REPO_HOST
+ - REPO_PORT
+ - REPO_DATABASE
+ - REPO_USER
+ - REPO_MISSING_SCHEMA_ACTION
+ - REPO_UPGRADEABLE_SCHEMA_ACTION
+ - REPO_SCHEMA_VERSION_IF_MISSING
+ - REPO_SCHEMA_VARIANT
+ - MP_MEM_MAX
+ - MP_MEM_INIT
+ - MP_JAVA_OPTS
+ - SSO_HEADER
+ - TIER_BEACON_OPT_OUT
+ - TIMEZONE
+ networks:
+ net:
+ aliases:
+ - midpoint-server
+ secrets:
+ - mp_database_password.txt
+ - mp_keystore_password.txt
+ - mp_sp-encrypt-key.pem
+ - mp_sp-signing-key.pem
+ - mp_host-key.pem
+ volumes:
+ - midpoint_home:/opt/midpoint/var
+ - type: bind
+ source: ./configs-and-secrets/midpoint/shibboleth/shibboleth2.xml
+ target: /etc/shibboleth/shibboleth2.xml
+ - type: bind
+ source: ./configs-and-secrets/midpoint/shibboleth/idp-metadata.xml
+ target: /etc/shibboleth/idp-metadata.xml
+ - type: bind
+ source: ./configs-and-secrets/midpoint/shibboleth/sp-signing-cert.pem
+ target: /etc/shibboleth/sp-signing-cert.pem
+ - type: bind
+ source: ./configs-and-secrets/midpoint/shibboleth/sp-encrypt-cert.pem
+ target: /etc/shibboleth/sp-encrypt-cert.pem
+ - type: bind
+ source: ./configs-and-secrets/midpoint/httpd/host-cert.pem
+ target: /etc/pki/tls/certs/host-cert.pem
+ - type: bind
+ source: ./configs-and-secrets/midpoint/httpd/host-cert.pem
+ target: /etc/pki/tls/certs/cachain.pem
+
+ idp:
+ build: ./idp/
+ depends_on:
+ - directory
+ environment:
+ - JETTY_MAX_HEAP=64m
+ - JETTY_BROWSER_SSL_KEYSTORE_PASSWORD=password
+ - JETTY_BACKCHANNEL_SSL_KEYSTORE_PASSWORD=password
+ networks:
+ - net
+ ports:
+ - 443:443
+
+ mq:
+ build: ./mq/
+ environment:
+ - RABBITMQ_NODENAME=docker-rabbit
+ hostname: rabbitmq
+ networks:
+ - net
+ ports:
+ - 15672:15672
+ volumes:
+ - mq:/var/lib/rabbitmq
+
+networks:
+ net:
+ driver: bridge
+
+secrets:
+# grouper
+ g_host-key.pem:
+ file: ./configs-and-secrets/grouper/httpd/host-key.pem
+ g_sp-key.pem:
+ file: ./configs-and-secrets/grouper/shibboleth/sp-key.pem
+ g_database_password.txt:
+ file: ./configs-and-secrets/grouper/application/database_password.txt
+ rabbitmq_password.txt:
+ file: ./configs-and-secrets/grouper/application/rabbitmq_password.txt
+ grouper.hibernate.properties:
+ file: ./configs-and-secrets/grouper/application/grouper.hibernate.properties
+ grouper-loader.properties:
+ file: ./configs-and-secrets/grouper/application/grouper-loader.properties
+ subject.properties:
+ file: ./configs-and-secrets/grouper/application/subject.properties
+# midPoint
+ mp_host-key.pem:
+ file: ./configs-and-secrets/midpoint/httpd/host-key.pem
+ mp_sp-signing-key.pem:
+ file: ./configs-and-secrets/midpoint/shibboleth/sp-signing-key.pem
+ mp_sp-encrypt-key.pem:
+ file: ./configs-and-secrets/midpoint/shibboleth/sp-encrypt-key.pem
+ mp_database_password.txt:
+ file: ./configs-and-secrets/midpoint/application/database_password.txt
+ mp_keystore_password.txt:
+ file: ./configs-and-secrets/midpoint/application/keystore_password.txt
+
+volumes:
+ grouper_data:
+ source_data:
+ source_mysql:
+ target_data:
+ ldap:
+ midpoint_data:
+ midpoint_mysql:
+ midpoint_home:
+ mq:
diff --git a/demo/grouper/get-import-sis-persons-status.sh b/demo/grouper/get-import-sis-persons-status.sh
new file mode 100755
index 0000000..26d3fcd
--- /dev/null
+++ b/demo/grouper/get-import-sis-persons-status.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ../../library.bash
+
+get_task_execution_status "Import from SIS persons"
diff --git a/demo/grouper/grouper_daemon/Dockerfile b/demo/grouper/grouper_daemon/Dockerfile
new file mode 100644
index 0000000..f2811ea
--- /dev/null
+++ b/demo/grouper/grouper_daemon/Dockerfile
@@ -0,0 +1,6 @@
+FROM tier/grouper:2.4.0-a47-u25-w5-p6-20190611
+
+LABEL author="tier-packaging@internet2.edu "
+
+COPY container_files/tmp/* /tmp/
+COPY container_files/usr-local-bin/* /usr/local/bin/
diff --git a/demo/grouper/grouper_daemon/container_files/usr-local-bin/startup.sh b/demo/grouper/grouper_daemon/container_files/usr-local-bin/startup.sh
new file mode 100755
index 0000000..5f2a302
--- /dev/null
+++ b/demo/grouper/grouper_daemon/container_files/usr-local-bin/startup.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+if [[ -e /tmp/initialize.gsh ]]
+then
+ echo Executing /tmp/initialize.gsh on the first start
+ /opt/grouper/grouper.apiBinary/bin/gsh /tmp/initialize.gsh
+ rm /tmp/initialize.gsh
+else
+ echo Skipping execution of /tmp/initialize.gsh as it is not present
+fi
+
+daemon
diff --git a/demo/grouper/grouper_data/Dockerfile b/demo/grouper/grouper_data/Dockerfile
new file mode 100644
index 0000000..f12245e
--- /dev/null
+++ b/demo/grouper/grouper_data/Dockerfile
@@ -0,0 +1,36 @@
+FROM tier/grouper:2.4.0-a47-u25-w5-p6-20190611
+
+LABEL author="tier-packaging@internet2.edu "
+
+RUN yum install -y epel-release \
+ && yum update -y \
+ && yum install -y mariadb-server mariadb \
+ && yum clean all \
+ && rm -rf /var/cache/yum
+
+COPY container_files/conf/ /opt/grouper/grouper.apiBinary/conf/
+
+RUN ln -s /usr/bin/resolveip /usr/libexec/resolveip
+
+RUN mysql_install_db \
+ && chown -R mysql:mysql /var/lib/mysql/ \
+ && sed -i 's/^\(bind-address\s.*\)/# \1/' /etc/my.cnf \
+ && sed -i 's/^\(log_error\s.*\)/# \1/' /etc/my.cnf \
+ && sed -i 's/\[mysqld\]/\[mysqld\]\ncharacter_set_server = utf8/' /etc/my.cnf \
+ && sed -i 's/\[mysqld\]/\[mysqld\]\ncollation_server = utf8_general_ci/' /etc/my.cnf \
+ && sed -i 's/\[mysqld\]/\[mysqld\]\nport = 3306/' /etc/my.cnf \
+ && cat /etc/my.cnf \
+ && echo "/usr/bin/mysqld_safe &" > /tmp/config \
+ && echo "mysqladmin --silent --wait=30 ping || exit 1" >> /tmp/config \
+ && echo "mysql -e 'GRANT ALL PRIVILEGES ON *.* TO \"root\"@\"%\" WITH GRANT OPTION;'" >> /tmp/config \
+ && echo "mysql -e 'CREATE DATABASE grouper CHARACTER SET utf8 COLLATE utf8_bin;'" >> /tmp/config \
+ && bash /tmp/config \
+ && rm -f /tmp/config
+
+RUN (mysqld_safe & ) \
+ && while ! curl -s localhost:3306 > /dev/null; do echo waiting for mysqld to start; sleep 1; done; \
+ bin/gsh -registry -check -runscript -noprompt
+
+EXPOSE 3306
+
+CMD mysqld_safe
diff --git a/demo/grouper/grouper_data/container_files/conf/grouper.hibernate.properties b/demo/grouper/grouper_data/container_files/conf/grouper.hibernate.properties
new file mode 100644
index 0000000..154b8eb
--- /dev/null
+++ b/demo/grouper/grouper_data/container_files/conf/grouper.hibernate.properties
@@ -0,0 +1,29 @@
+#
+# Grouper Hibernate Configuration
+# $Id: grouper.hibernate.example.properties,v 1.9 2009-08-11 20:18:09 mchyzer Exp $
+#
+
+# The grouper hibernate config uses Grouper Configuration Overlays (documented on wiki)
+# By default the configuration is read from grouper.hibernate.base.properties
+# (which should not be edited), and the grouper.hibernate.properties overlays
+# the base settings. See the grouper.hibernate.base.properties for the possible
+# settings that can be applied to the grouper.hibernate.properties
+
+########################################
+## DB settings
+########################################
+
+# e.g. mysql: jdbc:mysql://localhost:3306/grouper
+# e.g. p6spy (log sql): [use the URL that your DB requires]
+# e.g. oracle: jdbc:oracle:thin:@server.school.edu:1521:sid
+# e.g. hsqldb (a): jdbc:hsqldb:dist/run/grouper;create=true
+# e.g. hsqldb (b): jdbc:hsqldb:hsql://localhost:9001/grouper
+# e.g. postgres: jdbc:postgresql://localhost:5432/database
+# e.g. mssql: jdbc:sqlserver://localhost:3280;databaseName=grouper
+hibernate.connection.url = jdbc:mysql://localhost:3306/grouper?CharSet=utf8&useUnicode=true&characterEncoding=utf8
+
+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 =
diff --git a/demo/grouper/grouper_data/container_files/conf/grouper.properties b/demo/grouper/grouper_data/container_files/conf/grouper.properties
new file mode 100644
index 0000000..c931287
--- /dev/null
+++ b/demo/grouper/grouper_data/container_files/conf/grouper.properties
@@ -0,0 +1,25 @@
+#
+# Grouper Configuration
+# $Id: grouper.example.properties,v 1.48 2009-12-16 06:02:30 mchyzer Exp $
+#
+
+# Grouper uses Grouper Configuration Overlays (documented on wiki)
+# By default the configuration is read from grouper.base.properties
+# (which should not be edited), and the grouper.properties overlays
+# the base settings. See the grouper.base.properties for the possible
+# settings that can be applied to the grouper.properties
+
+#if groups like the wheel group should be auto-created for convenience (note: check config needs to be on)
+configuration.autocreate.system.groups = true
+
+# A wheel group allows you to enable non-GrouperSystem subjects to act
+# like a root user when interacting with the registry.
+groups.wheel.use = true
+
+# Set to the name of the group you want to treat as the wheel group.
+# The members of this group will be treated as root-like users.
+groups.wheel.group = etc:sysadmingroup
+
+# Used to allow Include Exclude groups
+grouperIncludeExclude.use = true
+grouperIncludeExclude.requireGroups.use = true
diff --git a/demo/grouper/grouper_ui/Dockerfile b/demo/grouper/grouper_ui/Dockerfile
new file mode 100644
index 0000000..60c8015
--- /dev/null
+++ b/demo/grouper/grouper_ui/Dockerfile
@@ -0,0 +1,7 @@
+FROM tier/grouper:2.4.0-a47-u25-w5-p6-20190611
+
+LABEL author="tier-packaging@internet2.edu "
+
+#COPY in custom css, images, etc
+
+CMD ["ui"]
diff --git a/demo/grouper/grouper_ui/container_files/shibboleth/shibd.logger b/demo/grouper/grouper_ui/container_files/shibboleth/shibd.logger
new file mode 100644
index 0000000..2589b43
--- /dev/null
+++ b/demo/grouper/grouper_ui/container_files/shibboleth/shibd.logger
@@ -0,0 +1,69 @@
+# set overall behavior
+log4j.rootCategory=DEBUG, shibd_log, warn_log
+
+# fairly verbose for DEBUG, so generally leave at DEBUG
+log4j.category.XMLTooling.XMLObject=DEBUG
+log4j.category.XMLTooling.KeyInfoResolver=DEBUG
+log4j.category.Shibboleth.IPRange=DEBUG
+log4j.category.Shibboleth.PropertySet=DEBUG
+
+# raise for low-level tracing of SOAP client HTTP/SSL behavior
+log4j.category.XMLTooling.libcurl=DEBUG
+
+# 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=DEBUG, sig_log
+log4j.additivity.XMLTooling.Signature.Debugger=false
+
+# the tran log blocks the "default" appender(s) at runtime
+# Level should be left at DEBUG for this category
+log4j.category.Shibboleth-TRANSACTION=DEBUG, 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.RollingFileAppender
+log4j.appender.shibd_log.fileName=/var/log/shibboleth/shibd.log
+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=%d{%Y-%m-%d %H:%M:%S} %p %c %x: %m%n
+
+log4j.appender.warn_log=org.apache.log4j.RollingFileAppender
+log4j.appender.warn_log.fileName=/var/log/shibboleth/shibd_warn.log
+log4j.appender.warn_log.maxFileSize=1000000
+log4j.appender.warn_log.maxBackupIndex=10
+log4j.appender.warn_log.layout=org.apache.log4j.PatternLayout
+log4j.appender.warn_log.layout.ConversionPattern=%d{%Y-%m-%d %H:%M:%S} %p %c %x: %m%n
+log4j.appender.warn_log.threshold=WARN
+
+log4j.appender.tran_log=org.apache.log4j.RollingFileAppender
+log4j.appender.tran_log.fileName=/var/log/shibboleth/transaction.log
+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=%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=/var/log/shibboleth/signature.log
+log4j.appender.sig_log.layout=org.apache.log4j.PatternLayout
+log4j.appender.sig_log.layout.ConversionPattern=%m
diff --git a/demo/grouper/grouper_ws/Dockerfile b/demo/grouper/grouper_ws/Dockerfile
new file mode 100644
index 0000000..272205f
--- /dev/null
+++ b/demo/grouper/grouper_ws/Dockerfile
@@ -0,0 +1,9 @@
+FROM tier/grouper:2.4.0-a47-u25-w5-p6-20190611
+
+LABEL author="tier-packaging@internet2.edu "
+
+COPY container_files/web.xml /opt/grouper/grouper.ws/WEB-INF/
+COPY container_files/tomcat-users.xml /opt/tomcat/conf/
+COPY container_files/server.xml /opt/tomcat/conf/
+
+CMD ["ws"]
diff --git a/demo/grouper/grouper_ws/container_files/server.xml b/demo/grouper/grouper_ws/container_files/server.xml
new file mode 100644
index 0000000..112e7d0
--- /dev/null
+++ b/demo/grouper/grouper_ws/container_files/server.xml
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/grouper_ws/container_files/tomcat-users.xml b/demo/grouper/grouper_ws/container_files/tomcat-users.xml
new file mode 100644
index 0000000..f5d6945
--- /dev/null
+++ b/demo/grouper/grouper_ws/container_files/tomcat-users.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/grouper/grouper_ws/container_files/web.xml b/demo/grouper/grouper_ws/container_files/web.xml
new file mode 100644
index 0000000..03d3deb
--- /dev/null
+++ b/demo/grouper/grouper_ws/container_files/web.xml
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+ Grouper service filter
+ edu.internet2.middleware.grouper.ws.GrouperServiceJ2ee
+
+
+
+
+ Grouper logging filter
+ edu.internet2.middleware.grouper.ws.j2ee.ServletFilterLogger
+
+
+
+
+
+ Grouper service filter
+ /services/*
+
+
+ Grouper service filter
+ /servicesRest/*
+
+
+ AxisServlet
+ Apache-Axis Servlet
+ edu.internet2.middleware.grouper.ws.GrouperServiceAxisServlet
+ 1
+
+
+
+
+ RestServlet
+ WS REST Servlet
+ edu.internet2.middleware.grouper.ws.rest.GrouperRestServlet
+ 1
+
+
+ StatusServlet
+ Status Servlet
+ edu.internet2.middleware.grouper.j2ee.status.GrouperStatusServlet
+ 1
+
+
+ StatusServlet
+ /status
+
+
+ AxisServlet
+ /services/*
+
+
+ RestServlet
+ /servicesRest/*
+
+
+
+
+ Web services
+ /services/*
+
+
+ *
+
+
+
+
+
+ Web services
+ /servicesRest/*
+
+
+
+ *
+
+
+
+
+
+ BASIC
+ Grouper Application
+
+
+
+
+
+ The role that is required to log in to web service
+
+ *
+
+
+
+ 1
+
+
+
diff --git a/demo/grouper/idp/Dockerfile b/demo/grouper/idp/Dockerfile
new file mode 100644
index 0000000..0f6f508
--- /dev/null
+++ b/demo/grouper/idp/Dockerfile
@@ -0,0 +1,5 @@
+FROM tier/shib-idp
+
+LABEL author="tier-packaging@internet2.edu "
+
+COPY shibboleth-idp/ /opt/shibboleth-idp/
diff --git a/demo/grouper/idp/shibboleth-idp/conf/attribute-filter.xml b/demo/grouper/idp/shibboleth-idp/conf/attribute-filter.xml
new file mode 100644
index 0000000..21ffdb8
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/conf/attribute-filter.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/idp/shibboleth-idp/conf/attribute-resolver.xml b/demo/grouper/idp/shibboleth-idp/conf/attribute-resolver.xml
new file mode 100644
index 0000000..ee9519f
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/conf/attribute-resolver.xml
@@ -0,0 +1,293 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/grouper/idp/shibboleth-idp/conf/idp.properties b/demo/grouper/idp/shibboleth-idp/conf/idp.properties
new file mode 100644
index 0000000..4396f49
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/conf/idp.properties
@@ -0,0 +1,195 @@
+# Load any additional property resources from a comma-delimited list
+idp.additionalProperties= /conf/ldap.properties, /conf/saml-nameid.properties, /conf/services.properties
+
+# Set the entityID of the IdP
+idp.entityID= https://idptestbed/idp/shibboleth
+
+# Set the scope used in the attribute resolver for scoped attributes
+idp.scope= example.org
+
+# General cookie properties (maxAge only applies to persistent cookies)
+#idp.cookie.secure = false
+#idp.cookie.httpOnly = true
+#idp.cookie.domain =
+#idp.cookie.path =
+#idp.cookie.maxAge = 31536000
+
+# Set the location of user-supplied web flow definitions
+#idp.webflows = %{idp.home}/flows
+
+# Set the location of Velocity view templates
+#idp.views = %{idp.home}/views
+
+# Settings for internal AES encryption key
+#idp.sealer.storeType = JCEKS
+#idp.sealer.updateInterval = PT15M
+#idp.sealer.aliasBase = secret
+idp.sealer.storeResource= %{idp.home}/credentials/sealer.jks
+idp.sealer.versionResource= %{idp.home}/credentials/sealer.kver
+idp.sealer.storePassword= password
+idp.sealer.keyPassword= password
+
+# Settings for public/private signing and encryption key(s)
+# During decryption key rollover, point the ".2" properties at a second
+# keypair, uncomment in credentials.xml, then publish it in your metadata.
+idp.signing.key= %{idp.home}/credentials/idp-signing.key
+idp.signing.cert= %{idp.home}/credentials/idp-signing.crt
+idp.encryption.key= %{idp.home}/credentials/idp-encryption.key
+idp.encryption.cert= %{idp.home}/credentials/idp-encryption.crt
+#idp.encryption.key.2 = %{idp.home}/credentials/idp-encryption-old.key
+#idp.encryption.cert.2 = %{idp.home}/credentials/idp-encryption-old.crt
+
+# Sets the bean ID to use as a default security configuration set
+#idp.security.config = shibboleth.DefaultSecurityConfiguration
+
+# To default to SHA-1, set to shibboleth.SigningConfiguration.SHA1
+#idp.signing.config = shibboleth.SigningConfiguration.SHA256
+
+# Configures trust evaluation of keys used by services at runtime
+# Defaults to supporting both explicit key and PKIX using SAML metadata.
+#idp.trust.signatures = shibboleth.ChainingSignatureTrustEngine
+# To pick only one set to one of:
+# shibboleth.ExplicitKeySignatureTrustEngine, shibboleth.PKIXSignatureTrustEngine
+#idp.trust.certificates = shibboleth.ChainingX509TrustEngine
+# To pick only one set to one of:
+# shibboleth.ExplicitKeyX509TrustEngine, shibboleth.PKIXX509TrustEngine
+
+# If true, encryption will happen whenever a key to use can be located, but
+# failure to encrypt won't result in request failure.
+#idp.encryption.optional = false
+
+# Configuration of client- and server-side storage plugins
+#idp.storage.cleanupInterval = PT10M
+#idp.storage.htmlLocalStorage = false
+
+# Set to true to expose more detailed errors in responses to SPs
+#idp.errors.detailed = false
+# Set to false to skip signing of SAML response messages that signal errors
+#idp.errors.signed = true
+# Name of bean containing a list of Java exception classes to ignore
+#idp.errors.excludedExceptions = ExceptionClassListBean
+# Name of bean containing a property set mapping exception names to views
+#idp.errors.exceptionMappings = ExceptionToViewPropertyBean
+# Set if a different default view name for events and exceptions is needed
+#idp.errors.defaultView = error
+
+# Set to false to disable the IdP session layer
+#idp.session.enabled = true
+
+# Set to "shibboleth.StorageService" for server-side storage of user sessions
+#idp.session.StorageService = shibboleth.ClientSessionStorageService
+idp.session.StorageService = shibboleth.StorageService
+
+# Size of session IDs
+#idp.session.idSize = 32
+# Bind sessions to IP addresses
+#idp.session.consistentAddress = true
+# Inactivity timeout
+#idp.session.timeout = PT60M
+# Extra time to store sessions for logout
+#idp.session.slop = PT0S
+# Tolerate storage-related errors
+#idp.session.maskStorageFailure = false
+# Track information about SPs logged into
+#idp.session.trackSPSessions = false
+# Support lookup by SP for SAML logout
+#idp.session.secondaryServiceIndex = false
+# Length of time to track SP sessions
+#idp.session.defaultSPlifetime = PT2H
+
+# Regular expression matching login flows to enable, e.g. IPAddress|Password
+idp.authn.flows= Password
+
+# Regular expression of forced "initial" methods when no session exists,
+# usually in conjunction with the idp.authn.resolveAttribute property below.
+#idp.authn.flows.initial = Password
+
+# Set to an attribute ID to resolve prior to selecting authentication flows;
+# its values are used to filter the flows to allow.
+#idp.authn.resolveAttribute = eduPersonAssurance
+
+# Default lifetime and timeout of various authentication methods
+#idp.authn.defaultLifetime = PT60M
+#idp.authn.defaultTimeout = PT30M
+
+# Whether to prioritize "active" results when an SP requests more than
+# one possible matching login method (V2 behavior was to favor them)
+#idp.authn.favorSSO = true
+
+# Whether to fail requests when a user identity after authentication
+# doesn't match the identity in a pre-existing session.
+#idp.authn.identitySwitchIsError = false
+
+# Set to "shibboleth.StorageService" or custom bean for alternate storage of consent
+#idp.consent.StorageService = shibboleth.ClientPersistentStorageService
+
+# Set to "shibboleth.consent.AttributeConsentStorageKey" to use an attribute
+# to key user consent storage records (and set the attribute name)
+#idp.consent.userStorageKey = shibboleth.consent.PrincipalConsentStorageKey
+#idp.consent.userStorageKeyAttribute = uid
+
+# Flags controlling how built-in attribute consent feature operates
+#idp.consent.allowDoNotRemember = true
+#idp.consent.allowGlobal = true
+#idp.consent.allowPerAttribute = false
+
+# Whether attribute values and terms of use text are compared
+#idp.consent.compareValues = false
+# Maximum number of consent records for space-limited storage (e.g. cookies)
+#idp.consent.maxStoredRecords = 10
+# Maximum number of consent records for larger/server-side storage (0 = no limit)
+#idp.consent.expandedMaxStoredRecords = 0
+
+# Time in milliseconds to expire consent storage records.
+#idp.consent.storageRecordLifetime = P1Y
+
+# Whether to lookup metadata, etc. for every SP involved in a logout
+# for use by user interface logic; adds overhead so off by default.
+#idp.logout.elaboration = false
+
+# Whether to require logout requests be signed/authenticated.
+#idp.logout.authenticated = true
+
+# Message freshness and replay cache tuning
+#idp.policy.messageLifetime = PT3M
+#idp.policy.clockSkew = PT3M
+
+# Set to custom bean for alternate storage of replay cache
+#idp.replayCache.StorageService = shibboleth.StorageService
+
+# Toggles whether to allow outbound messages via SAML artifact
+#idp.artifact.enabled = true
+# Suppresses typical signing/encryption when artifact binding used
+#idp.artifact.secureChannel = true
+# May differ to direct SAML 2 artifact lookups to specific server nodes
+#idp.artifact.endpointIndex = 2
+# Set to custom bean for alternate storage of artifact map state
+#idp.artifact.StorageService = shibboleth.StorageService
+
+# Name of access control policy for various admin flows
+idp.status.accessPolicy= AccessByIPAddress
+idp.resolvertest.accessPolicy= AccessByIPAddress
+idp.reload.accessPolicy= AccessByIPAddress
+
+# Comma-delimited languages to use if not match can be found with the
+# browser-supported languages, defaults to an empty list.
+idp.ui.fallbackLanguages= en,fr,de
+
+# Storage service used by CAS protocol
+# Defaults to shibboleth.StorageService (in-memory)
+# MUST be server-side storage (e.g. in-memory, memcached, database)
+# NOTE that idp.session.StorageService requires server-side storage
+# when CAS protocol is enabled
+idp.cas.StorageService=shibboleth.StorageService
+
+# CAS service registry implementation class
+#idp.cas.serviceRegistryClass=net.shibboleth.idp.cas.service.PatternServiceRegistry
+
+# Profile flows in which the ProfileRequestContext should be exposed
+# in servlet request under the key "opensamlProfileRequestContext"
+#idp.profile.exposeProfileRequestContextInServletRequest = SAML2/POST/SSO,SAML2/Redirect/SSO
+
+# F-TICKS auditing - set salt to include hashed username
+#idp.fticks.federation=MyFederation
+#idp.fticks.algorithm=SHA-256
+#idp.fticks.salt=somethingsecret
diff --git a/demo/grouper/idp/shibboleth-idp/conf/ldap.properties b/demo/grouper/idp/shibboleth-idp/conf/ldap.properties
new file mode 100644
index 0000000..726f145
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/conf/ldap.properties
@@ -0,0 +1,58 @@
+# LDAP authentication configuration, see authn/ldap-authn-config.xml
+
+## Authenticator strategy, either anonSearchAuthenticator, bindSearchAuthenticator, directAuthenticator, adAuthenticator
+#idp.authn.LDAP.authenticator = anonSearchAuthenticator
+
+## Connection properties ##
+idp.authn.LDAP.ldapURL = ldap://directory:389
+idp.authn.LDAP.useStartTLS = false
+idp.authn.LDAP.useSSL = false
+#idp.authn.LDAP.connectTimeout = 3000
+
+## SSL configuration, either jvmTrust, certificateTrust, or keyStoreTrust
+#idp.authn.LDAP.sslConfig = certificateTrust
+## If using certificateTrust above, set to the trusted certificate's path
+idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldap-server.crt
+## If using keyStoreTrust above, set to the truststore path
+idp.authn.LDAP.trustStore = %{idp.home}/credentials/ldap-server.truststore
+
+## Return attributes during authentication
+## NOTE: this is not used during attribute resolution; configure that directly in the
+## attribute-resolver.xml configuration via a DataConnector's element
+idp.authn.LDAP.returnAttributes = cn,businessCategory,mail
+
+## DN resolution properties ##
+
+# Search DN resolution, used by anonSearchAuthenticator, bindSearchAuthenticator
+# for AD: CN=Users,DC=example,DC=org
+idp.authn.LDAP.baseDN = ou=people,dc=internet2,dc=edu
+#idp.authn.LDAP.subtreeSearch = false
+idp.authn.LDAP.userFilter = (uid={user})
+# bind search configuration
+# for AD: idp.authn.LDAP.bindDN=adminuser@domain.com
+idp.authn.LDAP.bindDN = cn=admin,dc=internet2,dc=edu
+idp.authn.LDAP.bindDNCredential = password
+
+# Format DN resolution, used by directAuthenticator, adAuthenticator
+# for AD use idp.authn.LDAP.dnFormat=%s@domain.com
+idp.authn.LDAP.dnFormat = uid=%s,ou=people,dc=internet2,dc=edu
+
+# LDAP attribute configuration, see attribute-resolver.xml
+idp.attribute.resolver.LDAP.ldapURL = %{idp.authn.LDAP.ldapURL}
+idp.attribute.resolver.LDAP.baseDN = %{idp.authn.LDAP.baseDN}
+idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN}
+idp.attribute.resolver.LDAP.bindDNCredential = %{idp.authn.LDAP.bindDNCredential}
+idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true}
+idp.attribute.resolver.LDAP.trustCertificates = %{idp.authn.LDAP.trustCertificates}
+idp.attribute.resolver.LDAP.searchFilter = (uid=$requestContext.principalName)
+
+# LDAP pool configuration, used for both authn and DN resolution
+#idp.pool.LDAP.minSize = 3
+#idp.pool.LDAP.maxSize = 10
+#idp.pool.LDAP.validateOnCheckout = false
+#idp.pool.LDAP.validatePeriodically = true
+#idp.pool.LDAP.validatePeriod = 300
+#idp.pool.LDAP.prunePeriod = 300
+#idp.pool.LDAP.idleTime = 600
+#idp.pool.LDAP.blockWaitTime = 3000
+#idp.pool.LDAP.failFastInitialize = false
diff --git a/demo/grouper/idp/shibboleth-idp/conf/metadata-providers.xml b/demo/grouper/idp/shibboleth-idp/conf/metadata-providers.xml
new file mode 100644
index 0000000..f70135e
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/conf/metadata-providers.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/idp/shibboleth-idp/credentials/idp-backchannel.crt b/demo/grouper/idp/shibboleth-idp/credentials/idp-backchannel.crt
new file mode 100644
index 0000000..c1f8fab
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/credentials/idp-backchannel.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAfugAwIBAgIUS9SuTXwsFVVG+LjOEAbLqqT/el0wDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMjZaFw0zNTEy
+MTEwMjIwMjZaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCMAoDHx8xCIfv/6QKqt9mcHYmEJ8y2dKprUbpdcOjH
+YvNPIl/lHPsUyrb+Nc+q2CDeiWjVk1mWYq0UpIwpBMuw1H6+oOqr4VQRi65pin0M
+SfE0MWIaFo5FPvpvoptkHD4gvREbm4swyXGMczcMRfqgalFXhUD2wz8W3XAM5Cq2
+03XeJbj6TwjvKatG5XPdeUe2FBGuOO2q54L1hcIGnLMCQrg7D31lR13PJbjnJ0No
+5C3k8TPuny6vJsBC03GNLNKfmrKVTdzr3VKp1uay1G3DL9314fgmbl8HA5iRQmy+
+XInUU6/8NXZSF59p3ITAOvZQeZsbJjg5gGDip5OZo9YlAgMBAAGjWzBZMB0GA1Ud
+DgQWBBRPlM4VkKZ0U4ec9GrIhFQl0hNbLDA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAIZ0a1ov3my3ljJG588I/PHx+TxAWONWmpKbO9c/qI3Drxk4oRIffiac
+ANxdvtabgIzrlk5gMMisD7oyqHJiWgKv5Bgctd8w3IS3lLl7wHX65mTKQRXniG98
+NIjkvfrhe2eeJxecOqnDI8GOhIGCIqZUn8ShdM/yHjhQ2Mh0Hj3U0LlKvnmfGSQl
+j0viGwbFCaNaIP3zc5UmCrdE5h8sWL3Fu7ILKM9RyFa2ILHrJScV9t623IcHffHP
+IeaY/WtuapsrqRFxuQL9QFWN0FsRIdLmjTq+00+B/XnnKRKFBuWfjhHLF/uu8f+E
+t6Lf23Kb8yD6ZR7dihMZAGHnYQ/hlhM=
+-----END CERTIFICATE-----
diff --git a/demo/grouper/idp/shibboleth-idp/credentials/idp-backchannel.p12 b/demo/grouper/idp/shibboleth-idp/credentials/idp-backchannel.p12
new file mode 100644
index 0000000..112540a
Binary files /dev/null and b/demo/grouper/idp/shibboleth-idp/credentials/idp-backchannel.p12 differ
diff --git a/demo/grouper/idp/shibboleth-idp/credentials/idp-browser.p12 b/demo/grouper/idp/shibboleth-idp/credentials/idp-browser.p12
new file mode 100644
index 0000000..032be0b
Binary files /dev/null and b/demo/grouper/idp/shibboleth-idp/credentials/idp-browser.p12 differ
diff --git a/demo/grouper/idp/shibboleth-idp/credentials/idp-encryption.crt b/demo/grouper/idp/shibboleth-idp/credentials/idp-encryption.crt
new file mode 100644
index 0000000..15d764f
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/credentials/idp-encryption.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAfugAwIBAgIUG6Nn1rlERS1vsi88tcdzSYX0oqAwDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMTRaFw0zNTEy
+MTEwMjIwMTRaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCBXv0o3fmT8iluyLjJ4lBAVCW+ZRVyEXPYQuRi7vfD
+cO4a6d1kxiJLsaK0W88VNxjFQRr8PgDkWr28vwoH1rgk4pLsszLD48DBzD942peJ
+l/S6FnsIJjmaHcBh4pbNhU4yowu63iKkvttrcZAEbpEro6Z8CziWEx8sywoaYEQG
+ifPkr9ORV6Cn3txq+9gMBePG41GrtZrUGIu+xrndL0Shh4Pq0eq/9MAsVlIIXEa8
+9WfH8J2kFcTOfoWtIc70b7TLZQsx4YnNcnrGLSUEcstFyPLX+Xtv5SNZF89OOIxX
+VNjNvgE5DbJb9hMM4UAFqI+1bo9QqtxwThjc/sOvIxzNAgMBAAGjWzBZMB0GA1Ud
+DgQWBBStTyogRPuAVG6q7yPyav1uvE+7pTA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAFMfoOv+oISGjvamq7+Y4G7ep5vxlAPeK3RATYPYvAmyH946qZXh98ni
+QXyuqZW5P5eEt86toY45IwDU5r09SKwHughEe99iiEkxh0mb2qo84qX9/qcg+kyN
+jeLd/OSyolpUCEFNwOFcog7pj7Eer+6AHbwTn1Mjb5TBsKwtDMJsaxPvdj0u7M5r
+xL/wHkFhn1rCo2QiojzjSlV3yLTh49iTyhE3cG+RxaNKDCxhp0jSSLX1BW/ZoPA8
++PMJEA+Q0QbyRD8aJOHN5O8jGxCa/ZzcOnYVL6AsEXoDiY3vAUYh1FUonOWw0m9H
+p+tGUbGS2l873J5PrsbpeKEVR/IIoKo=
+-----END CERTIFICATE-----
diff --git a/demo/grouper/idp/shibboleth-idp/credentials/idp-encryption.key b/demo/grouper/idp/shibboleth-idp/credentials/idp-encryption.key
new file mode 100644
index 0000000..8bb5cc6
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/credentials/idp-encryption.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAgV79KN35k/Ipbsi4yeJQQFQlvmUVchFz2ELkYu73w3DuGund
+ZMYiS7GitFvPFTcYxUEa/D4A5Fq9vL8KB9a4JOKS7LMyw+PAwcw/eNqXiZf0uhZ7
+CCY5mh3AYeKWzYVOMqMLut4ipL7ba3GQBG6RK6OmfAs4lhMfLMsKGmBEBonz5K/T
+kVegp97cavvYDAXjxuNRq7Wa1BiLvsa53S9EoYeD6tHqv/TALFZSCFxGvPVnx/Cd
+pBXEzn6FrSHO9G+0y2ULMeGJzXJ6xi0lBHLLRcjy1/l7b+UjWRfPTjiMV1TYzb4B
+OQ2yW/YTDOFABaiPtW6PUKrccE4Y3P7DryMczQIDAQABAoIBAF/IflMllcUtw/Nb
+9USzpIscQh2nJaugtE5nqER/fT1cfU273Mjh0T6NtFMorjec5WAWBe6/0VVAwb3f
+C4QmO4xDnFhXjLxwAaT6nfvSi+O5d93XCxxLgNZUNL3ET7a2feELyoF+OdQT4sy3
+9dLyMdVHgtnQTQMAAVLeuQoyP+s+Zax4Gca6ln8QxIIvDoD7NITnpl8887Hghhzl
+CvKtRiPRtoI2JTXWgWuLI6xXfVsDvFT+Up+ki9TMLWLACcmMU1d+lUBOKIqhhQHG
++np9iKxVausJwYaLwwT3h8SItNon7ltbV6kcqyZxMAA+uN8CVgIb5UaUrlW7Nvze
+1iUNudkCgYEAxpnBg8YxdEHFSMTqjEOYapn18cs3n32EBPtvPaUcvw3mGC1+ZVx1
+9WqnVsgykBOWI0qSBVF7Kke8yOqgqWtYQUFqLiMgCC9e/QcXnrm/bzAmKDgLVcCR
+KzgqU2ECQDkNSS0qeODjLGX4SEabDbLhN59WykHKM0i/RcrbhuvT1BcCgYEApsMD
+TFQBaiaEmLVm252piZf8b5g3DrUHeqGktHkHXTW4Iyyn8zEknoiCosk/Tej73zga
+cTT3zQgEh63DMC9Ag8IbIJiDpYLMkt1QvZYtq95E/94GVEfRRok6/pyagGYB351R
+PXcykrDyy26FSofmtaXU37Wxaj3ow+WROaPgULsCgYEArFoFScG3a2gkuRlDX8TN
+wj2o5lTxCbWY2+YEzR+8icWbGQJqPbb3G6uaW8LTtpt44Vm2zWzAEZo+KLMOCNmC
+tub5Kd8Lzm6l5brA8dvLWcgUZTT2CU5b7YEJomB+3pNkh0vuHwczv3Ui+j5kE4hY
+0bezT0W3H7iTXhNFXprMs7MCgYEAlIZn75l6URLRUjluzPdVQoktei72CpFNgflp
++ps45dmskRd61mzUkqY+w8G+MiPqANu1IVLtyZz0e+tVRxsuuKsvAg8UYVtn3P5k
+pRaWwtaKWeFjfbkhOVOMSa0tJmK0FHfHHZmGX4ReGrXq3YDBCNQUDtOCmn9dSuyy
+NcYxSXUCgYB+yo6dg8nyHDSqKDdrQQiAKv7jNsbecQ/rYrt8l0n9FBiwn5R7v6kp
+afsimCVou5i06L2Cr5Xs+XSf11KVkDh+qM70ZFubWEsHCDrS1KrxUzfFbrQczKof
+qX7ZsBuOT72RwVEa8fpT6IZ6IpOOEPmUid/f2VM2aAcXgaF//vMjxA==
+-----END RSA PRIVATE KEY-----
diff --git a/demo/grouper/idp/shibboleth-idp/credentials/idp-signing.crt b/demo/grouper/idp/shibboleth-idp/credentials/idp-signing.crt
new file mode 100644
index 0000000..6a032c1
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/credentials/idp-signing.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDFDCCAfygAwIBAgIVAN3vv+b7KN5Se9m1RZsCllp/B/hdMA0GCSqGSIb3DQEB
+CwUAMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwHhcNMTUxMjExMDIyMDE0WhcNMzUx
+MjExMDIyMDE0WjAVMRMwEQYDVQQDDAppZHB0ZXN0YmVkMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAh91caeY0Q85uhaUyqFwP2bMjwMFxMzRlAoqBHd7g
+u6eo4duaeLz1BaoR2XTBpNNvFR5oHH+TkKahVDGeH5+kcnIpxI8JPdsZml1srvf2
+Z6dzJsulJZUdpqnngycTkGtZgEoC1vmYVky2BSAIIifmdh6s0epbHnMGLsHzMKfJ
+Cb/Q6dYzRWTCPtzE2VMuQqqWgeyMr7u14x/Vqr9RPEFsgY8GIu5jzB6AyUIwrLg+
+MNkv6aIdcHwxYTGL7ijfy6rSWrgBflQoYRYNEnseK0ZHgJahz4ovCag6wZAoPpBs
+uYlY7lEr89Ucb6NHx3uqGMsXlDFdE4QwfDLLhCYHPvJ0uwIDAQABo1swWTAdBgNV
+HQ4EFgQUAkOgED3iYdmvQEOMm6u/JmD/UTQwOAYDVR0RBDEwL4IKaWRwdGVzdGJl
+ZIYhaHR0cHM6Ly9pZHB0ZXN0YmVkL2lkcC9zaGliYm9sZXRoMA0GCSqGSIb3DQEB
+CwUAA4IBAQBIdd4YWlnvJjql8+zKKgmWgIY7U8DA8e6QcbAf8f8cdE33RSnjI63X
+sv/y9GfmbAVAD6RIAXPFFeRYJ08GOxGI9axfNaKdlsklJ9bk4ducHqgCSWYVer3s
+RQBjxyOfSTvk9YCJvdJVQRJLcCvxwKakFCsOSnV3t9OvN86Ak+fKPVB5j2fM/0fZ
+Kqjn3iqgdNPTLXPsuJLJO5lITRiBa4onmVelAiCstI9PQiaEck+oAHnMTnC9JE/B
+DHv3e4rwq3LznlqPw0GSd7xqNTdMDwNOWjkuOr3sGpWS8ms/ZHHXV1Vd22uPe70i
+s00xrv14zLifcc8oj5DYzOhYRifRXgHX
+-----END CERTIFICATE-----
diff --git a/demo/grouper/idp/shibboleth-idp/credentials/idp-signing.key b/demo/grouper/idp/shibboleth-idp/credentials/idp-signing.key
new file mode 100644
index 0000000..011c27c
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/credentials/idp-signing.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAh91caeY0Q85uhaUyqFwP2bMjwMFxMzRlAoqBHd7gu6eo4dua
+eLz1BaoR2XTBpNNvFR5oHH+TkKahVDGeH5+kcnIpxI8JPdsZml1srvf2Z6dzJsul
+JZUdpqnngycTkGtZgEoC1vmYVky2BSAIIifmdh6s0epbHnMGLsHzMKfJCb/Q6dYz
+RWTCPtzE2VMuQqqWgeyMr7u14x/Vqr9RPEFsgY8GIu5jzB6AyUIwrLg+MNkv6aId
+cHwxYTGL7ijfy6rSWrgBflQoYRYNEnseK0ZHgJahz4ovCag6wZAoPpBsuYlY7lEr
+89Ucb6NHx3uqGMsXlDFdE4QwfDLLhCYHPvJ0uwIDAQABAoIBAGpInLarQ0+X+ZXK
++aoC+tNO9DUiHq/z2OD4ALGhXSTvr4mgBWNWTkc0F+qJD8MlM8zNkJxaoNGTyLjY
+Z95NQJPXAx2k15HwCENdulvV1oiX0dkTjgmscRmj6FwNAZ0EnWtien45mxZHxEyW
+FkbB9+OHc6JzNvzG9ps1Vk1FtFtO8w4exXuJVATJeArQmMvAUHMJYPb7Qs+/NX9R
+RlDvFfXDzQv5eAzudT1SyFSa5W+Bsw6BtEoeiqdp+xQh4yc733nwN7KG2Z/TpGse
+jVe6akbULuCXOe9uPa7kv8hnQEUH38QVlIw8pK1SsgNq7S0U44WU5uF8gbDBYle/
+OoPBvSECgYEAvCwVEa8ryLzee5FaX4PBxk10lEl/Yp9jC88wPUQ+ZpfniIIQIfwl
+csRE9D3/dJOVAxw/Ac32F72SLVDzLabAhlBRINYLB0ZkVuJi1CIoDHIf9nfh/pOx
+b96VMUe/mpAL4hZnZkmBKjesX5URPEKtBD0aSeCw9aFqhORjRrxCJg0CgYEAuNaD
+LOuTPKsC6nxRtiL9r0CA5gCCdpALxwJA7wHAeh03i5xmy61i4iOMaunxKZhG+nzz
+PhcI8Uhwwk+l3tbYAf1rrtmMKNcyjy+UqWXGt4ZkWFlIyIungyLiH9L32IMhXNF0
+fBgOZNtFTmQBU18a78uIir9xASUbtaakzOtJ2+cCgYAgfawVpZ11x8bSp0Jng6SN
+zQn4IMiyCrtbaqb1rTbpGAmOdIa8l4EP0/vkAGB/jIwKQXJPqXR4nO8EjBmxJD3R
+80RO2yaEVw80QVq3Lj6kB4ClWgXXo0DcBB7Wp4DZ+01R+HRaIQ8AbySATIjxUsH1
+HWfQoc9sWja+Q4Ew0YjKcQKBgGLoPsdBw8b6B5RsM9lPvgoSbScmbKl/CR5TwWVj
+vZhanAd0CLnCrSAvP4tSZf8JAio1xH+cGefrCJOhxTOKKYpfDklBFjQge2iNYHKJ
+CJ3aJ0XzePP/bwLIHtJCtOdBvA+L8VYaFVG418xLzT3MrYBVnFoKeTDQp5Q7eQJC
+gYJPAoGBAKHcuXWzvXoHKnOg8Ljg2xZ6/SfjwNDIIrpXVTAQifmK3q4+Ua2Q+Cjq
+97tPMxF2bVRcbnCSNKpTMOTrsWs8Z3GpMyCh6XgYMSlclXusDVUkRkPpWj8hVTR4
+opm/rxS83hCrTsIX3Il3T8Fpb97kdF+unCiWEaxrPEurjW8lB506
+-----END RSA PRIVATE KEY-----
diff --git a/demo/grouper/idp/shibboleth-idp/credentials/sealer.jks b/demo/grouper/idp/shibboleth-idp/credentials/sealer.jks
new file mode 100644
index 0000000..89957e0
Binary files /dev/null and b/demo/grouper/idp/shibboleth-idp/credentials/sealer.jks differ
diff --git a/demo/grouper/idp/shibboleth-idp/credentials/sealer.kver b/demo/grouper/idp/shibboleth-idp/credentials/sealer.kver
new file mode 100644
index 0000000..d64b0e4
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/credentials/sealer.kver
@@ -0,0 +1,2 @@
+#Fri Dec 11 02:20:32 UTC 2015
+CurrentVersion=1
diff --git a/demo/grouper/idp/shibboleth-idp/metadata/grouper-sp.xml b/demo/grouper/idp/shibboleth-idp/metadata/grouper-sp.xml
new file mode 100644
index 0000000..5b42a7b
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/metadata/grouper-sp.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ sp.example.org
+
+ CN=sp.example.org,O=Internet2/TIER,L=Ann Arbor,ST=MI,C=US
+ MIIDPDCCAiQCCQDNZe8r0hVtuTANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJV
+UzELMAkGA1UECAwCTUkxEjAQBgNVBAcMCUFubiBBcmJvcjEXMBUGA1UECgwOSW50
+ZXJuZXQyL1RJRVIxFzAVBgNVBAMMDnNwLmV4YW1wbGUub3JnMB4XDTE3MDkyMjE5
+NTAzNVoXDTI3MDkyMDE5NTAzNVowYDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1J
+MRIwEAYDVQQHDAlBbm4gQXJib3IxFzAVBgNVBAoMDkludGVybmV0Mi9USUVSMRcw
+FQYDVQQDDA5zcC5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAMTNJmsNpTpR4NrDJwOgK/o3UYlNdi1c6xBflt+liLAsQc160QReV4dS
+SGK8LZvN58a/BTIsH8dLhQlUQ8qQUY2AfolVrNxb7Waumeh/POzYUTRylnoGpU3W
+bGMEPxE/AdgP5U/adYvyu4XI5epv7wjZJOTqcVag15SalY+aso+ZC/5l+UzRxmWB
+ZxKTsSL1y7PFehY4/Zl3Y3oGVsVl/zspt5lteoZQeeVxUX29S3Af11yHY4xpEp+7
+rvAzY/nlsTiHAsUoCFK/NFQ2evvSRx52B9Fk1cWP1MDVDm2QjQqD9xBGYSnX6bhQ
+ejVx7JUJHlblu2Q5p5XdW0BihgFluoECAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
+n/qhYnIviPs4tglCdrw+M7gbqKNWadDC3F9HDYzlJMFeS/ae2turhEUgQPbYPDQQ
+eO3oOILtvCXNFUPM58jf8V5YFRrOqrTgx44kexQDaHO5YYNft5tF5TdvBYE2gOVr
+GdYrH2iSP8WX+Yy7JH5uqkfwWzEntWHJdey39rCWKAUCCB35+/2b4N53Qmlv2+ug
+CpNJYFtXInd4YMmM5HjXLyoWXtjnKiwDqYUCeYPSwAajnCqRqRXUX0gYTFDRiwRP
+HbmO9We0nqoc/71nikmGGoSRMO/zWVMFjwmAx1fGiWdU61sjGX8sHifzmVyJVEBI
+Z75p+JrWYZJYrx/vpWxL8g==
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/idp/shibboleth-idp/metadata/idp-metadata.xml b/demo/grouper/idp/shibboleth-idp/metadata/idp-metadata.xml
new file mode 100644
index 0000000..84266d4
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/metadata/idp-metadata.xml
@@ -0,0 +1,206 @@
+
+
+
+
+
+
+
+ example.org
+
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUS9SuTXwsFVVG+LjOEAbLqqT/el0wDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMjZaFw0zNTEy
+MTEwMjIwMjZaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCMAoDHx8xCIfv/6QKqt9mcHYmEJ8y2dKprUbpdcOjH
+YvNPIl/lHPsUyrb+Nc+q2CDeiWjVk1mWYq0UpIwpBMuw1H6+oOqr4VQRi65pin0M
+SfE0MWIaFo5FPvpvoptkHD4gvREbm4swyXGMczcMRfqgalFXhUD2wz8W3XAM5Cq2
+03XeJbj6TwjvKatG5XPdeUe2FBGuOO2q54L1hcIGnLMCQrg7D31lR13PJbjnJ0No
+5C3k8TPuny6vJsBC03GNLNKfmrKVTdzr3VKp1uay1G3DL9314fgmbl8HA5iRQmy+
+XInUU6/8NXZSF59p3ITAOvZQeZsbJjg5gGDip5OZo9YlAgMBAAGjWzBZMB0GA1Ud
+DgQWBBRPlM4VkKZ0U4ec9GrIhFQl0hNbLDA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAIZ0a1ov3my3ljJG588I/PHx+TxAWONWmpKbO9c/qI3Drxk4oRIffiac
+ANxdvtabgIzrlk5gMMisD7oyqHJiWgKv5Bgctd8w3IS3lLl7wHX65mTKQRXniG98
+NIjkvfrhe2eeJxecOqnDI8GOhIGCIqZUn8ShdM/yHjhQ2Mh0Hj3U0LlKvnmfGSQl
+j0viGwbFCaNaIP3zc5UmCrdE5h8sWL3Fu7ILKM9RyFa2ILHrJScV9t623IcHffHP
+IeaY/WtuapsrqRFxuQL9QFWN0FsRIdLmjTq+00+B/XnnKRKFBuWfjhHLF/uu8f+E
+t6Lf23Kb8yD6ZR7dihMZAGHnYQ/hlhM=
+
+
+
+
+
+
+
+
+
+MIIDFDCCAfygAwIBAgIVAN3vv+b7KN5Se9m1RZsCllp/B/hdMA0GCSqGSIb3DQEB
+CwUAMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwHhcNMTUxMjExMDIyMDE0WhcNMzUx
+MjExMDIyMDE0WjAVMRMwEQYDVQQDDAppZHB0ZXN0YmVkMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAh91caeY0Q85uhaUyqFwP2bMjwMFxMzRlAoqBHd7g
+u6eo4duaeLz1BaoR2XTBpNNvFR5oHH+TkKahVDGeH5+kcnIpxI8JPdsZml1srvf2
+Z6dzJsulJZUdpqnngycTkGtZgEoC1vmYVky2BSAIIifmdh6s0epbHnMGLsHzMKfJ
+Cb/Q6dYzRWTCPtzE2VMuQqqWgeyMr7u14x/Vqr9RPEFsgY8GIu5jzB6AyUIwrLg+
+MNkv6aIdcHwxYTGL7ijfy6rSWrgBflQoYRYNEnseK0ZHgJahz4ovCag6wZAoPpBs
+uYlY7lEr89Ucb6NHx3uqGMsXlDFdE4QwfDLLhCYHPvJ0uwIDAQABo1swWTAdBgNV
+HQ4EFgQUAkOgED3iYdmvQEOMm6u/JmD/UTQwOAYDVR0RBDEwL4IKaWRwdGVzdGJl
+ZIYhaHR0cHM6Ly9pZHB0ZXN0YmVkL2lkcC9zaGliYm9sZXRoMA0GCSqGSIb3DQEB
+CwUAA4IBAQBIdd4YWlnvJjql8+zKKgmWgIY7U8DA8e6QcbAf8f8cdE33RSnjI63X
+sv/y9GfmbAVAD6RIAXPFFeRYJ08GOxGI9axfNaKdlsklJ9bk4ducHqgCSWYVer3s
+RQBjxyOfSTvk9YCJvdJVQRJLcCvxwKakFCsOSnV3t9OvN86Ak+fKPVB5j2fM/0fZ
+Kqjn3iqgdNPTLXPsuJLJO5lITRiBa4onmVelAiCstI9PQiaEck+oAHnMTnC9JE/B
+DHv3e4rwq3LznlqPw0GSd7xqNTdMDwNOWjkuOr3sGpWS8ms/ZHHXV1Vd22uPe70i
+s00xrv14zLifcc8oj5DYzOhYRifRXgHX
+
+
+
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUG6Nn1rlERS1vsi88tcdzSYX0oqAwDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMTRaFw0zNTEy
+MTEwMjIwMTRaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCBXv0o3fmT8iluyLjJ4lBAVCW+ZRVyEXPYQuRi7vfD
+cO4a6d1kxiJLsaK0W88VNxjFQRr8PgDkWr28vwoH1rgk4pLsszLD48DBzD942peJ
+l/S6FnsIJjmaHcBh4pbNhU4yowu63iKkvttrcZAEbpEro6Z8CziWEx8sywoaYEQG
+ifPkr9ORV6Cn3txq+9gMBePG41GrtZrUGIu+xrndL0Shh4Pq0eq/9MAsVlIIXEa8
+9WfH8J2kFcTOfoWtIc70b7TLZQsx4YnNcnrGLSUEcstFyPLX+Xtv5SNZF89OOIxX
+VNjNvgE5DbJb9hMM4UAFqI+1bo9QqtxwThjc/sOvIxzNAgMBAAGjWzBZMB0GA1Ud
+DgQWBBStTyogRPuAVG6q7yPyav1uvE+7pTA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAFMfoOv+oISGjvamq7+Y4G7ep5vxlAPeK3RATYPYvAmyH946qZXh98ni
+QXyuqZW5P5eEt86toY45IwDU5r09SKwHughEe99iiEkxh0mb2qo84qX9/qcg+kyN
+jeLd/OSyolpUCEFNwOFcog7pj7Eer+6AHbwTn1Mjb5TBsKwtDMJsaxPvdj0u7M5r
+xL/wHkFhn1rCo2QiojzjSlV3yLTh49iTyhE3cG+RxaNKDCxhp0jSSLX1BW/ZoPA8
++PMJEA+Q0QbyRD8aJOHN5O8jGxCa/ZzcOnYVL6AsEXoDiY3vAUYh1FUonOWw0m9H
+p+tGUbGS2l873J5PrsbpeKEVR/IIoKo=
+
+
+
+
+
+
+ urn:mace:shibboleth:1.0:nameIdentifier
+ urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+
+
+
+
+
+
+
+
+
+
+
+
+ localhost
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUS9SuTXwsFVVG+LjOEAbLqqT/el0wDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMjZaFw0zNTEy
+MTEwMjIwMjZaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCMAoDHx8xCIfv/6QKqt9mcHYmEJ8y2dKprUbpdcOjH
+YvNPIl/lHPsUyrb+Nc+q2CDeiWjVk1mWYq0UpIwpBMuw1H6+oOqr4VQRi65pin0M
+SfE0MWIaFo5FPvpvoptkHD4gvREbm4swyXGMczcMRfqgalFXhUD2wz8W3XAM5Cq2
+03XeJbj6TwjvKatG5XPdeUe2FBGuOO2q54L1hcIGnLMCQrg7D31lR13PJbjnJ0No
+5C3k8TPuny6vJsBC03GNLNKfmrKVTdzr3VKp1uay1G3DL9314fgmbl8HA5iRQmy+
+XInUU6/8NXZSF59p3ITAOvZQeZsbJjg5gGDip5OZo9YlAgMBAAGjWzBZMB0GA1Ud
+DgQWBBRPlM4VkKZ0U4ec9GrIhFQl0hNbLDA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAIZ0a1ov3my3ljJG588I/PHx+TxAWONWmpKbO9c/qI3Drxk4oRIffiac
+ANxdvtabgIzrlk5gMMisD7oyqHJiWgKv5Bgctd8w3IS3lLl7wHX65mTKQRXniG98
+NIjkvfrhe2eeJxecOqnDI8GOhIGCIqZUn8ShdM/yHjhQ2Mh0Hj3U0LlKvnmfGSQl
+j0viGwbFCaNaIP3zc5UmCrdE5h8sWL3Fu7ILKM9RyFa2ILHrJScV9t623IcHffHP
+IeaY/WtuapsrqRFxuQL9QFWN0FsRIdLmjTq+00+B/XnnKRKFBuWfjhHLF/uu8f+E
+t6Lf23Kb8yD6ZR7dihMZAGHnYQ/hlhM=
+
+
+
+
+
+
+
+
+
+MIIDFDCCAfygAwIBAgIVAN3vv+b7KN5Se9m1RZsCllp/B/hdMA0GCSqGSIb3DQEB
+CwUAMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwHhcNMTUxMjExMDIyMDE0WhcNMzUx
+MjExMDIyMDE0WjAVMRMwEQYDVQQDDAppZHB0ZXN0YmVkMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAh91caeY0Q85uhaUyqFwP2bMjwMFxMzRlAoqBHd7g
+u6eo4duaeLz1BaoR2XTBpNNvFR5oHH+TkKahVDGeH5+kcnIpxI8JPdsZml1srvf2
+Z6dzJsulJZUdpqnngycTkGtZgEoC1vmYVky2BSAIIifmdh6s0epbHnMGLsHzMKfJ
+Cb/Q6dYzRWTCPtzE2VMuQqqWgeyMr7u14x/Vqr9RPEFsgY8GIu5jzB6AyUIwrLg+
+MNkv6aIdcHwxYTGL7ijfy6rSWrgBflQoYRYNEnseK0ZHgJahz4ovCag6wZAoPpBs
+uYlY7lEr89Ucb6NHx3uqGMsXlDFdE4QwfDLLhCYHPvJ0uwIDAQABo1swWTAdBgNV
+HQ4EFgQUAkOgED3iYdmvQEOMm6u/JmD/UTQwOAYDVR0RBDEwL4IKaWRwdGVzdGJl
+ZIYhaHR0cHM6Ly9pZHB0ZXN0YmVkL2lkcC9zaGliYm9sZXRoMA0GCSqGSIb3DQEB
+CwUAA4IBAQBIdd4YWlnvJjql8+zKKgmWgIY7U8DA8e6QcbAf8f8cdE33RSnjI63X
+sv/y9GfmbAVAD6RIAXPFFeRYJ08GOxGI9axfNaKdlsklJ9bk4ducHqgCSWYVer3s
+RQBjxyOfSTvk9YCJvdJVQRJLcCvxwKakFCsOSnV3t9OvN86Ak+fKPVB5j2fM/0fZ
+Kqjn3iqgdNPTLXPsuJLJO5lITRiBa4onmVelAiCstI9PQiaEck+oAHnMTnC9JE/B
+DHv3e4rwq3LznlqPw0GSd7xqNTdMDwNOWjkuOr3sGpWS8ms/ZHHXV1Vd22uPe70i
+s00xrv14zLifcc8oj5DYzOhYRifRXgHX
+
+
+
+
+
+
+
+
+
+MIIDEzCCAfugAwIBAgIUG6Nn1rlERS1vsi88tcdzSYX0oqAwDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKaWRwdGVzdGJlZDAeFw0xNTEyMTEwMjIwMTRaFw0zNTEy
+MTEwMjIwMTRaMBUxEzARBgNVBAMMCmlkcHRlc3RiZWQwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCBXv0o3fmT8iluyLjJ4lBAVCW+ZRVyEXPYQuRi7vfD
+cO4a6d1kxiJLsaK0W88VNxjFQRr8PgDkWr28vwoH1rgk4pLsszLD48DBzD942peJ
+l/S6FnsIJjmaHcBh4pbNhU4yowu63iKkvttrcZAEbpEro6Z8CziWEx8sywoaYEQG
+ifPkr9ORV6Cn3txq+9gMBePG41GrtZrUGIu+xrndL0Shh4Pq0eq/9MAsVlIIXEa8
+9WfH8J2kFcTOfoWtIc70b7TLZQsx4YnNcnrGLSUEcstFyPLX+Xtv5SNZF89OOIxX
+VNjNvgE5DbJb9hMM4UAFqI+1bo9QqtxwThjc/sOvIxzNAgMBAAGjWzBZMB0GA1Ud
+DgQWBBStTyogRPuAVG6q7yPyav1uvE+7pTA4BgNVHREEMTAvggppZHB0ZXN0YmVk
+hiFodHRwczovL2lkcHRlc3RiZWQvaWRwL3NoaWJib2xldGgwDQYJKoZIhvcNAQEL
+BQADggEBAFMfoOv+oISGjvamq7+Y4G7ep5vxlAPeK3RATYPYvAmyH946qZXh98ni
+QXyuqZW5P5eEt86toY45IwDU5r09SKwHughEe99iiEkxh0mb2qo84qX9/qcg+kyN
+jeLd/OSyolpUCEFNwOFcog7pj7Eer+6AHbwTn1Mjb5TBsKwtDMJsaxPvdj0u7M5r
+xL/wHkFhn1rCo2QiojzjSlV3yLTh49iTyhE3cG+RxaNKDCxhp0jSSLX1BW/ZoPA8
++PMJEA+Q0QbyRD8aJOHN5O8jGxCa/ZzcOnYVL6AsEXoDiY3vAUYh1FUonOWw0m9H
+p+tGUbGS2l873J5PrsbpeKEVR/IIoKo=
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/idp/shibboleth-idp/metadata/midpoint-sp-new.xml b/demo/grouper/idp/shibboleth-idp/metadata/midpoint-sp-new.xml
new file mode 100644
index 0000000..a819f4b
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/metadata/midpoint-sp-new.xml
@@ -0,0 +1,37 @@
+
+
+
+ midpointdemo
+
+
+
+
+
+MIIDHDCCAgSgAwIBAgIJAPEnL5jgbeVoMA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV
+BAMMD2lkcC5leGFtcGxlLmVkdTAeFw0xODEwMTAyMDM1NDBaFw0yMzEwMDkyMDM1
+NDBaMBoxGDAWBgNVBAMMD2lkcC5leGFtcGxlLmVkdTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAKwTrvQhmFX3SUNgJAhQ/YV0UX56Rt53mwbiKuH+Ez83
+7z6XRynBVsfzHfbWe0IpNKx5mIr84dfbGhQKQBEKzQuek7ihW3J6PIVZN1A3icZZ
+B9i7gow902bT0ZfRG8QW49gl7pk3ASutPcO9Dq5Xc/AqWr3OSO/Pei0yBtTdzG3b
+rm0u0gbj3P2tjt7BN77wIB+yjJsND3ITtP0MFXIJxLTlty8thwqQOAOAYcF+rhC5
+znnBLsRNo0E57PtzZs8i/BpEX2uPTxpEyvlU1vtyxcKUiHtK5ZjOsDEkS2rEualr
++FILYg/Oxw1gi0+mNO1a94Ft+UoLiREztq6MQt8OK98CAwEAAaNlMGMwQgYDVR0R
+BDswOYIPaWRwLmV4YW1wbGUuZWR1hiZodHRwczovL2lkcC5leGFtcGxlLmVkdS9p
+ZHAvc2hpYmJvbGV0aDAdBgNVHQ4EFgQU3ZJ8oHkmlgPtZuZAxnzONccPsb8wDQYJ
+KoZIhvcNAQELBQADggEBAIJ4oZKSMGpF8J3qdfjLZGkc3iVbu/eiE1MD77no0oCz
+nelY0CNUBuFJk1Xv+Bv0fW0cVugtMPz4xi7zv0zkpS2IVxpPZWBosuVabUD9k+V4
+iN5woJdO7e2KRGvhlWmbkmoZUvhygDe0u0vblNfLzDwFQvxHXiWG//P7SanoQrjP
+dE8U21tYz+EFm6s5TvHxVhr9id8c+UacAFCpAtzUB+J8K1abx05XlKsySflkOQV9
+JbM4zOy5gXSI5dY9dGUF77g0muyC+jAhIhLSt/7v3vJgvBurrxPoeBFXOU3D+siT
+VZlKtYzYjJhVqXx1vKrWEE1hkpqm+iYgZe4MvgcdswY=
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/idp/shibboleth-idp/metadata/midpoint-sp.xml b/demo/grouper/idp/shibboleth-idp/metadata/midpoint-sp.xml
new file mode 100644
index 0000000..54f0577
--- /dev/null
+++ b/demo/grouper/idp/shibboleth-idp/metadata/midpoint-sp.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ midpoint.sp.example.org
+
+ CN=midpoint.sp.example.org,O=Internet2/TIER,L=Ann Arbor,ST=MI,C=US
+ MIIDqDCCApCgAwIBAgIJAKUZrfriIt9cMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJNSTESMBAGA1UEBwwJQW5uIEFyYm9yMRcwFQYDVQQK
+DA5JbnRlcm5ldDIvVElFUjEgMB4GA1UEAwwXZXZvbHZldW0uc3AuZXhhbXBsZS5v
+cmcwHhcNMTgwOTE0MDU0NjU3WhcNMTkwOTE0MDU0NjU3WjBpMQswCQYDVQQGEwJV
+UzELMAkGA1UECAwCTUkxEjAQBgNVBAcMCUFubiBBcmJvcjEXMBUGA1UECgwOSW50
+ZXJuZXQyL1RJRVIxIDAeBgNVBAMMF2V2b2x2ZXVtLnNwLmV4YW1wbGUub3JnMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw5v1zxlM94yaBssgNNbIUJwW
+XxbGxgSs2AWBeg2aEi/VQd2UE5ivZakNJlqWSJyHo2xE4kxeSyBBxinjSyhmpNao
+xIcqQsgW0gxo4SEHo3kUXWPo+of/pj6CslutsSJZWGTRV0dHITvaWX+NM8eXMfgu
+mJFwy3RMdLaWQhY1Dyi2jNoO+DZnfNgPyPeEZcmORaoeEID9QdZfHtcgTf2QfSHq
++xsTwHB6Ro5t7YD2ma8Krb/XcDTfsq3qJemd7LhPj5lGmhYSMgDbgwEkZgZ1kBOP
+lfsP2BvX5nipv7Vd1C5YXmv+NDR8V3yAWBC7ZAenxGmrnkaSVXnpUplUsGGm1QID
+AQABo1MwUTAdBgNVHQ4EFgQUuxSZwW6V1P/b0tsTM32OU/v/n+UwHwYDVR0jBBgw
+FoAUuxSZwW6V1P/b0tsTM32OU/v/n+UwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQsFAAOCAQEAJWLXEfZkPeUyiGvsIUjczzdF3ptqXoP9aETS2pOV9sTri19R
+TsQZW6XQRHGtuEOsqEGH8yiTdGR5hbGC+ynH/xTJnK+tBn/R3KrgxLKyMvoUzAPl
+mhVq1dh+ZEtbsRpQRRubP6nm9kXNma0cXrkJSzuWM0W+l/xSOOYiSRRk3XWJfVjn
+9jQlcJRh5SOkKN08oZHrCYKxToEuOfV8PtRj3T80DhsBTv2SHqhg4cBhzQPb0Kjm
+9m4IkYOz8c5ZtuHDGnqMHw60Nyt+jyik4mMFP2frcOVP0W0sgwcfHllYzHoA/Khq
+Yk3TBVs1BjPuNDJWHct8Eo68YP2/ZvzqfVM87Q==
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/midpoint-objects-manual/tasks/task-async-update-grouper.xml b/demo/grouper/midpoint-objects-manual/tasks/task-async-update-grouper.xml
new file mode 100644
index 0000000..750ddc5
--- /dev/null
+++ b/demo/grouper/midpoint-objects-manual/tasks/task-async-update-grouper.xml
@@ -0,0 +1,43 @@
+
+
+
+ Grouper async updates
+
+
+
+ 1552664339630-0-2
+
+
+
+ runnable
+ AsynchronousUpdate
+ http://midpoint.evolveum.com/xml/ns/public/model/synchronization/task/async-update/handler-3
+
+
+
+ single
+ loose
+ restart
+
diff --git a/demo/grouper/midpoint-objects-manual/tasks/task-import-sis-persons.xml b/demo/grouper/midpoint-objects-manual/tasks/task-import-sis-persons.xml
new file mode 100644
index 0000000..ebeb5df
--- /dev/null
+++ b/demo/grouper/midpoint-objects-manual/tasks/task-import-sis-persons.xml
@@ -0,0 +1,31 @@
+
+ Import from SIS persons
+
+ account
+ ri:AccountObjectClass
+
+ 500
+
+
+ 1535407239440-0-1
+
+ runnable
+ ImportingAccounts
+ http://midpoint.evolveum.com/xml/ns/public/model/synchronization/task/import/handler-3
+
+ single
+ loose
+
diff --git a/demo/grouper/midpoint-objects-manual/tasks/task-recomputation-users.xml b/demo/grouper/midpoint-objects-manual/tasks/task-recomputation-users.xml
new file mode 100644
index 0000000..08bcc01
--- /dev/null
+++ b/demo/grouper/midpoint-objects-manual/tasks/task-recomputation-users.xml
@@ -0,0 +1,25 @@
+
+ User recomputing with bucket
+
+ c:UserType
+ 200
+
+ 1571729899646-0-1
+
+
+
+ http://midpoint.evolveum.com/xml/ns/public/provisioning/channels-3#recompute
+ runnable
+ Recomputation
+ http://midpoint.evolveum.com/xml/ns/public/model/synchronization/task/recompute/handler-3
+
+ standalone
+
+
+ 2
+
+
+
+ single
+ tight
+
diff --git a/demo/grouper/midpoint-objects-manual/tasks/task-reconciliation-grouper-groups.xml b/demo/grouper/midpoint-objects-manual/tasks/task-reconciliation-grouper-groups.xml
new file mode 100644
index 0000000..b59f5d7
--- /dev/null
+++ b/demo/grouper/midpoint-objects-manual/tasks/task-reconciliation-grouper-groups.xml
@@ -0,0 +1,43 @@
+
+
+
+ Grouper reconciliation (groups)
+
+ ri:CustomPlainGroupObjectClass
+
+ 605a0127-a313-442a-9d5e-151eac8b0745
+
+
+
+ runnable
+ Reconciliation
+ http://midpoint.evolveum.com/xml/ns/public/model/synchronization/task/reconciliation/handler-3
+
+
+
+ single
+ loose
+ restart
+
diff --git a/demo/grouper/midpoint-objects/archetypes/archetype-academic-person.xml b/demo/grouper/midpoint-objects/archetypes/archetype-academic-person.xml
new file mode 100644
index 0000000..bbbd6a8
--- /dev/null
+++ b/demo/grouper/midpoint-objects/archetypes/archetype-academic-person.xml
@@ -0,0 +1,25 @@
+
+
+ Academic
+ Person with a relation to the academy environment
+
+
+
+ Academics
+ Academic person
+
+ fa fa-user
+ darkgreen
+
+
+
+
+
+ UserType
+
+
+
diff --git a/demo/grouper/midpoint-objects/archetypes/archetype-affiliation.xml b/demo/grouper/midpoint-objects/archetypes/archetype-affiliation.xml
new file mode 100644
index 0000000..b0b9400
--- /dev/null
+++ b/demo/grouper/midpoint-objects/archetypes/archetype-affiliation.xml
@@ -0,0 +1,52 @@
+
+ affiliation
+
+ ref:affiliation:
+ ou=Affiliations,ou=Groups,dc=internet2,dc=edu
+ affiliation_
+ Affiliation:
+
+
+
+
+ Affiliations
+
+ fa fa-superpowers
+ steelblue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
diff --git a/demo/grouper/midpoint-objects/archetypes/archetype-course.xml b/demo/grouper/midpoint-objects/archetypes/archetype-course.xml
new file mode 100644
index 0000000..0b7013e
--- /dev/null
+++ b/demo/grouper/midpoint-objects/archetypes/archetype-course.xml
@@ -0,0 +1,64 @@
+
+ course
+
+ ref:course:
+ ou=Courses,ou=Groups,dc=internet2,dc=edu
+ course_
+ Course:
+
+
+
+
+ Courses
+
+ fa fa-university
+ teal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ weak
+
+
+ ri:courses
+
+ strong
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+
diff --git a/demo/grouper/midpoint-objects/archetypes/archetype-department.xml b/demo/grouper/midpoint-objects/archetypes/archetype-department.xml
new file mode 100644
index 0000000..26691be
--- /dev/null
+++ b/demo/grouper/midpoint-objects/archetypes/archetype-department.xml
@@ -0,0 +1,53 @@
+
+ department
+
+ ref:dept:
+ department_
+ Department:
+
+
+
+
+ Departments
+
+ fa fa-building
+ darkgreen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [ri:businessCategory]
+
+ strong
+
+
+
+
+
+
+ 2
+
+
diff --git a/demo/grouper/midpoint-objects/archetypes/archetype-generic-grouper-group.xml b/demo/grouper/midpoint-objects/archetypes/archetype-generic-grouper-group.xml
new file mode 100644
index 0000000..62f73eb
--- /dev/null
+++ b/demo/grouper/midpoint-objects/archetypes/archetype-generic-grouper-group.xml
@@ -0,0 +1,40 @@
+
+ generic-grouper-group
+
+
+ ou=generic,ou=Groups,dc=internet2,dc=edu
+ generic_
+
+
+
+
+
+ Generic Grouper Groups
+
+ fa fa-users
+ lightcoral
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/midpoint-objects/archetypes/archetype-mailing-list.xml b/demo/grouper/midpoint-objects/archetypes/archetype-mailing-list.xml
new file mode 100644
index 0000000..2db1df4
--- /dev/null
+++ b/demo/grouper/midpoint-objects/archetypes/archetype-mailing-list.xml
@@ -0,0 +1,56 @@
+
+ mailing-list
+
+ app:mailinglist:
+ ou=generic,ou=Groups,dc=internet2,dc=edu
+ mailinglist_
+ Mailing list:
+
+
+
+
+ Mailing lists
+
+ fa fa-list
+ darkgoldenrod
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ri:lists
+
+ strong
+
+
+
+
+
+
+ 2
+
+
diff --git a/demo/grouper/midpoint-objects/archetypes/archetype-midpoint-group.xml b/demo/grouper/midpoint-objects/archetypes/archetype-midpoint-group.xml
new file mode 100644
index 0000000..e3bc872
--- /dev/null
+++ b/demo/grouper/midpoint-objects/archetypes/archetype-midpoint-group.xml
@@ -0,0 +1,32 @@
+
+ midpoint-group
+
+ ou=midpoint,ou=Groups,dc=internet2,dc=edu
+
+
+
+
+ midPoint Groups
+
+ fa fa-users
+ darkgviolet
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/midpoint-objects/archetypes/archetype-non-academic-person.xml b/demo/grouper/midpoint-objects/archetypes/archetype-non-academic-person.xml
new file mode 100644
index 0000000..1c604aa
--- /dev/null
+++ b/demo/grouper/midpoint-objects/archetypes/archetype-non-academic-person.xml
@@ -0,0 +1,25 @@
+
+
+ Non-academic
+ Non-academic person with no relation to the academy environment
+
+
+
+ Non-academics
+ Non-academic persons
+
+ fa fa-space-shuttle
+ olive
+
+
+
+
+
+ UserType
+
+
+
diff --git a/demo/grouper/midpoint-objects/functionLibraries/function-library-grouper.xml b/demo/grouper/midpoint-objects/functionLibraries/function-library-grouper.xml
new file mode 100644
index 0000000..6219eb0
--- /dev/null
+++ b/demo/grouper/midpoint-objects/functionLibraries/function-library-grouper.xml
@@ -0,0 +1,184 @@
+
+
+
+ grouper
+ Functions for Grouper AMQP connector
+
+
+
+
+
+ createUcfChange
+
+ message
+ c:AsyncUpdateMessageType
+
+
+ superGroup
+ xsd:string
+
+
+ groupIncludePattern
+ xsd:anyType
+
+
+ groupExcludePattern
+ xsd:anyType
+
+
+ relevantSourceId
+ xsd:string
+
+
+ c:UcfChangeType
+
+
diff --git a/demo/grouper/midpoint-objects/objectTemplates/template-user.xml b/demo/grouper/midpoint-objects/objectTemplates/template-user.xml
new file mode 100644
index 0000000..9442803
--- /dev/null
+++ b/demo/grouper/midpoint-objects/objectTemplates/template-user.xml
@@ -0,0 +1,92 @@
+
+
+
+
+ User Template
+
+ strong
+
+ name
+
+
+
+
+
+ assignment
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/midpoint-objects/orgs/org-affiliations.xml b/demo/grouper/midpoint-objects/orgs/org-affiliations.xml
new file mode 100644
index 0000000..577c894
--- /dev/null
+++ b/demo/grouper/midpoint-objects/orgs/org-affiliations.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ affiliations
+ Affiliations
+
diff --git a/demo/grouper/midpoint-objects/orgs/org-courses.xml b/demo/grouper/midpoint-objects/orgs/org-courses.xml
new file mode 100644
index 0000000..47147d5
--- /dev/null
+++ b/demo/grouper/midpoint-objects/orgs/org-courses.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ courses
+ Courses
+
\ No newline at end of file
diff --git a/demo/grouper/midpoint-objects/orgs/org-departments.xml b/demo/grouper/midpoint-objects/orgs/org-departments.xml
new file mode 100644
index 0000000..b5638d4
--- /dev/null
+++ b/demo/grouper/midpoint-objects/orgs/org-departments.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ departments
+ Departments
+
\ No newline at end of file
diff --git a/demo/grouper/midpoint-objects/orgs/org-generic-groups.xml b/demo/grouper/midpoint-objects/orgs/org-generic-groups.xml
new file mode 100644
index 0000000..baa2c79
--- /dev/null
+++ b/demo/grouper/midpoint-objects/orgs/org-generic-groups.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ generic-groups
+ Generic groups
+
diff --git a/demo/grouper/midpoint-objects/orgs/org-grouper-sysadmin.xml b/demo/grouper/midpoint-objects/orgs/org-grouper-sysadmin.xml
new file mode 100644
index 0000000..201777a
--- /dev/null
+++ b/demo/grouper/midpoint-objects/orgs/org-grouper-sysadmin.xml
@@ -0,0 +1,16 @@
+
+
+
+ org-grouper-sysadmin
+ Grouper Administrators
+
+
+
+ sysadmingroup
+
diff --git a/demo/grouper/midpoint-objects/orgs/org-mailing-lists.xml b/demo/grouper/midpoint-objects/orgs/org-mailing-lists.xml
new file mode 100644
index 0000000..6674745
--- /dev/null
+++ b/demo/grouper/midpoint-objects/orgs/org-mailing-lists.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ mailing-lists
+ Mailing lists
+
diff --git a/demo/grouper/midpoint-objects/orgs/org-midpoint-groups.xml b/demo/grouper/midpoint-objects/orgs/org-midpoint-groups.xml
new file mode 100644
index 0000000..9c0658d
--- /dev/null
+++ b/demo/grouper/midpoint-objects/orgs/org-midpoint-groups.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ midpoint-groups
+ midPoint groups
+
diff --git a/demo/grouper/midpoint-objects/resources/ldap-main.xml b/demo/grouper/midpoint-objects/resources/ldap-main.xml
new file mode 100644
index 0000000..b49ed25
--- /dev/null
+++ b/demo/grouper/midpoint-objects/resources/ldap-main.xml
@@ -0,0 +1,341 @@
+
+
+
+
+
+ LDAP (directory)
+
+
+
+
+ c:connectorType
+ com.evolveum.polygon.connector.ldap.LdapConnector
+
+
+
+
+
+
+ 389
+ directory
+
+ dc=internet2,dc=edu
+ cn=Directory Manager
+
+ password
+
+ nsUniqueId
+ spr
+
+ memberOf
+ createTimestamp
+ nsAccountLock
+
+
+
+
+ false
+ false
+ false
+
+
+
+
+
+ ri:inetOrgPerson
+ ri:eduPerson
+ ri:groupOfUniqueNames
+ ri:groupOfNames
+ ri:organizationalUnit
+
+
+
+
+
+ account
+ Normal Account
+ true
+ ri:inetOrgPerson
+ ri:eduPerson
+
+ [ri:dn]
+ Distinguished Name
+
+ 0
+
+ false
+ mr:distinguishedName
+
+ strong
+
+ name
+
+
+
+
+
+
+
+ [ri:cn]
+ Common Name
+
+ 0
+
+ false
+
+ strong
+
+ fullName
+
+
+
+
+ [ri:sn]
+ Surname
+
+ 0
+
+ false
+
+ strong
+
+ familyName
+
+
+
+
+ [ri:givenName]
+ Given Name
+
+ 0
+
+ false
+
+ strong
+
+ givenName
+
+
+
+
+ [ri:uid]
+ Login Name
+ false
+ mr:stringIgnoreCase
+
+ strong
+
+ name
+
+
+
+
+ [ri:mail]
+ Mail
+ mr:stringIgnoreCase
+ false
+
+ strong
+
+ emailAddress
+
+
+
+
+ [ri:employeeNumber]
+ false
+
+ strong
+
+ employeeNumber
+
+
+
+
+ [ri:businessCategory]
+ false
+
+
+
+ false
+ [ri:group]
+ entitlement
+ group
+ objectToSubject
+ ri:uniqueMember
+ ri:dn
+
+
+
+
+ http://prism.evolveum.com/xml/ns/public/matching-rule-3#distinguishedName
+ attributes/ri:dn
+ cn=root,dc=internet2,dc=edu
+
+
+
+
+
+
+
+
+
+
+
+ entitlement
+ group
+ LDAP Group
+ ri:groupOfUniqueNames
+
+ [ri:uniqueMember]
+ mr:distinguishedName
+ minimal
+
+
+ [ri:dn]
+ mr:distinguishedName
+
+ strong
+
+ extension/ldapDn
+
+
+
+
+ [ri:cn]
+ mr:stringIgnoreCase
+
+ weak
+
+ identifier
+
+
+
+
+ [ri:uniqueMember]
+ mr:distinguishedName
+ minimal
+
+
+
+
+
+
+ true
+
+
+ name
+
+
+ declare namespace ri="http://midpoint.evolveum.com/xml/ns/public/resource/instance-3";
+ $projection/attributes/ri:uid
+
+
+
+
+
+ linked
+ true
+
+
+ deleted
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#unlink
+
+
+
+ unlinked
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#link
+
+
+
+ unmatched
+
+
+
+ group sync
+ ri:groupOfUniqueNames
+ entitlement
+ group
+ OrgType
+ true
+
+
+
+
+
+ extension/ldapDn
+
+ $projection/attributes/ri:dn
+
+
+
+
+ linked
+ true
+
+
+ deleted
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#unlink
+
+
+
+ unlinked
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#link
+
+
+
+ unmatched
+
+
+
+
+ true
+
+
diff --git a/demo/grouper/midpoint-objects/resources/resource-grouper.xml b/demo/grouper/midpoint-objects/resources/resource-grouper.xml
new file mode 100644
index 0000000..eafb708
--- /dev/null
+++ b/demo/grouper/midpoint-objects/resources/resource-grouper.xml
@@ -0,0 +1,186 @@
+
+
+
+
+
+ Grouper Resource
+
+
+
+ connectorType
+ com.evolveum.polygon.connector.grouper.rest.GrouperConnector
+
+
+
+
+
+ https://grouper-ws:443
+ banderson
+ password
+ etc:midpointGroups
+ midpoint:.*
+ app:.*
+ test:.*
+ ref:.*
+ .*_(includes|excludes|systemOfRecord|systemOfRecordAndIncludes)
+ ldap
+ g:gsa
+ true
+ :
+
+
+
+ AMQP async update connector
+
+
+
+ connectorType
+ AsyncUpdateConnector
+
+
+
+
+
+
+ amqp://mq:5672
+ guest
+ guest
+ sampleQueue
+
+
+
+
+
+
+
+
+
+ entitlement
+ group
+ ri:CustomPlainGroupObjectClass
+ true
+
+ [icfs:name]
+
+ strong
+
+ extension/grouperName
+
+
+
+ strong
+
+
+
+
+ assignment
+
+ all
+
+
+
+
+
+ [ri:member]
+ explicit
+ indexOnly
+
+
+
+
+
+ true
+ entitlement
+ group
+ ri:CustomPlainGroupObjectClass
+ OrgType
+
+
+ extension/grouperName
+
+ $projection/attributes/name
+
+
+
+
+ linked
+ http://midpoint.evolveum.com/xml/ns/public/provisioning/channels-3#asyncUpdate
+ false
+
+
+ linked
+ true
+
+
+ deleted
+
+
+ true
+
+
+ unlinked
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#link
+
+
+
+ unmatched
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus
+
+
+
+
+
+ passive
+
+
diff --git a/demo/grouper/midpoint-objects/resources/scriptedsql-sis-persons.xml b/demo/grouper/midpoint-objects/resources/scriptedsql-sis-persons.xml
new file mode 100644
index 0000000..0ca8cb0
--- /dev/null
+++ b/demo/grouper/midpoint-objects/resources/scriptedsql-sis-persons.xml
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+ SQL SIS persons (sources)
+
+
+
+
+ connectorType
+ net.tirasa.connid.bundles.db.scriptedsql.ScriptedSQLConnector
+
+
+
+
+
+
+
+ sources
+ 3306
+
+ root
+
+ 123321
+
+ sis
+
+ GROOVY
+
+ /opt/midpoint/var/res/sis-persons/SearchScript.groovy
+ /opt/midpoint/var/res/sis-persons/TestScript.groovy
+ /opt/midpoint/var/res/sis-persons/SchemaScript.groovy
+
+ false
+
+
+
+
+
+ org.mariadb.jdbc.Driver
+ jdbc:mysql://%h:%p/%d?useUnicode=true&characterEncoding=utf8&connectionCollation=utf8_bin
+ true
+ true
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+ account
+ Normal Account
+ true
+ ri:AccountObjectClass
+
+ [ri:uid]
+ UID
+
+
+ name
+
+
+
+ strong
+
+
+ RoleType
+ c89f31dd-8d4f-4e0a-82cb-58ff9d8c1b2f
+
+ grouper-basic
+
+
+
+
+ assignment
+
+
+
+
+
+
+
+
+ strong
+
+
+ ArchetypeType
+ 958da09c-fefb-11e9-892d-975972472527
+
+ grouper-basic
+
+
+
+
+ assignment
+
+
+
+
+
+
+
+
+
+ [ri:fullName]
+ Full Name
+
+
+ fullName
+
+
+
+
+ [ri:surname]
+ Surname
+
+
+ familyName
+
+
+
+
+ [ri:givenName]
+ Given Name
+
+
+ givenName
+
+
+
+
+ [ri:mail]
+ Mail
+ mr:stringIgnoreCase
+
+
+ emailAddress
+
+
+
+
+
+
+
+
+ true
+
+
+
+ name
+
+
+ declare namespace ri="http://midpoint.evolveum.com/xml/ns/public/resource/instance-3";
+ $projection/attributes/ri:uid
+
+
+
+
+
+
+ linked
+ true
+
+
+ deleted
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#unlink
+
+
+
+
+ unlinked
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#link
+
+
+
+ unmatched
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus
+
+
+
+
+
+
+
diff --git a/demo/grouper/midpoint-objects/resources/target-cs-portal.xml b/demo/grouper/midpoint-objects/resources/target-cs-portal.xml
new file mode 100644
index 0000000..e308eb1
--- /dev/null
+++ b/demo/grouper/midpoint-objects/resources/target-cs-portal.xml
@@ -0,0 +1,112 @@
+
+
+
+
+ Target: Computer science portal (CSV)
+
+
+
+
+ c:connectorType
+ com.evolveum.polygon.connector.csv.CsvConnector
+
+
+
+
+
+
+
+ /opt/midpoint/var/cs-portal.csv
+ utf-8
+ ,
+ ;
+ identifier
+
+
+
+
+
+
+ Default Account
+ true
+ ri:AccountObjectClass
+
+ [ri:identifier]
+
+ strong
+
+ name
+
+
+
+
+ [ri:name]
+
+ strong
+
+ fullName
+
+
+
+
+ [ri:mail]
+
+ strong
+
+ emailAddress
+
+
+
+
+ [ri:courses]
+
+ unbounded
+
+ false
+
+
+
+
+
+
+ true
+
+
+ name
+
+ $projection/attributes/identifier
+
+
+
+
+ linked
+ true
+
+
+ deleted
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#unlink
+
+
+
+ unlinked
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#link
+
+
+
+ unmatched
+
+
+
+
diff --git a/demo/grouper/midpoint-objects/resources/target-faculty-portal.xml b/demo/grouper/midpoint-objects/resources/target-faculty-portal.xml
new file mode 100644
index 0000000..855268b
--- /dev/null
+++ b/demo/grouper/midpoint-objects/resources/target-faculty-portal.xml
@@ -0,0 +1,121 @@
+
+
+
+
+ Target: Faculty portal (CSV)
+
+
+
+
+ c:connectorType
+ com.evolveum.polygon.connector.csv.CsvConnector
+
+
+
+
+
+
+
+ /opt/midpoint/var/faculty-portal.csv
+ utf-8
+ ,
+ ;
+ uid
+
+
+
+
+
+ Default Account
+ true
+ ri:AccountObjectClass
+
+ [ri:uid]
+
+ strong
+
+ name
+
+
+
+
+ [ri:givenName]
+
+ strong
+
+ givenName
+
+
+
+
+ [ri:familyName]
+
+ strong
+
+ familyName
+
+
+
+
+ [ri:fullName]
+
+ strong
+
+ fullName
+
+
+
+
+ [ri:mail]
+
+ strong
+
+ emailAddress
+
+
+
+
+
+
+
+ true
+
+
+ name
+
+ $projection/attributes/uid
+
+
+
+
+ linked
+ true
+
+
+ deleted
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#unlink
+
+
+
+ unlinked
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#link
+
+
+
+ unmatched
+
+
+
+
diff --git a/demo/grouper/midpoint-objects/resources/target-mailing-lists.xml b/demo/grouper/midpoint-objects/resources/target-mailing-lists.xml
new file mode 100644
index 0000000..1f69417
--- /dev/null
+++ b/demo/grouper/midpoint-objects/resources/target-mailing-lists.xml
@@ -0,0 +1,102 @@
+
+
+
+
+ Target: Mailing lists (CSV)
+
+
+
+
+ c:connectorType
+ com.evolveum.polygon.connector.csv.CsvConnector
+
+
+
+
+
+
+
+ /opt/midpoint/var/mailing-lists.csv
+ utf-8
+ ,
+ ;
+ uid
+
+
+
+
+
+ Default Account
+ true
+ ri:AccountObjectClass
+
+ [ri:uid]
+
+ strong
+
+ name
+
+
+
+
+ [ri:mail]
+
+ strong
+
+ emailAddress
+
+
+
+
+ [ri:lists]
+
+ unbounded
+
+ false
+
+
+
+
+
+
+ true
+
+
+ name
+
+ $projection/attributes/uid
+
+
+
+
+ linked
+ true
+
+
+ deleted
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#unlink
+
+
+
+ unlinked
+ true
+
+ http://midpoint.evolveum.com/xml/ns/public/model/action-3#link
+
+
+
+ unmatched
+
+
+
+
diff --git a/demo/grouper/midpoint-objects/roles/metarole-grouper-provided-group.xml b/demo/grouper/midpoint-objects/roles/metarole-grouper-provided-group.xml
new file mode 100644
index 0000000..1274be7
--- /dev/null
+++ b/demo/grouper/midpoint-objects/roles/metarole-grouper-provided-group.xml
@@ -0,0 +1,192 @@
+
+
+
+ metarole-grouper-provided-group
+ A metarole for archetyped Grouper-provided groups
+
+
+
+
+ identifier
+ This mapping fills-in org identifier (e.g. 'member') from extension/grouperName (e.g. 'ref:affiliation:member').
+ It uses extension/grouperNamePrefix information from the archetype (e.g. 'ref:affiliation:' defined in affiliation archetype)
+ strong
+
+ extension/grouperName
+
+
+
+
+
+ identifier
+
+
+
+
+ name
+ This mapping fills-in org name (e.g. 'affiliation_member') from identifier (e.g. 'member').
+ It uses extension/midPointNamePrefix information from the archetype (e.g. 'affiliation_' defined in affiliation archetype)
+ strong
+
+ identifier
+
+
+
+
+
+ name
+
+
+
+
+ displayName
+ This mapping fills-in org displayName (e.g. 'Affiliation: member') from identifier (e.g. 'member').
+ It uses extension/midPointDisplayNamePrefix information from the archetype (e.g. 'Affiliation: ' defined in affiliation archetype)
+ strong
+
+ identifier
+
+
+
+
+
+ displayName
+
+
+
+
+ lifecycle state
+ This mapping sets org lifecycle state to be either "active" or "retired", depending on
+ whether Grouper group for this org still exists. Orgs in the latter state are on the way to deletion:
+ their members are unassigned and after no members are there, the org is automatically deleted.
+ strong
+
+
+
+
+ lifecycleState
+
+
+
+
+
+ 2
+
+
\ No newline at end of file
diff --git a/demo/grouper/midpoint-objects/roles/metarole-ldap-group.xml b/demo/grouper/midpoint-objects/roles/metarole-ldap-group.xml
new file mode 100644
index 0000000..91bf370
--- /dev/null
+++ b/demo/grouper/midpoint-objects/roles/metarole-ldap-group.xml
@@ -0,0 +1,128 @@
+
+
+
+ metarole-ldap-group
+ A metarole for archetyped LDAP groups
+
+
+
+
+
+
+ ldapDn
+ strong
+
+ identifier
+
+
+
+
+
+ extension/ldapDn
+
+
+
+ 2
+
+
+
+
+
+
+ entitlement
+ group
+
+ 2
+
+
+
+
+
+
+
+ ri:group
+
+
+
+
+ entitlement
+ group
+
+ 1
+
+
+
+
+
+ 3
+
+
diff --git a/demo/grouper/midpoint-objects/roles/role-ldap-basic.xml b/demo/grouper/midpoint-objects/roles/role-ldap-basic.xml
new file mode 100644
index 0000000..731f024
--- /dev/null
+++ b/demo/grouper/midpoint-objects/roles/role-ldap-basic.xml
@@ -0,0 +1,25 @@
+
+
+
+ role-ldap-basic
+
+
+
+
+ 1
+
+
diff --git a/demo/grouper/midpoint-objects/systemConfigurations/SystemConfiguration.xml b/demo/grouper/midpoint-objects/systemConfigurations/SystemConfiguration.xml
new file mode 100644
index 0000000..9970677
--- /dev/null
+++ b/demo/grouper/midpoint-objects/systemConfigurations/SystemConfiguration.xml
@@ -0,0 +1,257 @@
+
+
+
+ SystemConfiguration
+
+
+
+ ERROR
+ ro.isdc.wro.extensions.processor.css.Less4jProcessor
+
+
+ OFF
+ org.hibernate.engine.jdbc.spi.SqlExceptionHelper
+
+
+ OFF
+ org.hibernate.engine.jdbc.batch.internal.BatchingBatch
+
+
+ WARN
+ org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl
+
+
+ OFF
+ org.hibernate.internal.ExceptionMapperStandardImpl
+
+
+ OFF
+ net.sf.jasperreports.engine.fill.JRFillDataset
+
+
+ WARN
+ org.apache.wicket.resource.PropertiesFactory
+
+
+ ERROR
+ org.springframework.context.support.ResourceBundleMessageSource
+
+
+ INFO
+ com.evolveum.midpoint.model.impl.lens.projector.Projector
+
+
+ INFO
+ com.evolveum.midpoint.model.impl.lens.Clockwork
+
+
+ %date [%X{subsystem}] [%thread] %level \(%logger\): %msg%n
+ MIDPOINT_LOG
+ ${midpoint.home}/log/midpoint.log
+ ${midpoint.home}/log/midpoint-%d{yyyy-MM-dd}.%i.log
+ 10
+ 100MB
+ true
+
+
+ %date %level: %msg%n
+ MIDPOINT_PROFILE_LOG
+ ${midpoint.home}/log/midpoint-profile.log
+ ${midpoint.home}/log/midpoint-profile-%d{yyyy-MM-dd}.%i.log
+ 10
+ 100MB
+ true
+
+ MIDPOINT_LOG
+ INFO
+
+ false
+ false
+
+
+
+ UserType
+
+
+
+ OrgType
+
+
+ retired
+
+
+
+
+
+
+ P3M
+
+
+ P1M
+
+
+
+ true
+
+ true
+
+
+ true
+ true
+
+
+ true
+ true
+
+
+ true
+
+
+
+ true
+
+
+ perCacheAndObjectType
+
+
+
+ 60
+
+ SystemConfigurationType
+ ArchetypeType
+ ObjectTemplateType
+ SecurityPolicyType
+ ValuePolicyType
+ ResourceType
+ RoleType
+ OrgType
+ ServiceType
+ ShadowType
+
+
+ perCacheAndObjectType
+
+
+
+
+
+
+ perOperationAndObjectType
+
+
+
+
+ performance
+ Performance tracing
+ true
+ true
+ performance-trace %{timestamp} %{focusName} %{milliseconds}
+ true
+ true
+
+
+ functional
+ Functional tracing
+ true
+ functional-trace %{timestamp} %{focusName}
+ true
+ true
+ true
+
+ normal
+
+
+
+ functional-model-logging
+ Functional tracing (with model logging)
+ true
+ functional-trace %{timestamp} %{focusName}
+ true
+ true
+ true
+
+
+ com.evolveum.midpoint.model
+ TRACE
+
+
+
+ normal
+
+
+
+ functional-sql-logging
+ Functional tracing (with SQL logging)
+ true
+ functional-trace %{timestamp} %{focusName}
+ true
+ true
+ true
+
+
+ org.hibernate.SQL
+ TRACE
+
+
+
+ normal
+
+
+
+
+
+ demo/grouper
+
+
+
+ /self/profile
+
+ View/edit your profile
+
+ fa fa-user
+
+ green
+ http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#selfProfile
+ http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#selfAll
+
+
+ /self/credentials
+
+ View/edit your credentials
+
+ fa fa-shield
+
+ blue
+ http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#selfCredentials
+ http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#selfAll
+
+
+ /admin/users
+
+
+ fa fa-users
+
+ red
+ http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#users
+
+
+ /admin/resources
+
+
+ fa fa-database
+
+ purple
+ http://midpoint.evolveum.com/xml/ns/public/security/authorization-ui-3#resources
+
+ true
+
+
+ never
+ never
+
+
diff --git a/demo/grouper/midpoint-objects/tasks/task-group-scavenger.xml b/demo/grouper/midpoint-objects/tasks/task-group-scavenger.xml
new file mode 100644
index 0000000..60f9852
--- /dev/null
+++ b/demo/grouper/midpoint-objects/tasks/task-group-scavenger.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+ Group Scavenger
+
+
+
+ execute-script
+
+ script
+
+ import com.evolveum.midpoint.xml.ns._public.common.common_3.*
+
+ result = midpoint.currentResult
+ log.info('Processing dead group: {}', input)
+ query = prismContext.queryFor(UserType.class)
+ .item(UserType.F_ROLE_MEMBERSHIP_REF).ref(input.oid)
+ .build()
+ members = midpoint.repositoryService.searchObjects(UserType.class, query, null, result)
+ log.info('Found {} members: {}', members.size(), members)
+
+ for (member in members) {
+ log.info('Going to recompute {}', member)
+ try {
+ midpoint.recompute(UserType.class, member.oid)
+ } catch (Throwable t) {
+ log.error('Couldn\'t recompute {}: {}', member, t.message, t)
+ }
+ }
+ log.info('Members recomputed; checking if the org is still in "retired" state')
+ orgAfter = midpoint.repositoryService.getObject(OrgType.class, input.oid, null, result)
+ currentState = orgAfter.asObjectable().lifecycleState
+ log.info('Current state = {}', currentState)
+ if (currentState == 'retired') {
+ log.info('Deleting the org: {}', orgAfter)
+ midpoint.deleteObject(OrgType.class, orgAfter.oid, null)
+ } else {
+ log.info('State has changed, not deleting the org: {}', orgAfter)
+ }
+ log.info('Dead group processing done: {}', input)
+
+
+
+
+
+ OrgType
+
+
+
+ lifecycleState
+ retired
+
+
+
+
+
+ runnable
+ BulkActions
+ http://midpoint.evolveum.com/xml/ns/public/model/iterative-scripting/handler-3
+ recurring
+
+ 60
+
+
diff --git a/demo/grouper/midpoint-objects/users/user-banderson.xml b/demo/grouper/midpoint-objects/users/user-banderson.xml
new file mode 100644
index 0000000..10197ea
--- /dev/null
+++ b/demo/grouper/midpoint-objects/users/user-banderson.xml
@@ -0,0 +1,27 @@
+
+
+
+ banderson
+
+
+
+
+
+ Bob Anderson
+ Bob
+ Anderson
+
+
+ password
+
+
+
+
diff --git a/demo/grouper/midpoint_server/Dockerfile b/demo/grouper/midpoint_server/Dockerfile
new file mode 100644
index 0000000..43dac56
--- /dev/null
+++ b/demo/grouper/midpoint_server/Dockerfile
@@ -0,0 +1,9 @@
+FROM tier/midpoint:laboratory
+
+MAINTAINER info@evolveum.com
+
+ENV MP_DIR /opt/midpoint
+
+VOLUME ${MP_DIR}/var
+
+COPY container_files/mp-home/ ${MP_DIR}/var/
diff --git a/demo/grouper/midpoint_server/container_files/httpd/host-cert.pem b/demo/grouper/midpoint_server/container_files/httpd/host-cert.pem
new file mode 100644
index 0000000..9b1021b
--- /dev/null
+++ b/demo/grouper/midpoint_server/container_files/httpd/host-cert.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDqDCCApCgAwIBAgIJAMOSkn4oS2aAMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJNSTESMBAGA1UEBwwJQW5uIEFyYm9yMRcwFQYDVQQK
+DA5JbnRlcm5ldDIvVElFUjEgMB4GA1UEAwwXbWlkcG9pbnQuc3AuZXhhbXBsZS5v
+cmcwHhcNMTgwOTE0MDU1OTQ1WhcNMTkwOTE0MDU1OTQ1WjBpMQswCQYDVQQGEwJV
+UzELMAkGA1UECAwCTUkxEjAQBgNVBAcMCUFubiBBcmJvcjEXMBUGA1UECgwOSW50
+ZXJuZXQyL1RJRVIxIDAeBgNVBAMMF21pZHBvaW50LnNwLmV4YW1wbGUub3JnMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApj/b7MEUSfu3oXMfNgRwTse7
+a5UV7Jswf1M/ZN/ZZkAkIxNBevZgozjesvLPWrmsTgONi7XigJUJvCjdjmlW9eDM
+lri/rkD8HuOR1DQCVKL9nvoS2c3D7sq5Emda3V8Tlj82VqfEmePd3sajx7mcTfbH
+8jwAL9NhkC+WMib5IpjLGpG0FEAC0ha7Lxb+7jIiqHVJaqLXJGCyGN4mh6c1Q9S1
+f8RVTiW2a8x22G+9wnZYbkiA2Kxls177imHlhSz8EdvV4IpGw1amrEWhhuDEum7B
+vZ1xQDLatgRqh4qAKLIVYeRnJ8H1FelMa90qB4G08MIPifmTsQwqJyBYaEdgWQID
+AQABo1MwUTAdBgNVHQ4EFgQUqb9BteODF6wv5R57aEON/wGXMiowHwYDVR0jBBgw
+FoAUqb9BteODF6wv5R57aEON/wGXMiowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQsFAAOCAQEAAcKhxI+tSItrXmqC0PSmgWyAYpqbkz6W/cefTutXqhIgY09f
+h0LSv7ogTahoGpyiZk9vy6u3OE9bYwxapEfa4KBjO6HxBMIVBBb3RegVjoPzjElN
+BDwAx0VGFcZTXwMxDWycWdG8ql7rCZBvS50w04uTaIgnGmqXAdWWmBgfJ9cRbxW+
+JwO/mOl1QM1lR/5142NpvuUVWlmZSKEGydE5A1qPz2wpDbBR1ym1BQNS4NEqw6Kp
+GSB8jKyCS1Ve0v2wVze2038Wukz02dq9uKPTIO3T+B+ibZmxn6Op/kFCc1/kK5NS
+Q6JdO1B6KquGAYdGmKAcQ19mv+jqGktqWEEf0g==
+-----END CERTIFICATE-----
diff --git a/demo/grouper/midpoint_server/container_files/httpd/host-key.pem b/demo/grouper/midpoint_server/container_files/httpd/host-key.pem
new file mode 100644
index 0000000..5746e59
--- /dev/null
+++ b/demo/grouper/midpoint_server/container_files/httpd/host-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCmP9vswRRJ+7eh
+cx82BHBOx7trlRXsmzB/Uz9k39lmQCQjE0F69mCjON6y8s9auaxOA42LteKAlQm8
+KN2OaVb14MyWuL+uQPwe45HUNAJUov2e+hLZzcPuyrkSZ1rdXxOWPzZWp8SZ493e
+xqPHuZxN9sfyPAAv02GQL5YyJvkimMsakbQUQALSFrsvFv7uMiKodUlqotckYLIY
+3iaHpzVD1LV/xFVOJbZrzHbYb73CdlhuSIDYrGWzXvuKYeWFLPwR29XgikbDVqas
+RaGG4MS6bsG9nXFAMtq2BGqHioAoshVh5GcnwfUV6Uxr3SoHgbTwwg+J+ZOxDCon
+IFhoR2BZAgMBAAECggEAEIRBpjjceiku6jRUwnoYaks/nIWYQwR8AfpUTwJKR/VR
+Yca097Fokm7A+UhUP3A45RtHQb0VPq8P44iv0kk24YCu8r5yFK7SHYOAZnOwU5ZJ
+2jSAEPF3aM7tKh3okhuzB3dKP7u1NZDE5zAW723KUJiW7sL1RcsbY0bHBj6G+9/H
+NplmsjuGt684vRBB0qOBfKF7EiG7mT69tHuNj4gRza9SMY31UtKbZdt2fNY6mp5V
+HscMba7egZP+Ke0pVX4+go9j7K8GG8hYaQDLjrzlPqrxZ2c5X9cC+CRDI/CHuL/s
+V/2yGZJ6n6UabwZoH83RdFrbQ94rU8Hkli6EvxXvMQKBgQDRpheNW5jDG5TfeJKh
+yfKTDQqH2Tk3BsBYYBN7Hf3m7vbkzlxnAKJAoSLmtRMuoeXvI5MrhzaHGsNIUS76
+LDIZnvB7DLUxhFUZsCPkpAA1QHuTWY96oR3PHnPjpk8lSUvtbOPwDLdzVApeFJgZ
+VqMNArZ7AHsK3Kkyi+f4WVQjbQKBgQDLAWiGb5dx6fAM2W6B6HjNmzjBWOuVEXa2
+76to9jzupBZmETfZgxtWUaWUDuNS+f7dtVUTE+p6v/w8clrHEhEZYkqunIOLo/UA
+LFPiuoTfEsWb1rh+nsCjCgy4uimixj/bSkf7NC6NyKTvCygA1mGnVVJUEPegYlDy
+LXCkaKWxHQKBgQCmyHSKL2lrJkEcOwakEU2acNCE3Gno/cT9SYmV83kvQ8JEqmrW
+QqnRsp9aXIljGscapPmKsmnNt5vNp1AxFAHTYh88NRLczsMIyZj0ZwgHVUI6KhC7
+5Psa78YQQBlMt2/g9TSsnuE+rYgF6mpKFiNm0Vasqeg47uzn2mdzqlUGTQKBgE04
+JutkTUY+h1pL5vYxWKpVDfy19z7H2tFxT1FowPrBneeLSyRI88Ac5I/yLdRlVeY9
+0LOmEr5Igwj3MsKgg7KVKfVLgdo/LrW3Jt2Kt3onKNXDkoBPoNUjwH0QC0Boiue+
+VK0gR0kVdm+bXccbxR+im+NwZNE0NLg6Qqu3RredAoGBALuVoqbPPmTCZXYG328H
+bzOs2aiR7BzPSVByV+qG6jW7w03RAnFPJZp7HMU+ViI5VY0wabUscMSvz5163+gM
+4KwY3v9ZjZzZGukIfLuudkdqtaiVOx/KeAC0n+nG21YU+wpZww8gkfHh1/sa2CME
+CWYCgOnmiTHcj83UaTqEXtmv
+-----END PRIVATE KEY-----
diff --git a/demo/grouper/midpoint_server/container_files/mp-home/config.xml b/demo/grouper/midpoint_server/container_files/mp-home/config.xml
new file mode 100644
index 0000000..5a4e0ea
--- /dev/null
+++ b/demo/grouper/midpoint_server/container_files/mp-home/config.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+ ${midpoint.home}/import
+
+
+ com.evolveum.midpoint.repo.sql.SqlRepositoryFactory
+ ${midpoint.home}
+ true
+ true
+ true
+ true
+
+
+
+ com.evolveum.midpoint.audit.impl.LoggerAuditServiceFactory
+
+
+ com.evolveum.midpoint.repo.sql.SqlAuditServiceFactory
+
+
+
+ true
+ ${midpoint.home}/icf-connectors
+
+
+ ${midpoint.home}/keystore.jceks
+ changeit
+ default
+
+
+
+
+
diff --git a/demo/grouper/midpoint_server/container_files/mp-home/cs-portal.csv b/demo/grouper/midpoint_server/container_files/mp-home/cs-portal.csv
new file mode 100644
index 0000000..02a0c65
--- /dev/null
+++ b/demo/grouper/midpoint_server/container_files/mp-home/cs-portal.csv
@@ -0,0 +1 @@
+identifier,name,mail,courses
diff --git a/demo/grouper/midpoint_server/container_files/mp-home/faculty-portal.csv b/demo/grouper/midpoint_server/container_files/mp-home/faculty-portal.csv
new file mode 100644
index 0000000..ce346c5
--- /dev/null
+++ b/demo/grouper/midpoint_server/container_files/mp-home/faculty-portal.csv
@@ -0,0 +1 @@
+uid,givenName,familyName,fullName,mail
diff --git a/demo/grouper/midpoint_server/container_files/mp-home/icf-connectors/connector-grouper-rest-0.4.jar b/demo/grouper/midpoint_server/container_files/mp-home/icf-connectors/connector-grouper-rest-0.4.jar
new file mode 100644
index 0000000..b072d05
Binary files /dev/null and b/demo/grouper/midpoint_server/container_files/mp-home/icf-connectors/connector-grouper-rest-0.4.jar differ
diff --git a/demo/grouper/midpoint_server/container_files/mp-home/icf-connectors/net.tirasa.connid.bundles.db.scriptedsql-2.2.6-SNAPSHOT.jar b/demo/grouper/midpoint_server/container_files/mp-home/icf-connectors/net.tirasa.connid.bundles.db.scriptedsql-2.2.6-SNAPSHOT.jar
new file mode 100644
index 0000000..88fcb54
Binary files /dev/null and b/demo/grouper/midpoint_server/container_files/mp-home/icf-connectors/net.tirasa.connid.bundles.db.scriptedsql-2.2.6-SNAPSHOT.jar differ
diff --git a/demo/grouper/midpoint_server/container_files/mp-home/mailing-lists.csv b/demo/grouper/midpoint_server/container_files/mp-home/mailing-lists.csv
new file mode 100644
index 0000000..780ab04
--- /dev/null
+++ b/demo/grouper/midpoint_server/container_files/mp-home/mailing-lists.csv
@@ -0,0 +1 @@
+uid,mail,lists
diff --git a/demo/grouper/midpoint_server/container_files/mp-home/res/sis-persons/SchemaScript.groovy b/demo/grouper/midpoint_server/container_files/mp-home/res/sis-persons/SchemaScript.groovy
new file mode 100644
index 0000000..0e0a52f
--- /dev/null
+++ b/demo/grouper/midpoint_server/container_files/mp-home/res/sis-persons/SchemaScript.groovy
@@ -0,0 +1,57 @@
+/*
+ * ====================
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 ForgeRock. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License("CDDL") (the "License"). You may not use this file
+ * except in compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://opensource.org/licenses/cddl1.php
+ * See the License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * When distributing the Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://opensource.org/licenses/cddl1.php.
+ * If applicable, add the following below this CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * ====================
+ * Portions Copyrighted 2013 ConnId.
+ */
+import org.identityconnectors.framework.common.objects.AttributeInfo;
+import org.identityconnectors.framework.common.objects.AttributeInfo.Flags;
+import org.identityconnectors.framework.common.objects.AttributeInfoBuilder;
+import org.identityconnectors.framework.common.objects.ObjectClassInfo;
+import org.identityconnectors.framework.common.objects.ObjectClassInfoBuilder;
+
+// Parameters:
+// The connector sends the following:
+// action: a string describing the action ("SCHEMA" here)
+// log: a handler to the Log facility
+// builder: SchemaBuilder instance for the connector
+//
+// The connector will make the final call to builder.build()
+// so the scipt just need to declare the different object types.
+
+// This sample shows how to create 3 basic ObjectTypes: __ACCOUNT__, __GROUP__ and organization.
+// Each of them contains one required attribute and normal String attributes
+
+
+log.info("Entering "+action+" Script");
+
+uidAIB = new AttributeInfoBuilder("uid",String.class);
+uidAIB.setRequired(true);
+
+accAttrsInfo = new HashSet();
+accAttrsInfo.add(uidAIB.build());
+accAttrsInfo.add(AttributeInfoBuilder.build("surname", String.class));
+accAttrsInfo.add(AttributeInfoBuilder.build("givenName", String.class));
+accAttrsInfo.add(AttributeInfoBuilder.build("fullName", String.class));
+accAttrsInfo.add(AttributeInfoBuilder.build("mail", String.class));
+ociAccount = new ObjectClassInfoBuilder().setType("__ACCOUNT__").addAllAttributeInfo(accAttrsInfo).build();
+builder.defineObjectClass(ociAccount);
+
+log.info("Schema script done");
diff --git a/demo/grouper/midpoint_server/container_files/mp-home/res/sis-persons/SearchScript.groovy b/demo/grouper/midpoint_server/container_files/mp-home/res/sis-persons/SearchScript.groovy
new file mode 100644
index 0000000..5a1f572
--- /dev/null
+++ b/demo/grouper/midpoint_server/container_files/mp-home/res/sis-persons/SearchScript.groovy
@@ -0,0 +1,153 @@
+/*
+ * ====================
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 ForgeRock. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License("CDDL") (the "License"). You may not use this file
+ * except in compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://opensource.org/licenses/cddl1.php
+ * See the License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * When distributing the Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://opensource.org/licenses/cddl1.php.
+ * If applicable, add the following below this CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * ====================
+ * Portions Copyrighted 2013 ConnId.
+ */
+
+import groovy.sql.Sql
+import groovy.sql.DataSet
+import org.identityconnectors.framework.common.objects.*
+
+// Parameters:
+// The connector sends the following:
+// connection: handler to the SQL connection
+// objectClass: a String describing the Object class (__ACCOUNT__ / __GROUP__ / other)
+// action: a string describing the action ("SEARCH" here)
+// log: a handler to the Log facility
+// options: a handler to the OperationOptions Map
+// query: a handler to the Query Map
+//
+// The Query map describes the filter used.
+//
+// query = [ operation: "CONTAINS", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "ENDSWITH", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "STARTSWITH", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "EQUALS", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "GREATERTHAN", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "GREATERTHANOREQUAL", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "LESSTHAN", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "LESSTHANOREQUAL", left: attribute, right: "value", not: true/false ]
+// query = null : then we assume we fetch everything
+//
+// AND and OR filter just embed a left/right couple of queries.
+// query = [ operation: "AND", left: query1, right: query2 ]
+// query = [ operation: "OR", left: query1, right: query2 ]
+//
+// Returns: A list of Maps. Each map describing one row.
+// !!!! Each Map must contain a '__UID__' and '__NAME__' attribute.
+// This is required to build a ConnectorObject.
+
+log.info("Entering "+action+" Script");
+
+def sql = new Sql(connection);
+def result = []
+def where = "";
+def sqlParams = null
+
+switch ( objectClass ) {
+ case "__ACCOUNT__":
+
+ uidColumn = 'uid'
+ nameColumn = 'uid'
+
+ log.info("Building where clause, query {0}, uidcolumn {1}, nameColumn {2}", query, uidColumn, nameColumn)
+
+ String left = query?.get("left")
+ if (left != null) {
+ if (Uid.NAME.equals(left)) {
+ left = uidColumn
+ } else if (Name.NAME.equals(left)) {
+ left = nameColumn
+ }
+
+ String right = query.get("right")
+
+ String operation = query.get("operation")
+ switch (operation) {
+ case "CONTAINS":
+ right = '%' + right + '%'
+ break;
+ case "ENDSWITH":
+ right = '%' + right
+ break;
+ case "STARTSWITH":
+ right = right + '%'
+ break;
+ }
+
+ sqlParams = [:]
+ sqlParams.put(left, right)
+ right = ":" + left
+
+ def engine = new groovy.text.SimpleTemplateEngine()
+
+ def whereTemplates = [
+ CONTAINS : ' $left ${not ? "not " : ""}like $right',
+ ENDSWITH : ' $left ${not ? "not " : ""}like $right',
+ STARTSWITH : ' $left ${not ? "not " : ""}like $right',
+ EQUALS : ' $left ${not ? "<>" : "="} $right',
+ GREATERTHAN : ' $left ${not ? "<=" : ">"} $right',
+ GREATERTHANOREQUAL: ' $left ${not ? "<" : ">="} $right',
+ LESSTHAN : ' $left ${not ? ">=" : "<"} $right',
+ LESSTHANOREQUAL : ' $left ${not ? ">" : "<="} $right'
+ ]
+
+ def wt = whereTemplates.get(operation)
+ if (wt != null) {
+ def binding = [left: left, right: right, not: query.get("not")]
+ def template = engine.createTemplate(wt).make(binding)
+ where = ' where ' + template.toString()
+ log.info("Where clause: {0}, with parameters {1}", where, sqlParams)
+ } else {
+ log.warn('Unsupported query: {0}, continuing without WHERE clause (worsening the performance)', query)
+ sqlParams = null
+ where = ''
+ }
+ }
+
+ q = 'select uid, surname, givenName, fullName, mail from SIS_PERSONS' + where
+
+ log.info('query = {0}', query)
+ log.info('sql = {0}', q)
+ log.info('sqlParams = {0}', sqlParams)
+
+ def processRow = { row -> result.add([
+ __UID__:row.uid,
+ __NAME__:row.uid,
+ uid:row.uid,
+ surname:row.surname,
+ givenName:row.givenName,
+ fullName:row.fullName,
+ mail:row.mail])
+ }
+
+ if (sqlParams != null) {
+ sql.eachRow(sqlParams, q, processRow)
+ } else {
+ sql.eachRow(q, processRow)
+ }
+ break
+
+ default:
+ result;
+}
+
+return result;
diff --git a/demo/grouper/midpoint_server/container_files/mp-home/res/sis-persons/TestScript.groovy b/demo/grouper/midpoint_server/container_files/mp-home/res/sis-persons/TestScript.groovy
new file mode 100644
index 0000000..c887660
--- /dev/null
+++ b/demo/grouper/midpoint_server/container_files/mp-home/res/sis-persons/TestScript.groovy
@@ -0,0 +1,38 @@
+/*
+ * ====================
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 ForgeRock. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common Development
+ * and Distribution License("CDDL") (the "License"). You may not use this file
+ * except in compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://opensource.org/licenses/cddl1.php
+ * See the License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * When distributing the Covered Code, include this CDDL Header Notice in each file
+ * and include the License file at http://opensource.org/licenses/cddl1.php.
+ * If applicable, add the following below this CDDL Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ * ====================
+ * Portions Copyrighted 2013 ConnId.
+ */
+import groovy.sql.Sql;
+import groovy.sql.DataSet;
+
+// Parameters:
+// The connector sends the following:
+// connection: handler to the SQL connection
+// action: a string describing the action ("TEST" here)
+// log: a handler to the Log facility
+
+log.info("Entering "+action+" Script");
+def sql = new Sql(connection);
+
+sql.eachRow("select * from SIS_PERSONS limit 10", { println it.uid } );
+
+
diff --git a/demo/grouper/midpoint_server/container_files/mp-home/schema/internet2.xsd b/demo/grouper/midpoint_server/container_files/mp-home/schema/internet2.xsd
new file mode 100644
index 0000000..c482436
--- /dev/null
+++ b/demo/grouper/midpoint_server/container_files/mp-home/schema/internet2.xsd
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/grouper/mq/Dockerfile b/demo/grouper/mq/Dockerfile
new file mode 100644
index 0000000..1593b80
--- /dev/null
+++ b/demo/grouper/mq/Dockerfile
@@ -0,0 +1,13 @@
+FROM tier/rabbitmq:latest
+
+COPY container_files/etc-rabbitmq/* /etc/rabbitmq/
+COPY container_files/usr-local-bin/* /usr/local/bin/
+
+ENV RABBITMQ_PID_FILE=/var/run/rabbitmq/pid
+
+# Must be on /var/lib/rabbitmq (this is the same place where queues are defined)
+ENV RABBITMQ_INIT_DONE_FILE=/var/lib/rabbitmq/initialization.done
+
+ENTRYPOINT ["/usr/local/bin/demo-entrypoint.sh"]
+
+CMD ["rabbitmq-server"]
diff --git a/demo/grouper/mq/container_files/etc-rabbitmq/rabbitmq.conf b/demo/grouper/mq/container_files/etc-rabbitmq/rabbitmq.conf
new file mode 100644
index 0000000..4c789ba
--- /dev/null
+++ b/demo/grouper/mq/container_files/etc-rabbitmq/rabbitmq.conf
@@ -0,0 +1,2 @@
+# Allow guest access from anywhere (change this in production!)
+loopback_users = none
diff --git a/demo/grouper/mq/container_files/usr-local-bin/demo-entrypoint.sh b/demo/grouper/mq/container_files/usr-local-bin/demo-entrypoint.sh
new file mode 100755
index 0000000..7355248
--- /dev/null
+++ b/demo/grouper/mq/container_files/usr-local-bin/demo-entrypoint.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+if [ ! -e $RABBITMQ_INIT_DONE_FILE ]; then
+ /usr/local/bin/initialize-rabbitmq.sh &
+else
+ echo "RabbitMQ was already initialized"
+fi
+/usr/local/bin/entrypoint.sh "$@"
diff --git a/demo/grouper/mq/container_files/usr-local-bin/initialize-rabbitmq.sh b/demo/grouper/mq/container_files/usr-local-bin/initialize-rabbitmq.sh
new file mode 100755
index 0000000..3660e80
--- /dev/null
+++ b/demo/grouper/mq/container_files/usr-local-bin/initialize-rabbitmq.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+
+echo "Executing RabbitMQ initialization"
+echo "Waiting for the server to start up..."
+rabbitmqctl -t 30 wait $RABBITMQ_PID_FILE
+echo "OK, creating sampleQueue..."
+rabbitmqadmin declare queue name=sampleQueue
+echo "Done"
+touch $RABBITMQ_INIT_DONE_FILE
diff --git a/demo/grouper/recompute.sh b/demo/grouper/recompute.sh
new file mode 100755
index 0000000..0d9633e
--- /dev/null
+++ b/demo/grouper/recompute.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+source $(dirname "$0")/../../library.bash
+
+recompute orgs d48ec05b-fffd-4262-acd3-d9ff63365b62
+recompute users e897468f-20bd-419c-8fc5-1fe60e2600de
diff --git a/demo/grouper/show-queue-size.sh b/demo/grouper/show-queue-size.sh
new file mode 100755
index 0000000..0af6d80
--- /dev/null
+++ b/demo/grouper/show-queue-size.sh
@@ -0,0 +1 @@
+docker exec grouper_mq_1 rabbitmqctl list_queues
diff --git a/demo/grouper/sources/Dockerfile b/demo/grouper/sources/Dockerfile
new file mode 100644
index 0000000..a2c5a50
--- /dev/null
+++ b/demo/grouper/sources/Dockerfile
@@ -0,0 +1,10 @@
+FROM tier/mariadb:mariadb10
+
+COPY container_files/seed-data/ /seed-data/
+
+ENV MYSQL_DATABASE sis
+ENV MYSQL_USER sis_user
+ENV MYSQL_PASSWORD 49321420423
+ENV MYSQL_DATADIR /var/lib/mysqlmounted
+ENV AFTER_FIRST_TIME_SQL /seed-data/persons-and-courses.sql
+
diff --git a/demo/grouper/sources/container_files/seed-data/persons-and-courses.sql b/demo/grouper/sources/container_files/seed-data/persons-and-courses.sql
new file mode 100644
index 0000000..65f8376
--- /dev/null
+++ b/demo/grouper/sources/container_files/seed-data/persons-and-courses.sql
@@ -0,0 +1,531 @@
+USE sis;
+
+CREATE TABLE SIS_PERSONS (
+ uid VARCHAR(255) NOT NULL,
+ surname VARCHAR(255) DEFAULT NULL,
+ givenName VARCHAR(255) DEFAULT NULL,
+ fullName VARCHAR(255) DEFAULT NULL,
+ department VARCHAR(255) DEFAULT NULL,
+ mail VARCHAR(255) DEFAULT NULL,
+ PRIMARY KEY (uid)
+);
+
+CREATE TABLE SIS_AFFILIATIONS (
+ uid VARCHAR(255) NOT NULL,
+ affiliation VARCHAR(255) NOT NULL,
+ PRIMARY KEY (uid , affiliation)
+);
+
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jsmith','Smith','Joe','John Smith',NULL,NULL);
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('banderson','Anderson','Bob','Bob Anderson',NULL,NULL);
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('kwhite','White','Karl','Karl White','Law','kwhite@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kwhite','member');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kwhite','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('whenderson','Henderson','William','William Henderson','Advising','whenderson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('whenderson','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('ddavis','Davis','David','David Davis','Computer Science','ddavis@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('ddavis','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('cmorrison','Morrison','Colin','Colin Morrison','Financial Aid','cmorrison@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('cmorrison','member');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('cmorrison','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('danderson','Anderson','Donna','Donna Anderson','Account Payable','danderson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('danderson','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('amorrison','Morrison','Ann','Ann Morrison','Law','amorrison@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('amorrison','student');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('amorrison','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('wprice','Price','William','William Price','Account Payable','wprice@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('wprice','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('mroberts','Roberts','Marie','Marie Roberts','Law','mroberts@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mroberts','student');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mroberts','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('kjohnson','Johnson','Kiersten','Kiersten Johnson','Physical Education','kjohnson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kjohnson','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jbrown','Brown','James','James Brown','Information Technology','jbrown@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jbrown','alum');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jbrown','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('agasper','Gasper','Ann','Ann Gasper','Computer Science','agasper@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('agasper','student');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('agasper','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jscott','Scott','Jennifer','Jennifer Scott','Business','jscott@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jscott','community');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jscott','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('bbutler','Butler','Betty','Betty Butler','Purchasing','bbutler@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('bbutler','community');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('bbutler','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('tmorrison','Morrison','Thomas','Thomas Morrison','Purchasing','tmorrison@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('tmorrison','student');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('tmorrison','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jbrown14','Brown','Jennifer','Jennifer Brown','Accounting','jbrown14@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jbrown14','member');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jbrown14','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('gjohnson','Johnson','Greg','Greg Johnson','Physical Education','gjohnson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('gjohnson','community');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('gjohnson','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('rmartinez','Martinez','Robert','Robert Martinez','Financial Aid','rmartinez@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('rmartinez','staff');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('rmartinez','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jlewis','Lewis','Jo','Jo Lewis','Accounting','jlewis@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jlewis','community');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jlewis','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('mgasper','Gasper','Mary','Mary Gasper','Physical Education','mgasper@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mgasper','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('kvales','Vales','Karoline','Karoline Vales','Information Technology','kvales@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kvales','student');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kvales','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('tgrady','Grady','Thomas','Thomas Grady','Law','tgrady@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('tgrady','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('kmorrison','Morrison','Kiersten','Kiersten Morrison','Information Technology','kmorrison@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kmorrison','staff');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kmorrison','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('dgrady','Grady','David','David Grady','Advising','dgrady@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dgrady','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('mthompson','Thompson','Mary','Mary Thompson','Financial Aid','mthompson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mthompson','staff');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mthompson','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('bgasper','Gasper','Bill','Bill Gasper','Business','bgasper@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('bgasper','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('dlopez','Lopez','David','David Lopez','Account Payable','dlopez@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dlopez','staff');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dlopez','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('hwhite','White','Heather','Heather White','Physical Education','hwhite@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('hwhite','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('ddavis27','Davis','Donna','Donna Davis','Accounting','ddavis27@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('ddavis27','staff');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('ddavis27','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('bgasper28','Gasper','Bill','Bill Gasper','Engineering','bgasper28@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('bgasper28','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jjohnson','Johnson','Jennifer','Jennifer Johnson','Financial Aid','jjohnson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jjohnson','student');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jjohnson','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('amorrison30','Morrison','Ann','Ann Morrison','Financial Aid','amorrison30@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('amorrison30','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('kmartinez','Martinez','Karl','Karl Martinez','Accounting','kmartinez@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kmartinez','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('ahenderson','Henderson','Ann','Ann Henderson','Accounting','ahenderson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('ahenderson','member');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('ahenderson','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('avales','Vales','Ann','Ann Vales','Purchasing','avales@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('avales','student');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('avales','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('ggonazles','Gonazles','Greg','Greg Gonazles','Language Arts','ggonazles@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('ggonazles','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('bdoe','Doe','Blake','Blake Doe','Business','bdoe@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('bdoe','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('plangenberg','Langenberg','Paul','Paul Langenberg','Information Technology','plangenberg@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('plangenberg','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('gvales','Vales','Greg','Greg Vales','Language Arts','gvales@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('gvales','community');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('gvales','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('nhenderson','Henderson','Nancy','Nancy Henderson','Physical Education','nhenderson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('nhenderson','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('wthompson','Thompson','William','William Thompson','Law','wthompson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('wthompson','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('kvales40','Vales','Karl','Karl Vales','Business','kvales40@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kvales40','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('blee','Lee','Bill','Bill Lee','Engineering','blee@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('blee','member');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('blee','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('mlee','Lee','Marie','Marie Lee','Information Technology','mlee@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mlee','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('kclark','Clark','Kiersten','Kiersten Clark','Financial Aid','kclark@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kclark','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('wscott','Scott','William','William Scott','Language Arts','wscott@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('wscott','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('dbutler','Butler','Donna','Donna Butler','Financial Aid','dbutler@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dbutler','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('awhite','White','Ann','Ann White','Purchasing','awhite@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('awhite','faculty');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('awhite','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('hdoe','Doe','Heather','Heather Doe','Financial Aid','hdoe@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('hdoe','community');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('hdoe','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('dlangenberg','Langenberg','David','David Langenberg','Language Arts','dlangenberg@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dlangenberg','alum');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dlangenberg','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('ethompson','Thompson','Eric','Eric Thompson','Law','ethompson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('ethompson','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jbrown50','Brown','Jennifer','Jennifer Brown','Account Payable','jbrown50@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jbrown50','alum');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jbrown50','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('mgonazles','Gonazles','Michael','Michael Gonazles','Computer Science','mgonazles@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mgonazles','student');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mgonazles','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('gbutler','Butler','Greg','Greg Butler','Information Technology','gbutler@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('gbutler','community');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('gbutler','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('mvales','Vales','Mark','Mark Vales','Engineering','mvales@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mvales','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('mlewis','Lewis','Michael','Michael Lewis','Information Technology','mlewis@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mlewis','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('hvales','Vales','Heather','Heather Vales','Information Technology','hvales@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('hvales','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jscott56','Scott','Jo','Jo Scott','Purchasing','jscott56@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jscott56','faculty');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jscott56','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('sdoe','Doe','Sarah','Sarah Doe','Business','sdoe@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('sdoe','member');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('sdoe','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('svales','Vales','Sarah','Sarah Vales','Advising','svales@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('svales','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('hmorrison','Morrison','Heather','Heather Morrison','Engineering','hmorrison@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('hmorrison','faculty');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('hmorrison','student');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jlopez','Lopez','Jennifer','Jennifer Lopez','Language Arts','jlopez@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jlopez','alum');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jlopez','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('dlangenberg61','Langenberg','Donna','Donna Langenberg','Law','dlangenberg61@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dlangenberg61','student');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dlangenberg61','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('bgrady','Grady','Betty','Betty Grady','Accounting','bgrady@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('bgrady','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jmorrison','Morrison','Jennifer','Jennifer Morrison','Law','jmorrison@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jmorrison','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('wvales','Vales','William','William Vales','Law','wvales@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('wvales','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('mmartinez','Martinez','Mark','Mark Martinez','Physical Education','mmartinez@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mmartinez','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jmartinez','Martinez','Jennifer','Jennifer Martinez','Information Technology','jmartinez@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jmartinez','community');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jmartinez','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('mgasper67','Gasper','Mary','Mary Gasper','Computer Science','mgasper67@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('mgasper67','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('dpeterson','Peterson','David','David Peterson','Advising','dpeterson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dpeterson','student');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dpeterson','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('eprice','Price','Erik','Erik Price','Business','eprice@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('eprice','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jgasper','Gasper','James','James Gasper','Accounting','jgasper@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jgasper','staff');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jgasper','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jclark','Clark','Jennifer','Jennifer Clark','Business','jclark@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jclark','faculty');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jclark','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('bpeterson','Peterson','Betty','Betty Peterson','Account Payable','bpeterson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('bpeterson','alum');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('bpeterson','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('wsmith','Smith','William','William Smith','Information Technology','wsmith@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('wsmith','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('lwilliams','Williams','Lisa','Lisa Williams','Purchasing','lwilliams@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('lwilliams','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('dgrady76','Grady','David','David Grady','Physical Education','dgrady76@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dgrady76','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jmartinez77','Martinez','Jo','Jo Martinez','Law','jmartinez77@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jmartinez77','faculty');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jmartinez77','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('dlewis','Lewis','Donna','Donna Lewis','Financial Aid','dlewis@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dlewis','community');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dlewis','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('wscott79','Scott','William','William Scott','Account Payable','wscott79@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('wscott79','faculty');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('wscott79','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('ddoe','Doe','Donna','Donna Doe','Physical Education','ddoe@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('ddoe','student');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('ddoe','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('gmorrison','Morrison','Greg','Greg Morrison','Language Arts','gmorrison@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('gmorrison','staff');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('gmorrison','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('khenderson','Henderson','Kim','Kim Henderson','Account Payable','khenderson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('khenderson','member');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('khenderson','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('kpeterson','Peterson','Karoline','Karoline Peterson','Accounting','kpeterson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kpeterson','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('eprice84','Price','Erik','Erik Price','Computer Science','eprice84@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('eprice84','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('hsmith','Smith','Heather','Heather Smith','Business','hsmith@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('hsmith','faculty');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('hsmith','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('dwilliams','Williams','Donna','Donna Williams','Financial Aid','dwilliams@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dwilliams','alum');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dwilliams','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('klopez','Lopez','Karl','Karl Lopez','Advising','klopez@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('klopez','staff');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('klopez','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('wjohnson','Johnson','William','William Johnson','Accounting','wjohnson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('wjohnson','staff');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('wbrown','Brown','William','William Brown','Physical Education','wbrown@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('wbrown','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('hbrown','Brown','Heather','Heather Brown','Law','hbrown@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('hbrown','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('kroberts','Roberts','Kim','Kim Roberts','Account Payable','kroberts@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('kroberts','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('dwalters','Walters','Donna','Donna Walters','Advising','dwalters@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dwalters','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('nlee','Lee','Nancy','Nancy Lee','Computer Science','nlee@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('nlee','faculty');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('nlee','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('sgonazles','Gonazles','Sarah','Sarah Gonazles','Computer Science','sgonazles@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('sgonazles','faculty');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('handerson','Anderson','Heather','Heather Anderson','Purchasing','handerson@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('handerson','member');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('danderson96','Anderson','David','David Anderson','Advising','danderson96@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('danderson96','alum');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('dgrady97','Grady','David','David Grady','Advising','dgrady97@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('dgrady97','community');
+INSERT INTO SIS_PERSONS (uid, surname, givenName, fullName, department, mail) VALUES ('jgrady','Grady','James','James Grady','Purchasing','jgrady@example.edu');
+INSERT INTO SIS_AFFILIATIONS (uid, affiliation) VALUES ('jgrady','student');
+
+CREATE TABLE SIS_COURSES (
+ uid VARCHAR(255) NOT NULL,
+ surname VARCHAR(255) DEFAULT NULL,
+ givenName VARCHAR(255) DEFAULT NULL,
+ courseId VARCHAR(255) NOT NULL,
+ PRIMARY KEY (uid , courseId)
+);
+
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('agasper','Gasper','Ann','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ahenderson','Henderson','Ann','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ahenderson','Henderson','Ann','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('amorrison','Morrison','Ann','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('amorrison','Morrison','Ann','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('amorrison','Morrison','Ann','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('amorrison30','Morrison','Ann','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('avales','Vales','Ann','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('awhite','White','Ann','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('awhite','White','Ann','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bbutler','Butler','Betty','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bbutler','Butler','Betty','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bbutler','Butler','Betty','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bbutler','Butler','Betty','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bdoe','Doe','Blake','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bdoe','Doe','Blake','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bdoe','Doe','Blake','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bdoe','Doe','Blake','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bgasper','Gasper','Bill','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bgasper','Gasper','Bill','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bgasper28','Gasper','Bill','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bgasper28','Gasper','Bill','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bgrady','Grady','Betty','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bgrady','Grady','Betty','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bgrady','Grady','Betty','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('blee','Lee','Bill','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('blee','Lee','Bill','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('blee','Lee','Bill','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bpeterson','Peterson','Betty','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('bpeterson','Peterson','Betty','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('cmorrison','Morrison','Colin','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('cmorrison','Morrison','Colin','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('cmorrison','Morrison','Colin','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('cmorrison','Morrison','Colin','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('danderson','Anderson','Donna','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('danderson','Anderson','Donna','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('danderson','Anderson','Donna','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('danderson96','Anderson','David','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('danderson96','Anderson','David','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('danderson96','Anderson','David','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('danderson96','Anderson','David','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dbutler','Butler','Donna','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dbutler','Butler','Donna','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dbutler','Butler','Donna','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ddavis','Davis','David','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ddavis','Davis','David','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ddavis27','Davis','Donna','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ddavis27','Davis','Donna','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ddavis27','Davis','Donna','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ddavis27','Davis','Donna','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ddoe','Doe','Donna','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ddoe','Doe','Donna','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ddoe','Doe','Donna','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ddoe','Doe','Donna','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dgrady','Grady','David','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dgrady','Grady','David','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dgrady76','Grady','David','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dgrady76','Grady','David','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dgrady76','Grady','David','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dgrady97','Grady','David','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dgrady97','Grady','David','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlangenberg','Langenberg','David','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlangenberg','Langenberg','David','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlangenberg','Langenberg','David','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlangenberg61','Langenberg','Donna','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlangenberg61','Langenberg','Donna','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlewis','Lewis','Donna','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlewis','Lewis','Donna','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlewis','Lewis','Donna','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlewis','Lewis','Donna','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlopez','Lopez','David','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlopez','Lopez','David','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dlopez','Lopez','David','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dpeterson','Peterson','David','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dpeterson','Peterson','David','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dwalters','Walters','Donna','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dwilliams','Williams','Donna','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('dwilliams','Williams','Donna','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('eprice','Price','Erik','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('eprice','Price','Erik','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('eprice','Price','Erik','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('eprice84','Price','Erik','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ethompson','Thompson','Eric','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ethompson','Thompson','Eric','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ethompson','Thompson','Eric','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ethompson','Thompson','Eric','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gbutler','Butler','Greg','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gbutler','Butler','Greg','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gbutler','Butler','Greg','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ggonazles','Gonazles','Greg','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('ggonazles','Gonazles','Greg','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gjohnson','Johnson','Greg','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gjohnson','Johnson','Greg','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gjohnson','Johnson','Greg','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gmorrison','Morrison','Greg','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gmorrison','Morrison','Greg','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gmorrison','Morrison','Greg','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gvales','Vales','Greg','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gvales','Vales','Greg','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('gvales','Vales','Greg','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('handerson','Anderson','Heather','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hbrown','Brown','Heather','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hbrown','Brown','Heather','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hbrown','Brown','Heather','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hbrown','Brown','Heather','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hdoe','Doe','Heather','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hdoe','Doe','Heather','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hmorrison','Morrison','Heather','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hmorrison','Morrison','Heather','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hmorrison','Morrison','Heather','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hmorrison','Morrison','Heather','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hsmith','Smith','Heather','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hsmith','Smith','Heather','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hsmith','Smith','Heather','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hsmith','Smith','Heather','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hvales','Vales','Heather','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hvales','Vales','Heather','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hvales','Vales','Heather','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hwhite','White','Heather','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hwhite','White','Heather','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('hwhite','White','Heather','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jbrown','Brown','James','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jbrown14','Brown','Jennifer','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jbrown14','Brown','Jennifer','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jbrown50','Brown','Jennifer','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jbrown50','Brown','Jennifer','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jbrown50','Brown','Jennifer','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jclark','Clark','Jennifer','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jclark','Clark','Jennifer','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jgasper','Gasper','James','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jgasper','Gasper','James','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jgasper','Gasper','James','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jgrady','Grady','James','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jgrady','Grady','James','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jjohnson','Johnson','Jennifer','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jjohnson','Johnson','Jennifer','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jjohnson','Johnson','Jennifer','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jjohnson','Johnson','Jennifer','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jlewis','Lewis','Jo','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jlewis','Lewis','Jo','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jlewis','Lewis','Jo','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jlopez','Lopez','Jennifer','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jlopez','Lopez','Jennifer','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jlopez','Lopez','Jennifer','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jmartinez','Martinez','Jennifer','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jmartinez','Martinez','Jennifer','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jmartinez','Martinez','Jennifer','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jmartinez77','Martinez','Jo','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jmorrison','Morrison','Jennifer','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jmorrison','Morrison','Jennifer','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jmorrison','Morrison','Jennifer','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jmorrison','Morrison','Jennifer','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jscott','Scott','Jennifer','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jscott','Scott','Jennifer','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jscott','Scott','Jennifer','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jscott56','Scott','Jo','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('jscott56','Scott','Jo','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kclark','Clark','Kiersten','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kclark','Clark','Kiersten','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kclark','Clark','Kiersten','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('khenderson','Henderson','Kim','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kjohnson','Johnson','Kiersten','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kjohnson','Johnson','Kiersten','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('klopez','Lopez','Karl','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kmartinez','Martinez','Karl','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kmartinez','Martinez','Karl','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kmartinez','Martinez','Karl','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kmorrison','Morrison','Kiersten','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kpeterson','Peterson','Karoline','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kpeterson','Peterson','Karoline','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kpeterson','Peterson','Karoline','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kpeterson','Peterson','Karoline','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kroberts','Roberts','Kim','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kroberts','Roberts','Kim','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kroberts','Roberts','Kim','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kroberts','Roberts','Kim','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kvales','Vales','Karoline','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kvales','Vales','Karoline','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kvales40','Vales','Karl','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kvales40','Vales','Karl','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kvales40','Vales','Karl','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kvales40','Vales','Karl','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kwhite','White','Karl','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kwhite','White','Karl','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kwhite','White','Karl','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('kwhite','White','Karl','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('lwilliams','Williams','Lisa','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('lwilliams','Williams','Lisa','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('lwilliams','Williams','Lisa','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mgasper','Gasper','Mary','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mgasper','Gasper','Mary','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mgasper','Gasper','Mary','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mgasper','Gasper','Mary','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mgasper67','Gasper','Mary','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mgasper67','Gasper','Mary','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mgasper67','Gasper','Mary','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mgasper67','Gasper','Mary','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mgonazles','Gonazles','Michael','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mlee','Lee','Marie','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mlee','Lee','Marie','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mlee','Lee','Marie','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mlewis','Lewis','Michael','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mlewis','Lewis','Michael','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mlewis','Lewis','Michael','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mlewis','Lewis','Michael','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mmartinez','Martinez','Mark','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mmartinez','Martinez','Mark','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mmartinez','Martinez','Mark','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mmartinez','Martinez','Mark','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mroberts','Roberts','Marie','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mroberts','Roberts','Marie','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mroberts','Roberts','Marie','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mroberts','Roberts','Marie','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mthompson','Thompson','Mary','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mthompson','Thompson','Mary','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mthompson','Thompson','Mary','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mthompson','Thompson','Mary','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mvales','Vales','Mark','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mvales','Vales','Mark','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('mvales','Vales','Mark','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('nhenderson','Henderson','Nancy','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('nlee','Lee','Nancy','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('nlee','Lee','Nancy','CS251');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('nlee','Lee','Nancy','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('nlee','Lee','Nancy','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('plangenberg','Langenberg','Paul','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('rmartinez','Martinez','Robert','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('rmartinez','Martinez','Robert','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('sdoe','Doe','Sarah','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('sdoe','Doe','Sarah','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('sdoe','Doe','Sarah','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('sdoe','Doe','Sarah','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('sgonazles','Gonazles','Sarah','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('sgonazles','Gonazles','Sarah','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('svales','Vales','Sarah','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('svales','Vales','Sarah','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('tgrady','Grady','Thomas','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('tgrady','Grady','Thomas','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('tmorrison','Morrison','Thomas','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('tmorrison','Morrison','Thomas','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('tmorrison','Morrison','Thomas','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wbrown','Brown','William','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('whenderson','Henderson','William','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wjohnson','Johnson','William','CS252');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wjohnson','Johnson','William','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wprice','Price','William','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wprice','Price','William','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wscott','Scott','William','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wscott79','Scott','William','ACCT201');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wscott79','Scott','William','MATH101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wsmith','Smith','William','ACCT101');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wsmith','Smith','William','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wthompson','Thompson','William','SCI123');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wthompson','Thompson','William','SCI404');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wvales','Vales','William','MATH100');
+INSERT INTO SIS_COURSES (uid, surname, givenName, courseId) VALUES ('wvales','Vales','William','SCI123');
+
diff --git a/demo/grouper/test-resources.sh b/demo/grouper/test-resources.sh
new file mode 100755
index 0000000..5551e55
--- /dev/null
+++ b/demo/grouper/test-resources.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+source $(dirname "$0")/../../library.bash
+
+test_resource 0a37121f-d515-4a23-9b6d-554c5ef61272
+test_resource 4d70a0da-02dd-41cf-b0a1-00e75d3eaa15
+test_resource a343fc2e-3954-4034-ba1a-2b72c21e577a
+test_resource e417225d-8a08-46f3-9b5d-624990b52386
+test_resource fe805d13-481b-43ec-97d8-9d2df72cd38e
+test_resource 1eff65de-5bb6-483d-9edf-8cc2c2ee0233
+
diff --git a/demo/grouper/tests/main.bats b/demo/grouper/tests/main.bats
new file mode 100644
index 0000000..4a781f7
--- /dev/null
+++ b/demo/grouper/tests/main.bats
@@ -0,0 +1,355 @@
+#!/usr/bin/env bats
+
+load ../../../common
+load ../../../library
+
+@test "000 Cleanup before running the tests" {
+ (cd ../simple ; docker-compose down -v)
+ (cd ../shibboleth ; docker-compose down -v)
+ (cd ../postgresql ; docker-compose down -v)
+ docker-compose down -v
+}
+
+@test "010 Initialize and start the composition" {
+ # We want to fail cleanly if there's any interference
+ docker ps
+ ! (docker ps | grep -E "shibboleth_(idp|directory)_1|(complex|simple|shibboleth|postgresql)_(midpoint_server|midpoint_data)_1")
+ docker-compose build --pull grouper_daemon grouper_ui grouper_data directory sources targets midpoint_data idp mq
+ # Sometimes the tier/midpoint:xyz is not yet in the repository, causing issues with --pull
+ docker-compose build midpoint_server
+ docker-compose up -d
+}
+
+@test "020 Wait until components are started" {
+ touch $BATS_TMPDIR/not-started
+ wait_for_midpoint_start complex_midpoint_server_1 complex_midpoint_data_1
+ wait_for_shibboleth_idp_start complex_idp_1
+ wait_for_grouper_ui_start complex_grouper_ui_1
+ rm $BATS_TMPDIR/not-started
+}
+
+@test "040 Check midPoint health" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+ check_health
+}
+
+@test "050 Check Shibboleth IDP health" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+ check_health_shibboleth_idp
+}
+
+@test "060 Check Grouper health" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+ skip TODO
+}
+
+@test "100 Get 'administrator'" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+ check_health
+ get_and_check_object users 00000000-0000-0000-0000-000000000002 administrator
+}
+
+@test "110 And and get 'test110'" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+ check_health
+ echo "test110" >/tmp/test110.xml
+ add_object users /tmp/test110.xml
+ rm /tmp/test110.xml
+ search_and_check_object users test110
+ delete_object_by_name users test110
+}
+
+@test "200 Upload objects" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ # reduce data in SIS database so imports will take reasonable time
+ docker exec complex_sources_1 mysql sis -u root -p123321 -e "delete from SIS_COURSES where uid not in ('amorrison', 'banderson', 'cmorrison', 'danderson', 'ddavis', 'jsmith', 'kwhite', 'mroberts', 'whenderson', 'wprice')"
+ docker exec complex_sources_1 mysql sis -u root -p123321 -e "delete from SIS_AFFILIATIONS where uid not in ('amorrison', 'banderson', 'cmorrison', 'danderson', 'ddavis', 'jsmith', 'kwhite', 'mroberts', 'whenderson', 'wprice')"
+ docker exec complex_sources_1 mysql sis -u root -p123321 -e "delete from SIS_PERSONS where uid not in ('amorrison', 'banderson', 'cmorrison', 'danderson', 'ddavis', 'jsmith', 'kwhite', 'mroberts', 'whenderson', 'wprice')"
+
+ check_health
+ ./upload-objects.sh
+
+ search_and_check_object objectTemplates template-org-course
+ search_and_check_object objectTemplates template-org-department
+ search_and_check_object objectTemplates template-role-affiliation
+ search_and_check_object objectTemplates template-role-generic-group
+
+ search_and_check_object orgs courses
+ search_and_check_object orgs departments
+
+ search_and_check_object resources "LDAP (directory)"
+ search_and_check_object resources "Grouper Resource"
+ search_and_check_object resources "SQL SIS courses (sources)"
+ search_and_check_object resources "SQL SIS persons (sources)"
+
+ search_and_check_object roles metarole-affiliation
+ search_and_check_object roles metarole-course
+ search_and_check_object roles metarole-department
+ search_and_check_object roles metarole-generic-group
+ search_and_check_object roles role-grouper-sysadmin
+ search_and_check_object roles role-ldap-basic
+}
+
+@test "210 Test LDAP and SQL resources" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+ test_resource 0a37121f-d515-4a23-9b6d-554c5ef61272
+ test_resource 13660d60-071b-4596-9aa1-5efcd1256c04
+ test_resource 4d70a0da-02dd-41cf-b0a1-00e75d3eaa15
+}
+
+@test "220 Import SIS_PERSONS" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ add_object tasks midpoint-objects-manual/tasks/task-import-sis-persons.xml
+ search_and_check_object tasks "Import from SIS persons"
+ wait_for_task_completion 22c2a3d0-0961-4255-9eec-c550a79aeaaa 6 10
+ assert_task_success 22c2a3d0-0961-4255-9eec-c550a79aeaaa
+
+ search_and_check_object users jsmith
+ search_and_check_object users banderson
+ search_and_check_object users kwhite
+ search_and_check_object users whenderson
+ search_and_check_object users ddavis
+ search_and_check_object users cmorrison
+ search_and_check_object users danderson
+ search_and_check_object users amorrison
+ search_and_check_object users wprice
+ search_and_check_object users mroberts
+
+ check_ldap_account_by_user_name jsmith complex_directory_1
+ check_ldap_account_by_user_name banderson complex_directory_1
+ check_ldap_account_by_user_name kwhite complex_directory_1
+ check_ldap_account_by_user_name whenderson complex_directory_1
+ check_ldap_account_by_user_name ddavis complex_directory_1
+ check_ldap_account_by_user_name cmorrison complex_directory_1
+ check_ldap_account_by_user_name danderson complex_directory_1
+ check_ldap_account_by_user_name amorrison complex_directory_1
+ check_ldap_account_by_user_name wprice complex_directory_1
+ check_ldap_account_by_user_name mroberts complex_directory_1
+}
+
+@test "230 Import SIS_COURSES" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ add_object tasks midpoint-objects-manual/tasks/task-import-sis-courses.xml
+ search_and_check_object tasks "Import from SIS courses"
+ wait_for_task_completion b73a2e66-8233-4c20-928f-acb30027b33e 8 10
+ assert_task_success b73a2e66-8233-4c20-928f-acb30027b33e
+
+ search_and_check_object orgs course_ACCT101
+ search_and_check_object orgs course_ACCT201
+ search_and_check_object orgs course_CS251
+ search_and_check_object orgs course_CS252
+ search_and_check_object orgs course_MATH100
+ search_and_check_object orgs course_MATH101
+ search_and_check_object orgs course_SCI123
+ search_and_check_object orgs course_SCI404
+
+ check_ldap_courses_by_name course_ACCT101 complex_directory_1
+ check_ldap_courses_by_name course_ACCT201 complex_directory_1
+ check_ldap_courses_by_name course_CS251 complex_directory_1
+ check_ldap_courses_by_name course_CS252 complex_directory_1
+ check_ldap_courses_by_name course_MATH100 complex_directory_1
+ check_ldap_courses_by_name course_MATH101 complex_directory_1
+ check_ldap_courses_by_name course_SCI123 complex_directory_1
+ check_ldap_courses_by_name course_SCI404 complex_directory_1
+
+ check_of_ldap_membership amorrison "ou=courses,ou=groups,dc=internet2,dc=edu" "ACCT101" complex_directory_1
+ check_of_ldap_membership cmorrison "ou=courses,ou=groups,dc=internet2,dc=edu" "ACCT101" complex_directory_1
+ check_of_ldap_membership mroberts "ou=courses,ou=groups,dc=internet2,dc=edu" "ACCT101" complex_directory_1
+ check_of_ldap_membership whenderson "ou=courses,ou=groups,dc=internet2,dc=edu" "ACCT101" complex_directory_1
+
+ check_of_ldap_membership amorrison "ou=courses,ou=groups,dc=internet2,dc=edu" "CS251" complex_directory_1
+ check_of_ldap_membership cmorrison "ou=courses,ou=groups,dc=internet2,dc=edu" "CS251" complex_directory_1
+ check_of_ldap_membership ddavis "ou=courses,ou=groups,dc=internet2,dc=edu" "CS251" complex_directory_1
+ check_of_ldap_membership mroberts "ou=courses,ou=groups,dc=internet2,dc=edu" "CS251" complex_directory_1
+
+ check_of_ldap_membership kwhite "ou=courses,ou=groups,dc=internet2,dc=edu" "CS252" complex_directory_1
+
+ check_of_ldap_membership danderson "ou=courses,ou=groups,dc=internet2,dc=edu" "MATH100" complex_directory_1
+ check_of_ldap_membership ddavis "ou=courses,ou=groups,dc=internet2,dc=edu" "MATH100" complex_directory_1
+ check_of_ldap_membership kwhite "ou=courses,ou=groups,dc=internet2,dc=edu" "MATH100" complex_directory_1
+ check_of_ldap_membership wprice "ou=courses,ou=groups,dc=internet2,dc=edu" "MATH100" complex_directory_1
+
+ check_of_ldap_membership amorrison "ou=courses,ou=groups,dc=internet2,dc=edu" "MATH101" complex_directory_1
+ check_of_ldap_membership cmorrison "ou=courses,ou=groups,dc=internet2,dc=edu" "MATH101" complex_directory_1
+ check_of_ldap_membership mroberts "ou=courses,ou=groups,dc=internet2,dc=edu" "MATH101" complex_directory_1
+
+ check_of_ldap_membership danderson "ou=courses,ou=groups,dc=internet2,dc=edu" "SCI123" complex_directory_1
+ check_of_ldap_membership mroberts "ou=courses,ou=groups,dc=internet2,dc=edu" "SCI123" complex_directory_1
+
+ check_of_ldap_membership kwhite "ou=courses,ou=groups,dc=internet2,dc=edu" "SCI404" complex_directory_1
+ check_of_ldap_membership wprice "ou=courses,ou=groups,dc=internet2,dc=edu" "SCI404" complex_directory_1
+}
+
+@test "240 Check 'TestUser240' in Midpoint and LDAP" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+ check_health
+ echo "TestUser240Test User240TestUser240password" >/tmp/testuser240.xml
+ add_object users /tmp/testuser240.xml
+ rm /tmp/testuser240.xml
+ search_and_check_object users TestUser240
+
+ execute_bulk_action tests/resources/bulk-action/recompute-role-grouper-sysadmin.xml complex_midpoint_server_1
+ execute_bulk_action tests/resources/bulk-action/assign-role-grouper-sysadmin-to-test-user.xml complex_midpoint_server_1
+
+ check_ldap_account_by_user_name TestUser240 complex_directory_1
+ check_of_ldap_membership TestUser240 "ou=groups,dc=internet2,dc=edu" "sysadmingroup" complex_directory_1
+
+ delete_object_by_name users TestUser240
+}
+
+@test "250 Make 'banderson' Grouper administrator" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+ check_health
+ recompute roles d48ec05b-fffd-4262-acd3-d9ff63365b62
+ execute_bulk_action tests/resources/bulk-action/assign-role-grouper-sysadmin-to-banderson.xml complex_midpoint_server_1
+ recompute users e897468f-20bd-419c-8fc5-1fe60e2600de # for some reason this looks necessary (TODO)
+ check_of_ldap_membership banderson "ou=groups,dc=internet2,dc=edu" "sysadmingroup" complex_directory_1
+}
+
+#@test "255 Wait 120 seconds for changes to be propagated to Grouper" {
+# if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+#
+# sleep 120
+#}
+
+@test "260 Export ref groups" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ ./add-ref-groups.sh
+}
+
+@test "265 Wait 120 seconds for changes to be propagated to MQ" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ sleep 120
+}
+
+@test "300 Test Grouper resource" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+ test_resource 1eff65de-5bb6-483d-9edf-8cc2c2ee0233
+}
+
+@test "310 Import Grouper-to-midPoint async update task" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ check_health
+ add_object tasks midpoint-objects-manual/tasks/task-async-update-grouper.xml
+ search_and_check_object tasks "Grouper async updates"
+}
+
+@test "320 Wait for the queue to become empty" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ ATTEMPT=0
+ MAX_ATTEMPTS=20
+ DELAY=10
+
+ get_messages sampleQueue
+ echo "Messages: $MESSAGES"
+
+ until [[ $ATTEMPT = $MAX_ATTEMPTS ]]; do
+ ATTEMPT=$((ATTEMPT+1))
+ get_messages sampleQueue
+ echo "Messages: $MESSAGES"
+ if [ "$MESSAGES" = "0" ]; then return 0; fi
+ echo "Waiting $DELAY seconds for the queue to become empty (attempt $ATTEMPT) ..."
+ sleep $DELAY
+ done
+ return 1
+}
+
+@test "330 Add wprice to 'midpoint:test' and 'ref:affiliation:alum_includes' groups" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ docker cp tests/resources/grouper/t330.gsh complex_grouper_daemon_1:/tmp/
+ docker exec complex_grouper_daemon_1 bash -c "/opt/grouper/grouper.apiBinary/bin/gsh /tmp/t330.gsh"
+}
+
+@test "335 Wait 80 seconds for changes to be propagated to MQ" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ sleep 80
+}
+
+@test "340 Assert wprice membership in LDAP" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ assert_ldap_user_has_value wprice Entitlement "midpoint:test" complex_directory_1
+ assert_ldap_user_has_value wprice Entitlement "ref:affiliation:alum" complex_directory_1
+}
+
+@test "350 Add kwhite to 'midpoint:test', remove wprice from 'ref:affiliation:alum_includes'" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ docker cp tests/resources/grouper/t350.gsh complex_grouper_daemon_1:/tmp/
+ docker exec complex_grouper_daemon_1 bash -c "/opt/grouper/grouper.apiBinary/bin/gsh /tmp/t350.gsh"
+}
+
+@test "355 Wait 80 seconds for changes to be propagated to MQ" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ sleep 80
+}
+
+@test "360 Assert wprice and kwhite membership in LDAP" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ assert_ldap_user_has_value kwhite Entitlement "midpoint:test" complex_directory_1
+ assert_ldap_user_has_value wprice Entitlement "midpoint:test" complex_directory_1
+ assert_ldap_user_has_no_value wprice Entitlement "ref:affiliation:alum" complex_directory_1
+}
+
+@test "400 Suspend async update task" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ suspend_task 47fc57bd-8c34-4555-9b9f-7087ff179860 complex_midpoint_server_1
+ wait_for_task_completion 47fc57bd-8c34-4555-9b9f-7087ff179860 5 10
+}
+
+@test "410 Remove kwhite and wprice from 'midpoint:test'" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ docker cp tests/resources/grouper/t410.gsh complex_grouper_daemon_1:/tmp/
+ docker exec complex_grouper_daemon_1 bash -c "/opt/grouper/grouper.apiBinary/bin/gsh /tmp/t410.gsh"
+}
+
+@test "420 Reconcile Grouper" {
+ if [ -e $BATS_TMPDIR/not-started ]; then skip 'not started'; fi
+
+ add_object tasks midpoint-objects-manual/tasks/task-reconciliation-grouper-users.xml
+ search_and_check_object tasks "Grouper reconciliation (users)"
+ wait_for_task_completion 42aa9f43-64c5-41a6-814c-b58b9ea4e204 6 10
+ assert_task_success 42aa9f43-64c5-41a6-814c-b58b9ea4e204
+
+ search_and_check_object users jsmith
+ search_and_check_object users banderson
+ search_and_check_object users kwhite
+ search_and_check_object users whenderson
+ search_and_check_object users ddavis
+ search_and_check_object users cmorrison
+ search_and_check_object users danderson
+ search_and_check_object users amorrison
+ search_and_check_object users wprice
+ search_and_check_object users mroberts
+
+ check_ldap_account_by_user_name jsmith complex_directory_1
+ check_ldap_account_by_user_name banderson complex_directory_1
+ check_ldap_account_by_user_name kwhite complex_directory_1
+ check_ldap_account_by_user_name whenderson complex_directory_1
+ check_ldap_account_by_user_name ddavis complex_directory_1
+ check_ldap_account_by_user_name cmorrison complex_directory_1
+ check_ldap_account_by_user_name danderson complex_directory_1
+ check_ldap_account_by_user_name amorrison complex_directory_1
+ check_ldap_account_by_user_name wprice complex_directory_1
+ check_ldap_account_by_user_name mroberts complex_directory_1
+
+ assert_ldap_user_has_no_value wprice Entitlement "midpoint:test" complex_directory_1
+ assert_ldap_user_has_no_value kwhite Entitlement "midpoint:test" complex_directory_1
+}
+
+@test "999 Clean up" {
+ docker-compose down -v
+}
diff --git a/demo/grouper/tests/resources/bulk-action/assign-role-grouper-sysadmin-to-banderson.xml b/demo/grouper/tests/resources/bulk-action/assign-role-grouper-sysadmin-to-banderson.xml
new file mode 100644
index 0000000..9ec69a2
--- /dev/null
+++ b/demo/grouper/tests/resources/bulk-action/assign-role-grouper-sysadmin-to-banderson.xml
@@ -0,0 +1,22 @@
+
+
+ c:UserType
+
+
+ c:name
+ banderson
+
+
+
+ assign
+
+ role
+ d48ec05b-fffd-4262-acd3-d9ff63365b62
+
+
+
+
diff --git a/demo/grouper/tests/resources/bulk-action/assign-role-grouper-sysadmin-to-test-user.xml b/demo/grouper/tests/resources/bulk-action/assign-role-grouper-sysadmin-to-test-user.xml
new file mode 100644
index 0000000..0cb1a6b
--- /dev/null
+++ b/demo/grouper/tests/resources/bulk-action/assign-role-grouper-sysadmin-to-test-user.xml
@@ -0,0 +1,22 @@
+
+
+ c:UserType
+
+
+ c:name
+ TestUser240
+
+
+
+ assign
+
+ role
+ d48ec05b-fffd-4262-acd3-d9ff63365b62
+
+
+
+
diff --git a/demo/grouper/tests/resources/bulk-action/recompute-role-grouper-sysadmin.xml b/demo/grouper/tests/resources/bulk-action/recompute-role-grouper-sysadmin.xml
new file mode 100644
index 0000000..1356484
--- /dev/null
+++ b/demo/grouper/tests/resources/bulk-action/recompute-role-grouper-sysadmin.xml
@@ -0,0 +1,16 @@
+
+
+ c:RoleType
+
+
+ name
+ role-grouper-sysadmin
+
+
+
+ recompute
+
+
+
diff --git a/demo/grouper/tests/resources/grouper/t300.gsh b/demo/grouper/tests/resources/grouper/t300.gsh
new file mode 100644
index 0000000..d2b63e3
--- /dev/null
+++ b/demo/grouper/tests/resources/grouper/t300.gsh
@@ -0,0 +1,15 @@
+System.out.println("************** t300.gsh starting **************");
+
+gs = GrouperSession.startRootSession()
+
+exportedGroups = GroupFinder.findByName(gs, 'etc:exportedGroups')
+alumSubject = SubjectFinder.findByIdentifier('ref:affiliation:alum', 'group', 'g:gsa')
+exportedGroups.addMember(alumSubject, false)
+
+alumIncludes = GroupFinder.findByName(gs, 'ref:affiliation:alum_includes')
+testGroup = GroupFinder.findByName(gs, 'etc:testGroup')
+wprice = SubjectFinder.findById('wprice', 'person', 'ldap')
+alumIncludes.addMember(wprice, false)
+testGroup.addMember(wprice, false)
+
+System.out.println("************** t300.gsh done **************");
diff --git a/demo/grouper/tests/resources/grouper/t330.gsh b/demo/grouper/tests/resources/grouper/t330.gsh
new file mode 100644
index 0000000..cb8f158
--- /dev/null
+++ b/demo/grouper/tests/resources/grouper/t330.gsh
@@ -0,0 +1,11 @@
+System.out.println("************** t330.gsh starting **************");
+
+gs = GrouperSession.startRootSession()
+
+testGroup = GroupFinder.findByName(gs, 'midpoint:test')
+alumIncludesGroup = GroupFinder.findByName(gs, 'ref:affiliation:alum_includes')
+wprice = SubjectFinder.findById('wprice', 'person', 'ldap')
+testGroup.addMember(wprice, false)
+alumIncludesGroup.addMember(wprice, false)
+
+System.out.println("************** t330.gsh done **************");
diff --git a/demo/grouper/tests/resources/grouper/t350.gsh b/demo/grouper/tests/resources/grouper/t350.gsh
new file mode 100644
index 0000000..d0d2d3e
--- /dev/null
+++ b/demo/grouper/tests/resources/grouper/t350.gsh
@@ -0,0 +1,12 @@
+System.out.println("************** t350.gsh starting **************");
+
+gs = GrouperSession.startRootSession()
+
+alumIncludes = GroupFinder.findByName(gs, 'ref:affiliation:alum_includes')
+testGroup = GroupFinder.findByName(gs, 'midpoint:test')
+kwhite = SubjectFinder.findById('kwhite', 'person', 'ldap')
+wprice = SubjectFinder.findById('wprice', 'person', 'ldap')
+testGroup.addMember(kwhite, false)
+alumIncludes.deleteMember(wprice, false)
+
+System.out.println("************** t350.gsh done **************");
diff --git a/demo/grouper/tests/resources/grouper/t410.gsh b/demo/grouper/tests/resources/grouper/t410.gsh
new file mode 100644
index 0000000..69e4b18
--- /dev/null
+++ b/demo/grouper/tests/resources/grouper/t410.gsh
@@ -0,0 +1,11 @@
+System.out.println("************** t410.gsh starting **************");
+
+gs = GrouperSession.startRootSession()
+
+testGroup = GroupFinder.findByName(gs, 'midpoint:test')
+kwhite = SubjectFinder.findById('kwhite', 'person', 'ldap')
+wprice = SubjectFinder.findById('wprice', 'person', 'ldap')
+testGroup.deleteMember(kwhite, false)
+testGroup.deleteMember(wprice, false)
+
+System.out.println("************** t410.gsh done **************");
diff --git a/demo/grouper/tests/resources/rabbitmq/check-samplequeue.sh b/demo/grouper/tests/resources/rabbitmq/check-samplequeue.sh
new file mode 100755
index 0000000..e336a63
--- /dev/null
+++ b/demo/grouper/tests/resources/rabbitmq/check-samplequeue.sh
@@ -0,0 +1,8 @@
+count=$(rabbitmqctl list_queues | grep sampleQueue | awk '{print $2}')
+if [[ -z $count || $count -eq 0 ]]; then
+ echo "ERROR: sampleQueue does not exist or is empty"
+ exit 1
+else
+ echo "OK: sampleQueue has $count message(s)"
+ exit 0
+fi
diff --git a/demo/grouper/tests/resources/tasks/task-livesync-grouper-single.xml b/demo/grouper/tests/resources/tasks/task-livesync-grouper-single.xml
new file mode 100644
index 0000000..365d007
--- /dev/null
+++ b/demo/grouper/tests/resources/tasks/task-livesync-grouper-single.xml
@@ -0,0 +1,29 @@
+
+ LiveSync from Grouper
+
+ account
+ ri:AccountObjectClass
+
+ 1535465478027-0-1
+
+ runnable
+ LiveSynchronization
+ http://midpoint.evolveum.com/xml/ns/public/model/synchronization/task/live-sync/handler-3
+
+ single
+ loose
+
diff --git a/demo/grouper/tests/resources/users/user-grouper-admin.xml b/demo/grouper/tests/resources/users/user-grouper-admin.xml
new file mode 100644
index 0000000..d785e47
--- /dev/null
+++ b/demo/grouper/tests/resources/users/user-grouper-admin.xml
@@ -0,0 +1,20 @@
+
+ grouper-admin
+
+
+
+
+
+ Grouper admin
+ Grouper
+ Admin
+
+
+ password
+
+
+
+
diff --git a/demo/grouper/update-bgasper-in-grouper.gsh b/demo/grouper/update-bgasper-in-grouper.gsh
new file mode 100644
index 0000000..b0ed0b2
--- /dev/null
+++ b/demo/grouper/update-bgasper-in-grouper.gsh
@@ -0,0 +1,13 @@
+
+def add(gs,groupName,subject) {
+ GroupFinder.findByName(gs, groupName, true).addMember(subject, false)
+}
+
+gs = GrouperSession.startRootSession()
+
+def bgasper = SubjectFinder.findById('bgasper', 'user', 'ldap')
+add(gs, 'ref:affiliation:alum_excludes', bgasper)
+add(gs, 'ref:affiliation:faculty_includes', bgasper)
+add(gs, 'app:mailinglist:chess', bgasper)
+add(gs, 'app:mailinglist:idm-fans', bgasper)
+add(gs, 'test:volunteers', bgasper)
diff --git a/demo/grouper/update-bgasper-in-grouper.sh b/demo/grouper/update-bgasper-in-grouper.sh
new file mode 100755
index 0000000..31abf04
--- /dev/null
+++ b/demo/grouper/update-bgasper-in-grouper.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ../../library.bash
+
+execute_gsh grouper_grouper_daemon_1 update-bgasper-in-grouper.gsh
diff --git a/demo/grouper/upload-async-update-task.sh b/demo/grouper/upload-async-update-task.sh
new file mode 100755
index 0000000..bdf8ba2
--- /dev/null
+++ b/demo/grouper/upload-async-update-task.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ../../library.bash
+
+upload_from_file midpoint-objects-manual/tasks/task-async-update-grouper.xml
diff --git a/demo/grouper/upload-import-sis-persons.sh b/demo/grouper/upload-import-sis-persons.sh
new file mode 100755
index 0000000..058c9af
--- /dev/null
+++ b/demo/grouper/upload-import-sis-persons.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ../../library.bash
+
+upload_from_file midpoint-objects-manual/tasks/task-import-sis-persons.xml
diff --git a/demo/grouper/upload-objects.sh b/demo/grouper/upload-objects.sh
new file mode 100755
index 0000000..3f1c9b8
--- /dev/null
+++ b/demo/grouper/upload-objects.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+function upload () {
+ local filename=$1
+ local regex="midpoint-objects/(.*)/(.*)"
+ if [[ $filename =~ $regex ]]
+ then
+ type="${BASH_REMATCH[1]}"
+ oid=`cat $filename | sed -n 's:.*oid=\"\([A-Za-z0-9\-]*\)\".*:\1:p' | sed -n '1 p'`
+ echo "Uploading $filename ($type, $oid)"
+ curl -k --user administrator:5ecr3t -H "Content-Type: application/xml" -X PUT "https://localhost:8443/midpoint/ws/rest/$type/$oid?options=overwrite&options=raw" --data-binary @$filename
+ else
+ echo "Skipping $filename"
+ fi
+}
+
+find midpoint-objects -name "*.xml" | while read filename; do upload $filename; done
diff --git a/demo/grouper/upload-recompute-users.sh b/demo/grouper/upload-recompute-users.sh
new file mode 100755
index 0000000..42b5551
--- /dev/null
+++ b/demo/grouper/upload-recompute-users.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ../../library.bash
+
+upload_from_file midpoint-objects-manual/tasks/task-recomputation-users.xml
diff --git a/demo/grouper/upload-reconcile-grouper-groups.sh b/demo/grouper/upload-reconcile-grouper-groups.sh
new file mode 100755
index 0000000..94deb18
--- /dev/null
+++ b/demo/grouper/upload-reconcile-grouper-groups.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+source ../../library.bash
+
+upload_from_file midpoint-objects-manual/tasks/task-reconciliation-grouper-groups.xml