# # 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. # ######################################## ## Config chaining hierarchy ## Grouper loader uses Grouper Configuration Overlays (documented on wiki) ## By default the configuration is read from grouper-loader.base.properties ## (which should not be edited), and the grouper-loader.properties overlays ## the base settings. See the grouper-loader.base.properties for the possible ## settings that can be applied to the grouper.properties ######################################## # comma separated config files that override each other (files on the right override the left) # each should start with file: or classpath: # e.g. classpath:grouper-loader.example.properties, file:c:/something/myconfig.properties # {valueType: "string", required: true, multiple: true} loader.config.hierarchy = classpath:grouper-loader.base.properties, classpath:grouper-loader.properties, database:grouper # seconds between checking to see if the config files are updated # {valueType: "integer", required: true} loader.config.secondsBetweenUpdateChecks = 600 ######################################## ## General settings ######################################## # auto-add grouper loader types and attributes when grouper starts up if they are not there # {valueType: "boolean", required: true} loader.autoadd.typesAttributes = true # if a transaction should be used when loading groups. If not, then # commits will happen as the group is loaded (and memory usage might be # less intensive, and caching settings need to be set right) # {valueType: "boolean", required: true} loader.use.transactions = false # if should use threads in the loader for add/remove member # {valueType: "boolean", required: true} loader.use.membershipThreads=true # number of threads to use for each group job (not shared among jobs) # {valueType: "integer", required: true} loader.membershipThreadPoolSize=10 # if should use threads in the loader for each group in a group of groups # {valueType: "boolean", required: true} loader.use.groupThreads=true # number of threads to use for each list of groups job (not shared among jobs) # {valueType: "integer", required: true} loader.groupThreadPoolSize=20 # if should use threads in incremental loader jobs # {valueType: "boolean", required: true} loader.incrementalThreads=true # number of threads to use in incremental loader jobs (not shared among jobs) # {valueType: "integer", required: true} loader.incrementalThreadPoolSize=10 # number of days to retain db logs in table grouperloader_log. -1 is forever. default is 7 # {valueType: "integer", required: true} loader.retain.db.logs.days=7 # number of days to retain db rows in grouper_change_log_entry. -1 is forever. default is 14 # {valueType: "integer", required: true} loader.retain.db.change_log_entry.days=14 # if daemon should remove old values which are multi-assigned if the attribute is single valued # {valueType: "boolean", required: true} loader.removeMultiAttributeValuesIfSingleValuedAttribute = true # if daemon should remove old values which are multi-assigned if the attribute is single valued # {valueType: "boolean", required: true} loader.removeMultiAttributeValuesIfSingleValuedAttributeLogOnly = true # if daemon should remove old assignments which are multi-assigned if the attribute is single assign # {valueType: "boolean", required: true} loader.removeMultiAttributeAssignIfSingleAssignAttribute = true # if daemon should remove old assignments which are multi-assigned if the attribute is single assign # {valueType: "boolean", required: true} loader.removeMultiAttributeAssignIfSingleAssignAttributeLogOnly = true # if you want queries which do not specify subject source to come from a certain # source, specify here (improves performance so it doesnt search through all sources) # {valueType: "string"} default.subject.source.id = #if using a sql table, and specifying the name like string, then should the group (in addition to memberships) # be removed if not used anywhere else? # {valueType: "boolean", required: true} loader.sqlTable.likeString.removeGroupIfNotUsed = true # if using a sql table, and specifying the name like string, then should the group be removed even when the group is member of some other group. # loader.sqlTable.likeString.removeGroupIfNotUsed has to be true for this to work # https://bugs.internet2.edu/jira/browse/GRP-1132 # {valueType: "boolean", required: true} loader.sqlTable.likeString.removeGroupIfMemberOfAnotherGroup = false # by default the top folder for an ldap group of groups is the folder where the config group lives. # set to false if you want to be able to provision groups to anywhere # {valueType: "boolean", required: true} loader.ldap.requireTopStemAsStemFromConfigGroup = true # if you dont specify a groupNameExpression, groups will be loaded into this folder # if this property doesnt exist, it will be groups: if it is blank, then there is no top level folder # e.g. loader:groups # {valueType: "string"} loader.ldap.defaultGroupFolder = groups: # Delimiter used in the example edu.internet2.middleware.grouper.app.loader.ldap.LdapResultsTransformationDelimitedValueExample # {valueType: "string"} loader.ldap.resultsTransformationDelimitedValueExampleDelimiter = - # Comma separated list of stems under which the display name changes in stems are allowed. # eg: loader.allowStemDisplayNameChangesUnderStems=school:courses:english, school:faculty # {valueType: "stem", multiple: true} loader.allowStemDisplayNameChangesUnderStems = # If a job creates or updates a group, and the job parameters do not compute # a description, true if a blank description is allowed. If false, the description will # be set to "{groupExtension} auto-created by grouperLoader". # {valueType: "boolean", required: false} loader.allowBlankGroupDescriptions = false # fix include excludes on each run # {valueType: "boolean", required: true} loader.fixIncludeExcludes = false #potentially delete groups that are no longer in the source system # {valueType: "boolean", required: true} loader.deleteGroupsNoLongerInSource = false # if a loader is registered to update the loader log table periodically, do this after this many seconds # {valueType: "integer", defaultValue: "60"} loader.otherJobUpdateLoaderLogDbAfterSeconds = 60 ############################################ ## Auditing lifetimes ############################################ # number of days to retain db rows in grouper_audit_entry with no logged in user (loader, gsh, etc). -1 is forever. suggested is 365 or five years: 1825. Default is -1 # audit entries with no logged in user aren't really all that useful. There is point in time data still. So removing these shouldn't be a big deal # {valueType: "integer", required: true} loader.retain.db.audit_entry_no_logged_in_user.days=-1 # number of days to retain db rows in grouper_audit_entry. -1 is forever. suggested is -1 or ten years: 3650 # Some think its ok to remove all audit entries over 10 (or X) years, but will default this # to never since even at large institutions there aren't that many records. # These are audits for things people do on the UI or WS generally (as a different to records with no logged in user) # {valueType: "integer", required: true} loader.retain.db.audit_entry.days=-1 # number of days to retain db rows for point in time deleted objects. -1 is forever. suggested is 365 or five years: 1825. Default is -1 # After you delete an object in grouper, it is still in point in time. So if you want to know who # was in a group a year ago, you need this info # However, after some time it might be ok to let it go. So the default is 5 years # {valueType: "integer", required: true} loader.retain.db.point_in_time_deleted_objects.days=-1 # number of days after a subfolder (directly in a parent folder) is created that it will be obliterated (deleted) # and point in time will be deleted too. # "courses" or "anotherLabel" are variables you make up in these examples # This is optional. You can automatically obliterate folders *directly in a parent folder* that are a certain age old e.g. courses. # so you could delete a term of courses 4 years old if you like. Note, make sure the loader isn't going to recreate or you will get churn # Note this can also delete the point in time data as well. # {valueType: "integer", required: true, regex: "^loader\\.retain\\.db\\.folder\\.([^.]+)\\.days$"} #loader.retain.db.folder.courses.days=1825 # delete old folders in this folder # {valueType: "stem", required: true, regex: "^loader\\.retain\\.db\\.folder\\.([^.]+)\\.parentFolderName$"} #loader.retain.db.folder.courses.parentFolderName=my:folder:for:courses # if also delete point in time for this old folder # {valueType: "boolean", required: true, regex: "^loader\\.retain\\.db\\.folder\\.([^.]+)\\.deletePointInTime$"} #loader.retain.db.folder.courses.deletePointInTime=true # number of days after a subfolder (directly in a parent folder) is created that it will be obliterated (deleted) # and point in time will be deleted too. # "courses" or "anotherLabel" are variables you make up in these examples # This is optional. You can automatically obliterate folders *directly in a parent folder* that are a certain age old e.g. courses. # so you could delete a term of courses 4 years old if you like. Note, make sure the loader isn't going to recreate or you will get churn # Note this can also delete the point in time data as well. # {valueType: "integer", required: true, regex: "^loader\\.retain\\.db\\.folder\\.([^.]+)\\.days$"} #loader.retain.db.folder.anotherLabel.days=1825 # delete old folders in this folder # {valueType: "stem", required: true, regex: "^loader\\.retain\\.db\\.folder\\.([^.]+)\\.parentFolderName$"} #loader.retain.db.folder.anotherLabel.parentFolderName=my:folder:for:something # if also delete point in time for this old folder # {valueType: "boolean", required: true, regex: "^loader\\.retain\\.db\\.folder\\.([^.]+)\\.deletePointInTime$"} #loader.retain.db.folder.anotherLabel.deletePointInTime=false ###################################### ## Fail-safe 1 - Each individual group ###################################### # if the loader should check to see too many users were removed, if so, then error out and # wait for manual intervention # {valueType: "boolean", required: true} loader.failsafe.use = false # if a group has a size less than this (default 200), then make changes including blanking it out # {valueType: "integer", required: true} loader.failsafe.minGroupSize = 200 # if a group with more members than the loader.failsafe.minGroupSize have more than this percent (default 30) # removed, then log it as error, fail the job, and don't actually remove the members # In order to run the job, an admin would need to change this param in the config, # and run the job manually, then change this config back # {valueType: "integer", required: true} loader.failsafe.maxPercentRemove = 30 ############################################ ## Fail-safe 2 - Group list - managed groups ############################################ # For group lists, if groupLikeString is specified, you can use this fail-safe to prevent too # many groups from having their memberships cleared out because they are managed by the loader # (i.e. match the groupLikeString) but don't have memberships in the group query. # {valueType: "boolean", required: true} loader.failsafe.groupList.managedGroups.use = false # Only applicable if the number of managed groups (i.e. match the groupLikeString) that have # members in Grouper before the loader starts is at least this amount. # {valueType: "integer", required: true} loader.failsafe.groupList.managedGroups.minManagedGroups = 200 # If the group list meets the criteria above and the percentage of groups that are managed by # the loader (i.e. match the groupLikeString) that currently have members in Grouper but # wouldn't after the job runs is greater than this percentage, then don't remove members, # log it as an error and fail the job. An admin would need to change this param in the config, # and run the job manually, then change this config back. # {valueType: "integer", required: true} loader.failsafe.groupList.managedGroups.maxPercentRemove = 30 ################################# ## Performance enhancements ################################# # if you want to bulk retrieve subjects to add/remove # {valueType: "boolean", required: true} loader.bulkLookupSubjects = true # If the bulk lookup should use lazy subjects to avoid actual subject lookups in the subject source. This is mainly beneficial if your subject source includes an LDAP. # {valueType: "boolean", required: true} loader.bulkLookupSubjectsAsLazySubjects = true ######################### ## Unresolvables ######################### # If there are unresolvables while loading a group from the source data, the job will still # have a result of SUCCESS unless the total membership count (with unresolvables) is # greater than or equal to minGroupSize and the percentage of unresolvables is greater than # the percent specified, in which case the result will be SUBJECT_PROBLEMS. # {valueType: "integer", required: true} loader.unresolvables.minGroupSize = 200 # If there are unresolvables while loading a group from the source data, the job will still # have a result of SUCCESS unless the total membership count (with unresolvables) is # greater than or equal to minGroupSize and the percentage of unresolvables is greater than # the percent specified, in which case the result will be SUBJECT_PROBLEMS. # {valueType: "integer", required: true} loader.unresolvables.maxPercentForSuccess = 5 ################################# ## DB connections ## specify the db connection with user, pass, url, and driver class ## the string after "db." is the name of the connection, and it should not have ## spaces or other special chars in it ################################# # specify the db connection with user, pass, url, and driver class # the string after "db." is the name of the connection, and it should not have # spaces or other special chars in it. eg: mylogin # {valueType: "string", required: true, regex: "^db\\.([^.]+)\\.user$"} # db.warehouse.user = #note the password can be stored encrypted in an external file # {valueType: "password", sensitive: true, regex: "^db\\.([^.]+)\\.pass$"} #db.warehouse.pass = # url for database connections. eg: jdbc:mysql://localhost:3306/grouper # {valueType: "string", required: true, regex: "^db\\.([^.]+)\\.url$"} #db.warehouse.url = # note: you probably dont have to enter a driver, it will detect from URL. If it # cant detect, then specify it here # {valueType: "string", regex: "^db\\.([^.]+)\\.driver$"} #db.warehouse.driver = #optional pooling params, these will default to the grouper.hibernate(.base).properties pooling settings. eg: 100 # {valueType: "integer", regex: "^db\\.([^.]+)\\.c3p0\\.max_size$"} #db.warehouse.c3p0.max_size = # optional pooling param. eg: 0 # {valueType: "integer", regex: "^db\\.([^.]+)\\.c3p0\\.min_size$"} #db.warehouse.c3p0.min_size = # seconds. eg: 100 # {valueType: "integer", regex: "^db\\.([^.]+)\\.c3p0\\.timeout$"} #db.warehouse.c3p0.timeout = # maximum statements. eg: 0 # {valueType: "integer", regex: "^db\\.([^.]+)\\.c3p0\\.max_statements$"} #db.warehouse.c3p0.max_statements = # idle test period. eg: 100 # {valueType: "integer", regex: "^db\\.([^.]+)\\.c3p0\\.idle_test_period$"} #db.warehouse.c3p0.idle_test_period = # acquire in increments of. eg: 1 # {valueType: "integer", regex: "^db\\.([^.]+)\\.c3p0\\.acquire_increment$"} #db.warehouse.c3p0.acquire_increment = # validate connection # {valueType: "boolean", regex: "^db\\.([^.]+)\\.c3p0\\.validate$"} #db.warehouse.c3p0.validate = # if unreturnedConnectionTimeout is non zero, then if connection takes too long it will be logged as stack # {valueType: "boolean", regex: "^db\\.([^.]+)\\.c3p0\\.debugUnreturnedConnectionStackTraces$"} # db.warehouse.c3p0.debugUnreturnedConnectionStackTraces = # in seconds, if connections are removed from the pool for longer than this, # and debugUnreturnedConnectionStackTraces is true, then log the stack of who took the connection (and didnt return it). eg: 30 # {valueType: "integer", regex: "^db\\.([^.]+)\\.c3p0\\.unreturnedConnectionTimeout$"} # db.warehouse.c3p0.unreturnedConnectionTimeout = # if this database connector is enabled # {valueType: "boolean", regex: "^db\\.([^.]+)\\.enabled$", defaultValue: "true"} #db.warehouse.enabled = # testQuery to test the connection. If its a known database type a default query might be known # {valueType: "string", regex: "^db\\.([^.]+)\\.testQuery$"} #db.warehouse.testQuery = # When testing the connection in the UI, this is the expected value from sql # {valueType: "string", regex: "^db\\.([^.]+)\\.testExpectedValue$"} # db.warehouse.testExpectedValue = # if the db connections should be pooled (this is new as of 2.3.0.patch) # {valueType: "boolean", required: true} grouperLoader.db.connections.pool = true ################################# ## 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" ################################# # 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. # 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 # You might not want to specify the base dn here. If you do then all ldap filters will use this base dn. # {valueType: "string", required: true, regex: "^ldap\\.([^.]+)\\.url$"} #ldap.personLdap.url = # load this ldaptive config file before the configs here. load from classpath. eg: ldap.personLdap.properties # {valueType: "string", regex: "^ldap\\.([^.]+)\\.configFileFromClasspath$"} #ldap.personLdap.configFileFromClasspath = #optional, if authenticated. eg: uid=someapp,ou=people,dc=myschool,dc=edu # {valueType: "string", regex: "^ldap\\.([^.]+)\\.user$"} #ldap.personLdap.user = #optional, if authenticated, note the password can be stored encrypted in an external file # {valueType: "password", sensitive: true, regex: "^ldap\\.([^.]+)\\.pass$"} #ldap.personLdap.pass = #optional, if you are using tls, set this to true. Generally you will not be using an SSL URL to use TLS. # {valueType: "boolean", regex: "^ldap\\.([^.]+)\\.tls$", defaultValue: "true"} #ldap.personLdap.tls = # optional, if this ldap connector is an active directory # {valueType: "boolean", regex: "^ldap\\.([^.]+)\\.isActiveDirectory$", defaultValue: "false"} #ldap.personLdap.isActiveDirectory = #optional, if using sasl # {valueType: "string", regex: "^ldap\\.([^.]+)\\.saslAuthorizationId$"} #ldap.personLdap.saslAuthorizationId = #optional, if using sasl # {valueType: "string", regex: "^ldap\\.([^.]+)\\.saslRealm$"} #ldap.personLdap.saslRealm = # When testing the connection in the UI, this is the search dn, e.g. ou=People,dc=example,dc=edu # {valueType: "string", regex: "^ldap\\.([^.]+)\\.uiTestSearchDn$"} # ldap.personLdap.uiTestSearchDn = # When testing the connection in the UI, this is the search scope # {valueType: "string", regex: "^ldap\\.([^.]+)\\.uiTestSearchScope$", formElement: "dropdown", optionValues: ["OBJECT_SCOPE", "ONELEVEL_SCOPE", "SUBTREE_SCOPE"]} # ldap.personLdap.uiTestSearchScope = # When testing the connection in the UI, this is the search filter, e.g. (uid=aanderson) # {valueType: "string", regex: "^ldap\\.([^.]+)\\.uiTestFilter$"} # ldap.personLdap.uiTestFilter = # When testing the connection in the UI, this is the search attribute name, e.g. cn # {valueType: "string", regex: "^ldap\\.([^.]+)\\.uiTestAttributeName$"} # ldap.personLdap.uiTestAttributeName = # When testing the connection in the UI, this is the search expected value # {valueType: "string", regex: "^ldap\\.([^.]+)\\.uiTestExpectedValue$"} # ldap.personLdap.uiTestExpectedValue = #optional (note, time limit is for search operations, timeout is for connection timeouts), #most of these default to ldaptive defaults. times are in millis # {valueType: "integer", regex: "^ldap\\.([^.]+)\\.batchSize$"} #ldap.personLdap.batchSize = #optional (note, time limit is for search operations, timeout is for connection timeouts), #most of these default to ldaptive defaults. times are in millis # {valueType: "integer", regex: "^ldap\\.([^.]+)\\.countLimit$"} #ldap.personLdap.countLimit = #optional (note, time limit is for search operations, timeout is for connection timeouts), #most of these default to ldaptive defaults. times are in millis # {valueType: "integer", regex: "^ldap\\.([^.]+)\\.timeLimit$"} #ldap.personLdap.timeLimit = #optional (note, time limit is for search operations, timeout is for connection timeouts), #most of these default to ldaptive defaults. times are in millis # {valueType: "integer", regex: "^ldap\\.([^.]+)\\.timeout$"} #ldap.personLdap.timeout = # if there is a max size limit on ldap server, then this will retrieve results in pages # {valueType: "integer", regex: "^ldap\\.([^.]+)\\.pagedResultsSize$"} #ldap.personLdap.pagedResultsSize = # set to 'follow' if using AD and using paged results size and need this for some reason (generally you shouldnt) # {valueType: "string", regex: "^ldap\\.([^.]+)\\.referral$"} #ldap.personLdap.referral = # comma-delimited list of classes to process LDAP search results. Useful if AD returns a ranged attribute for large # groups (e.g., member;range=0-1499); include the GrouperRangeEntryHandler to handle progressive fetching. # {valueType: "class", mustImplementInterface:"org.ldaptive.handler.Handler", multiple: true, regex: "^ldap\\.([^.]+)\\.searchResultHandlers$"} #ldap.personLdap.searchResultHandlers=org.ldaptive.handler.DnAttributeEntryHandler,edu.internet2.middleware.grouper.ldap.ldaptive.GrouperRangeEntryHandler # comma-delimited list of result codes (org.ldaptive.ResultCode) to ignore, e.g. TIME_LIMIT_EXCEEDED, SIZE_LIMIT_EXCEEDED, PARTIAL_RESULTS # {valueType: "string", multiple: true, regex: "^ldap\\.([^.]+)\\.searchIgnoreResultCodes$"} #ldap.personLdap.searchIgnoreResultCodes= # if this ldap connector is enabled # {valueType: "boolean", regex: "^ldap\\.([^.]+)\\.enabled$", defaultValue: "true"} #ldap.personLdap.enabled = #if want to customize pooling # {valueType: "boolean", regex: "^ldap\\.([^.]+)\\.customizePooling$", subSection: "pooling", defaultValue: "false"} #ldap.personLdap.customizePooling = #optional (note, time limit is for search operations, timeout is for connection timeouts), #most of these default to ldaptive defaults. times are in millis # {valueType: "integer", regex: "^ldap\\.([^.]+)\\.minPoolSize$", subSection: "pooling", showEl: "${customizePooling}"} #ldap.personLdap.minPoolSize = #optional (note, time limit is for search operations, timeout is for connection timeouts), #most of these default to ldaptive defaults. times are in millis # {valueType: "integer", regex: "^ldap\\.([^.]+)\\.maxPoolSize$", subSection: "pooling", showEl: "${customizePooling}"} #ldap.personLdap.maxPoolSize = #optional (note, time limit is for search operations, timeout is for connection timeouts), #most of these default to ldaptive defaults. times are in millis # {valueType: "boolean", regex: "^ldap\\.([^.]+)\\.validateOnCheckIn$", subSection: "pooling", showEl: "${customizePooling}"} #ldap.personLdap.validateOnCheckIn = # validateOnCheckOut defaults to true if all other validate methods are false # {valueType: "boolean", regex: "^ldap\\.([^.]+)\\.validateOnCheckOut$", subSection: "pooling", showEl: "${customizePooling}"} #ldap.personLdap.validateOnCheckOut = #optional (note, time limit is for search operations, timeout is for connection timeouts), #most of these default to ldaptive defaults. times are in millis # {valueType: "boolean", regex: "^ldap\\.([^.]+)\\.validatePeriodically$", subSection: "pooling", showEl: "${customizePooling}"} #ldap.personLdap.validatePeriodically = #optional (note, time limit is for search operations, timeout is for connection timeouts), #most of these default to ldaptive defaults. times are in millis # {valueType: "integer", regex: "^ldap\\.([^.]+)\\.validateTimerPeriod$", subSection: "pooling", showEl: "${customizePooling}"} #ldap.personLdap.validateTimerPeriod = #optional (note, time limit is for search operations, timeout is for connection timeouts), #most of these default to ldaptive defaults. times are in millis # {valueType: "integer", regex: "^ldap\\.([^.]+)\\.pruneTimerPeriod$", subSection: "pooling", showEl: "${customizePooling}"} #ldap.personLdap.pruneTimerPeriod = # validator setup, currently supports CompareLdapValidator and SearchValidator. additional properties below for CompareLdapValidator. # {valueType: "string", regex: "^ldap\\.([^.]+)\\.validator$", subSection: "pooling", showEl: "${customizePooling}", formElement: "dropdown", optionValues: ["CompareLdapValidator", "SearchValidator"]} #ldap.personLdap.validator = # validator setup, currently supports CompareLdapValidator and SearchValidator. additional properties below for CompareLdapValidator. eg: ou=people,dc=example,dc=com # {valueType: "string", regex: "^ldap\\.([^.]+)\\.validatorCompareDn$", subSection: "pooling", showEl: "${customizePooling && validator == 'CompareLdapValidator'}"} #ldap.personLdap.validatorCompareDn = # validator setup, currently supports CompareLdapValidator and SearchValidator. additional properties below for CompareLdapValidator. eg: ou # {valueType: "string", regex: "^ldap\\.([^.]+)\\.validatorCompareAttribute$", subSection: "pooling", showEl: "${customizePooling && validator == 'CompareLdapValidator'}"} #ldap.personLdap.validatorCompareAttribute = # validator setup, currently supports CompareLdapValidator and SearchValidator. additional properties below for CompareLdapValidator. eg: people # {valueType: "string", regex: "^ldap\\.([^.]+)\\.validatorCompareValue$", subSection: "pooling", showEl: "${customizePooling && validator == 'CompareLdapValidator'}"} #ldap.personLdap.validatorCompareValue = # set this to true to set the system property: org.ldaptive.response.ENCODE_CNTRL_CHARS for ldaptive, helpful for AD # https://todos.internet2.edu/browse/GRP-2969 # {valueType: "boolean"} ldaptiveEncodeControlChars = false ################################## ## LDAP loader settings ################################## # el classes to add to the el context for the EL to calculate subejct ids or group names etc. # Comma-separated fully qualified classnamesm will be registered by the non-fully qualified # uncapitalized classname. So you register a.b.SomeClass, it will be available by variable: someClass # {valueType: "class", multiple: true} loader.ldap.el.classes = ################################## ## Daemon logging ## When running the daemon log, do you want to log these various things? ################################## # overall log for a job # {valueType: "boolean", required: true} daemon.log.logEnabled_overallLog = true # subjob log for a job (e.g. if a job manages a lite of groups) # {valueType: "boolean", required: true} daemon.log.logEnabled_subjobLog = true # groups being created or deleted # {valueType: "boolean", required: true} daemon.log.logEnabled_groupManagement = true # memberships being created or deleted # {valueType: "boolean", required: true} daemon.log.logEnabled_membershipManagement = true # if each logger map should have an id # {valueType: "boolean", required: true} daemon.log.logIdsEnabled = false ################################## ## Daily report ################################## #quartz cron-like schedule for daily grouper report, the default is 7am every day: 0 0 7 * * ? #leave blank to disable this # {valueType: "cron"} daily.report.quartz.cron = 0 0 7 * * ? #comma separated email addresses to email the daily report, e.g. a@b.c, b@c.d # {valueType: "string", multiple: true} daily.report.emailTo = #if you put a directory here, the daily reports will be saved there, and you can #link up to a web service or store them or whatever. e.g. /home/grouper/reports/ # {valueType: "string"} daily.report.saveInDirectory = ################################## ## enabled / disabled cron ################################## #quartz cron-like schedule for enabled/disabled daemon. Note, this has nothing to do with the changelog #leave blank to disable this, the default is 12:01am, 11:01am, 3:01pm every day: 0 1 0,11,15 * * ? # {valueType: "cron"} changeLog.enabledDisabled.quartz.cron = 0 1 0,11,15 * * ? ################################## ## clean logs ################################## #quartz cron-like schedule for clean logs daemon. # {valueType: "cron", defaultValue="0 0 6 * * ?"} changeLog.cleanLogs.quartz.cron = 0 0 6 * * ? ################################## ## grouper builtin messaging cleanup cron ################################## #quartz cron-like schedule for grouper messaging daemon. #leave blank to disable this, the default is every hour, 10 minutes after the hour #this daemon does cleanup on the builtin messaging table # {valueType: "cron"} changeLog.builtinMessagingDaemon.quartz.cron = 0 10 * * * ? # after three days of not consuming messages, delete them, if -1, dont run this daemon # {valueType: "integer", required: true} grouper.builtin.messaging.deleteAllMessagesMoreThanHoursOld = 72 # after three hours of having processed messages, delete them. Note, if this is -1 just delete when marking processed # {valueType: "integer", required: true} grouper.builtin.messaging.deleteProcessedMessagesMoreThanMinutesOld = 180 ################################## ## Change log ################################## # should the change log temp to change log daemon run? Note, this should be true # {valueType: "boolean", defaultValue: "true"} changeLog.changeLogTempToChangeLog.enable = true #quartz cron-like schedule for change log temp to change log daemon, the default is 50 seconds after every minute: 50 * * * * ? # {valueType: "cron"} changeLog.changeLogTempToChangeLog.quartz.cron = # The max number of changes to send to a change log consumer at one time # {valueType: "integer", required: true} changeLog.changeLogConsumerBatchSize = 1000 # Should the change log include flattened memberships? # {valueType: "boolean", required: true} changeLog.includeFlattenedMemberships = true # Should the change log include flattened privileges? # {valueType: "boolean", required: true} changeLog.includeFlattenedPrivileges = true # Should the change log include roles that have had permission changes? # {valueType: "boolean", required: true} changeLog.includeRolesWithPermissionChanges = false # Should the change log include subjects that have had permission changes? # {valueType: "boolean", required: true} changeLog.includeSubjectsWithPermissionChanges = false # Should the change log include non-flattened (immediate and composite only) memberships? # {valueType: "boolean", required: true} changeLog.includeNonFlattenedMemberships = false # Should the change log include non-flattened (immediate only) privileges? # {valueType: "boolean", required: true} changeLog.includeNonFlattenedPrivileges = false # Once the number of change log updates exceeds this value, the transaction will commit and a new one will be created # {valueType: "integer", required: true} changeLog.tooManyChangeLogUpdatesSize = 10000 ################################## ## Change log consumers ################################## # specify the consumers here. specify the consumer name after the changeLog.consumer. part. This example is "printTest" # but it could be "myConsumerName" e.g. changeLog.consumer.myConsumerName.class # the class must extend edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase # note see Impl below # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase", regex: "^changeLog\\.consumer\\.([^.]+)\\.class$"} # changeLog.consumer.printTest.class = edu.internet2.middleware.grouper.changeLog.consumer.PrintTest # the quartz cron is a cron-like string. it defaults to every minute on the minute (since the temp to change log job runs # at 10 seconds to each minute). it defaults to this: 0 * * * * ? # though it will stagger each one by 2 seconds. You can leave this blank # {valueType: "cron", regex: "^changeLog\\.consumer\\.([^.]+)\\.quartzCron$"} # changeLog.consumer.printTest.quartzCron = # if you want to bump up the number of change log entries for a particular consumer, you can enter that here, per change log consumer # {valueType: "integer"} # changeLog.consumer.printTest.changeLogConsumerBatchSize = 1000 # rules consumer, needed for some of the Grouper rule types to run (e.g. flattenedMembershipRemove, flattenedMembershipAdd) # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase"} changeLog.consumer.grouperRules.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.RuleConsumer # rules consumer, needed for some of the Grouper rule types to run (e.g. flattenedMembershipRemove, flattenedMembershipAdd) # {valueType: "cron"} changeLog.consumer.grouperRules.quartzCron = # consumer for syncing groups to other groupers # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase"} changeLog.consumer.syncGroups.class = edu.internet2.middleware.grouper.client.GroupSyncConsumer # consumer for syncing groups to other groupers # {valueType: "cron"} changeLog.consumer.syncGroups.quartzCron = # recent-memberships consumer will update recent-membership groups as memberships/attributes change # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase"} changeLog.consumer.recentMemberships.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer # recent-memberships runs as change log consumer # {valueType: "cron"} changeLog.consumer.recentMemberships.quartzCron = # if this many records happens in one change log session, just do a full loader job # {valueType: "integer", defaultValue: "100"} changeLog.consumer.recentMemberships.maxUntilFullSync = 100 # publishing class for recent-memberships # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.esb.listener.EsbListenerBase"} changeLog.consumer.recentMemberships.publisher.class = edu.internet2.middleware.grouper.app.serviceLifecycle.GrouperRecentMembershipsChangeLogConsumer # find bad memberships consumer will fix membership issues soon after they occur # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase"} changeLog.consumer.findBadMemberships.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer # find bad memberships change log consumer # {valueType: "cron"} changeLog.consumer.findBadMemberships.quartzCron = # publishing class for find bad memberships # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.esb.listener.EsbListenerBase"} changeLog.consumer.findBadMemberships.publisher.class = edu.internet2.middleware.grouper.misc.FindBadMembershipsChangeLogConsumer ################################## ## Change log consumers based in Impl ## Note, you might want to extend: edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBaseImpl ## this is a higher level change log consumer that does a lot of logic for you ## this class will fire certain events for groups and memberships based on tagged folders or groups ## Note, to use this make an attribute and assign it to (generally) folder(s) or some groups or whatever ## GSH: ## GrouperSession grouperSession = GrouperSession.startRootSession(); ## AttributeDef provisioningMarkerAttributeDef = new AttributeDefSave(grouperSession).assignCreateParentStemsIfNotExist(true).assignName("attr:someAttrDef").assignToStem(true).assignToGroup(true).save(); ## AttributeDefName provisioningMarkerAttributeName = new AttributeDefNameSave(grouperSession, provisioningMarkerAttributeDef).assignName("attr:provisioningMarker").save() ## Stem parentFolder = StemFinder.findByName(grouperSession, "some:folder", true); ## parentFolder.getAttributeDelegate().assignAttribute(provisioningMarkerAttributeName); ################################## # {valueType: "class", mustExtendClass: "edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBaseImpl", regex: "^changeLog\\.consumer\\.([^.]+)\\.class$"} # changeLog.consumer.abc.class = edu.internet2.middleware.grouper.changeLog.consumer.PrintChangeLogConsumer # note: this name matches the attribute name created in the example above # {valueType: "attributeDefName", regex: "^changeLog\\.consumer\\.([^.]+)\\.syncAttributeName$"} # changeLog.consumer.abc.syncAttributeName = # quartz cron of consumer # {valueType: "cron", regex: "^changeLog\\.consumer\\.([^.]+)\\.quartzCron$"} # changeLog.consumer.abc.quartzCron = # defaults to true if not configured # {valueType: "boolean", regex: "^changeLog\\.consumer\\.([^.]+)\\.retryOnError$"} # changeLog.consumer.abc.retryOnError = ################################## ## PSPNG ################################## # cache the result of the analysis seeing if a group is provisionable # {valueType: "boolean", defaultValue: "true"} pspngCacheGroupProvisionable = true # When getting all provisionable groups, it will do a more efficient way if the provisionable # script is the standard one which I think everyone has. i.e. it knows where provision_to and # do_not_provision_to are, so just do the logic in java and in memory # {valueType: "boolean", defaultValue: "true"} pspngNonScriptProvisionable = true # The list of provisionable groups are cached for a number of minutes, 2 should be fine, # this cache is cleared at the start of each incremental or full sync also # {valueType: "integer", defaultValue: "1"} pspngCacheAllGroupProvisionableMinutes = 2 # if pspng should not find group and stem attributes if it doesnt think it need to, false for old behavior # {valueType: "boolean", defaultValue: "true"} pspngCacheGroupAndStemAttributes = true # if the full sync otherJob is running, then dont run the change log for that provisioner for X minutes # so cached can be fully used and things dont conflict. After X minutes, allow change log to run and finish # but then the next change log the next minute, will wait X minutes too # {valueType: "integer", defaultValue: "10"} pspngDontRunChangeLogDuringFullSyncForMinutes = 10 ################################## ## PSP ################################## # psp consumer class # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.psp.grouper.PspChangeLogConsumer"} # changeLog.consumer.psp.class = edu.internet2.middleware.psp.grouper.PspChangeLogConsumer # http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger # {valueType: "cron"} # changeLog.consumer.psp.quartzCron = 0 * * * * ? # To retry processing a change log entry if an error occurs, set retryOnError to true. Defaults to false. # {valueType: "boolean", required: true} # changeLog.consumer.psp.retryOnError = false # To run full provisioning synchronizations periodically, provide the class name which provides a 'public void fullSync()' method. # {valueType: "class", readOnly: true} # changeLog.psp.fullSync.class = edu.internet2.middleware.psp.grouper.PspChangeLogConsumer # Schedule full synchronizations. Defaults to 5 am : 0 0 5 * * ?. # {valueType: "cron"} # changeLog.psp.fullSync.quartzCron = 0 0 5 * * ? # Run a full synchronization job at startup. Defaults to false. # {valueType: "boolean", required: true} # changeLog.psp.fullSync.runAtStartup = false # Omit diff responses from bulk response to conserve memory. # {valueType: "boolean", required: true} # changeLog.psp.fullSync.omitDiffResponses = true # Omit sync responses from bulk response to conserve memory. # {valueType: "boolean", required: true} # changeLog.psp.fullSync.omitSyncResponses = true ################################### ## XMPP notifications ## (note, uncomment the consumer class and cron above) ## this will get grouper ws getMembers rest lite xmp: ## http://anonsvn.internet2.edu/cgi-bin/viewvc.cgi/i2mi/trunk/grouper-ws/grouper-ws/doc/samples/getMembers/WsSampleGetMembersRestLite_xml.txt?view=log ################################### # general xmpp configuration # {valueType: "string"} xmpp.server.host = jabber.school.edu # xmpp port # {valueType: "integer", required: true} xmpp.server.port = 5222 # xmpp username # {valueType: "string"} xmpp.user = username # note, pass can be in an external file with morphstring # {valueType: "password", sensitive: true} xmpp.pass = # xmpp resource # {valueType: "string"} xmpp.resource = grouperServer ################################### ## Rules config ################################### # when the rules validations and daemons run. Leave blank to not run # {valueType: "cron"} rules.quartz.cron = 0 0 7 * * ? ##################################### ## Messaging overall settings for daemon jobs ##################################### # auto create built in queues, topics, privileges # {valueType: "boolean", required: true} loader.messaging.settings.autocreate.objects = true ##################################### ## Messaging listener using the messaging API ## note, change "messagingListener" in key to be the name of the listener. e.g. messaging.listener.myAzureListener.class ## extends edu.internet2.middleware.grouper.messaging.MessagingListenerBase ## note, routingKey property is valid only for rabbitmq. For other messaging systems, it is ignored. ## this listener will just print out messages: edu.internet2.middleware.grouper.messaging.MessagingListenerPrint ##################################### # messaging listener class # {valueType: "class", required: true, mustExtendClass: "edu.internet2.middleware.grouper.messaging.MessagingListenerBase", regex: "^messaging\\.listener\\.([^.]+)\\.class$"} #messaging.listener.messagingListener.class = edu.internet2.middleware.grouper.messaging.MessagingListenerBase # messaging listener quartz cron # {valueType: "cron", regex: "^messaging\\.listener\\.([^.]+)\\.quartzCron$"} #messaging.listener.messagingListener.quartzCron = 0 * * * * ? # messaging listener messaging system name # {valueType: "string", regex: "^messaging\\.listener\\.([^.]+)\\.messagingSystemName$"} #messaging.listener.messagingListener.messagingSystemName = grouperBuiltinMessaging # messaging listener queue name # {valueType: "string", regex: "^messaging\\.listener\\.([^.]+)\\.queueName$"} #messaging.listener.messagingListener.queueName = abc # messaging listener routing key # {valueType: "string", regex: "^messaging\\.listener\\.([^.]+)\\.routingKey$"} #messaging.listener.messagingListener.routingKey = # messaging listener exchange type. Valid options are DIRECT, HEADERS, TOPIC, FANOUT # {valueType: "string", regex: "^messaging\\.listener\\.([^.]+)\\.exchangeType$"} #messaging.listener.messagingListener.exchangeType = # messaging listener number of tries per iteration # {valueType: "integer", regex: "^messaging\\.listener\\.([^.]+)\\.numberOfTriesPerIteration$"} #messaging.listener.messagingListener.numberOfTriesPerIteration = 3 # messaging listener polling timeout seconds # {valueType: "integer", regex: "^messaging\\.listener\\.([^.]+)\\.pollingTimeoutSeconds$"} #messaging.listener.messagingListener.pollingTimeoutSeconds = 18 # messaging listener sleep seconds in between iterations # {valueType: "integer", regex: "^messaging\\.listener\\.([^.]+)\\.sleepSecondsInBetweenIterations$"} #messaging.listener.messagingListener.sleepSecondsInBetweenIterations = 0 # messaging listener max messages to receive at once # {valueType: "integer", regex: "^messaging\\.listener\\.([^.]+)\\.maxMessagesToReceiveAtOnce$"} #messaging.listener.messagingListener.maxMessagesToReceiveAtOnce = 20 # if there are 20 messages to receive at once, then do this 50 times per call max # {valueType: "integer", regex: "^messaging\\.listener\\.([^.]+)\\.maxOuterLoops$"} #messaging.listener.messagingListener.maxOuterLoops = 50 ##################################### ## Messaging listener using the change log consumer API ##################################### # note, change "messagingListenerChangeLogConsumer" in key to be the name of the listener. e.g. messaging.listener.myAzureListener.class # keep this class to be MessagingListenerToChangeLogConsumer # {valueType: "class", readOnly: true, required: true, mustExtendClass: "edu.internet2.middleware.grouper.messaging.MessagingListenerToChangeLogConsumer", regex: "^messaging\\.listener\\.([^.]+)\\.class$"} #messaging.listener.messagingListenerChangeLogConsumer.class = edu.internet2.middleware.grouper.messaging.MessagingListenerToChangeLogConsumer # Class extends: edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase # {valueType: "class", required: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase", regex: "^messaging\\.listener\\.([^.]+)\\.changeLogConsumerClass$"} #messaging.listener.messagingListenerChangeLogConsumer.changeLogConsumerClass = edu.internet2.middleware.grouper.messaging.SomethingExtendsChangeLogConsumerBase # messaging listener quartz cron # {valueType: "cron", regex: "^messaging\\.listener\\.([^.]+)\\.quartzCron$"} #messaging.listener.messagingListenerChangeLogConsumer.quartzCron = 0 * * * * ? # system name # {valueType: "string", regex: "^messaging\\.listener\\.([^.]+)\\.messagingSystemName$"} #messaging.listener.messagingListenerChangeLogConsumer.messagingSystemName = grouperBuiltinMessaging # queue name in messaging system # {valueType: "string", regex: "^messaging\\.listener\\.([^.]+)\\.queueName$"} #messaging.listener.messagingListenerChangeLogConsumer.queueName = abc # number of tries per iteration # {valueType: "integer", regex: "^messaging\\.listener\\.([^.]+)\\.numberOfTriesPerIteration$"} #messaging.listener.messagingListenerChangeLogConsumer.numberOfTriesPerIteration = 3 # polling timeout seconds # {valueType: "integer", regex: "^messaging\\.listener\\.([^.]+)\\.pollingTimeoutSeconds$"} #messaging.listener.messagingListenerChangeLogConsumer.pollingTimeoutSeconds = 18 # sleep seconds in between iteration # {valueType: "integer", regex: "^messaging\\.listener\\.([^.]+)\\.sleepSecondsInBetweenIterations$"} #messaging.listener.messagingListenerChangeLogConsumer.sleepSecondsInBetweenIterations = 0 # max messages to receive at once # {valueType: "integer", regex: "^messaging\\.listener\\.([^.]+)\\.maxMessagesToReceiveAtOnce$"} #messaging.listener.messagingListenerChangeLogConsumer.maxMessagesToReceiveAtOnce = 20 # max outer loops # if there are 20 messages to receive at once, then do this 50 times per call max # {valueType: "integer", regex: "^messaging\\.listener\\.([^.]+)\\.maxOuterLoops$"} #messaging.listener.messagingListenerChangeLogConsumer.maxOuterLoops = 50 ##################################### ## Messaging integration with change log, send change log entries to a messaging system ##################################### # note, change "messaging" in key to be the name of the consumer. e.g. changeLog.consumer.myAzureConsumer.class # note, routingKey property is valid only for rabbitmq. For other messaging systems, it is ignored. # {valueType: "class", required: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerToMessage", regex: "^changeLog\\.consumer\\.([^.]+)\\.class$"} #changeLog.consumer.messaging.class = edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerToMessage # quartz cron # {valueType: "cron", regex: "^changeLog\\.consumer\\.([^.]+)\\.quartzCron$"} #changeLog.consumer.messaging.quartzCron = 0 * * * * ? # system name # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.messagingSystemName$"} #changeLog.consumer.messaging.messagingSystemName = grouperBuiltinMessaging # routing key # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.routingKey$"} #changeLog.consumer.messaging.routingKey = # exchange type. valid options are DIRECT, TOPIC, HEADERS, FANOUT # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.exchangeType$"} #changeLog.consumer.messaging.exchangeType = # queue or topic # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.messageQueueType$"} #changeLog.consumer.messaging.messageQueueType = queue # queue or topic name # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.queueOrTopicName$"} #changeLog.consumer.messaging.queueOrTopicName = abc ##################################### ## Messaging integration with ESB, send change log entries to a messaging system ##################################### # note, change "messagingEsb" in key to be the name of the consumer. e.g. changeLog.consumer.myAzureConsumer.class # note, routingKey property is valid only for rabbitmq. For other messaging systems, it is ignored. # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.ChangeLogConsumerBase"} #changeLog.consumer.messagingEsb.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer # quartz cron # {valueType: "cron", regex: "^changeLog\\.consumer\\.([^.]+)\\.quartzCron$"} #changeLog.consumer.messagingEsb.quartzCron = 0 * * * * ? # el filter # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.elfilter$"} #changeLog.consumer.messagingEsb.elfilter = event.eventType eq 'GROUP_DELETE' || event.eventType eq 'GROUP_ADD' || event.eventType eq 'MEMBERSHIP_DELETE' || event.eventType eq 'MEMBERSHIP_ADD' # publishing class # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbMessagingPublisher", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.class$"} #changeLog.consumer.messagingEsb.publisher.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbMessagingPublisher # messaging system name # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.messagingSystemName$"} #changeLog.consumer.messagingEsb.publisher.messagingSystemName = grouperBuiltinMessaging # routing key # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.routingKey$"} #changeLog.consumer.messagingEsb.publisher.routingKey = # EL replacement definition. groupName is the variable for the name of the group. grouperUtil is the class GrouperUtilElSafe can be used for utility methods. # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.regexRoutingKeyReplacementDefinition$"} #changeLog.consumer.messagingEsb.regexRoutingKeyReplacementDefinition = ${groupName.replaceFirst('hawaii.edu', 'group.modify').replace(':enrolled', '').replace(':waitlisted', '').replace(':withdrawn', '')} # replace routing key with periods # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.replaceRoutingKeyColonsWithPeriods$"} #changeLog.consumer.messagingEsb.replaceRoutingKeyColonsWithPeriods = true # queue or topic # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.messageQueueType$"} #changeLog.consumer.messagingEsb.publisher.messageQueueType = queue # queue or topic name # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.queueOrTopicName$"} #changeLog.consumer.messagingEsb.publisher.queueOrTopicName = abc # exchange type for rabbitmq. valid options are DIRECT, TOPIC, HEADERS, FANOUT # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.exchangeType$"} #changeLog.consumer.messagingEsb.publisher.exchangeType = # key for optional extra arguments for rabbitmq. For each key, set up a corresponding value having the same index # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.queueArgs\\.([0-9]+)\\.key$"} #changeLog.consumer.messagingEsb.publisher.queueArgs.0.key = x-queue-type # value for optional extra arguments for rabbitmq. Each index should have a corresponding key # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.queueArgs\\.([0-9]+)\\.value$"} #changeLog.consumer.messagingEsb.publisher.queueArgs.0.value = quorum ##################################### ## ESB integration ##################################### # quartz cron # {valueType: "cron", regex: "^changeLog\\.consumer\\.([^.]+)\\.quartzCron$"} #changeLog.consumer.awsJira.quartzCron = 0/15 * * * * ? # class # {valueType: "class", readOnly: true, required: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer", regex: "^changeLog\\.consumer\\.([^.]+)\\.class$"} #changeLog.consumer.awsJira.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer # el filter # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.elfilter$"} #changeLog.consumer.awsJira.elfilter = event.eventType eq 'MEMBERSHIP_ADD' || event.eventType eq 'MEMBERSHIP_ADD' # if dont send sensitive data # {valueType: "boolean", regex: "^changeLog\\.consumer\\.([^.]+)\\.noSensitiveData$"} #changeLog.consumer.awsJira.noSensitiveData = true # if you want to encrypt messages, set this to an implementation of edu.internet2.middleware.grouperClient.encryption.GcEncryptionInterface # {valueType: "class", regex: "^changeLog\\.consumer\\.([^.]+)\\.encryptionImplementation$", mustImplementInterface: "edu.internet2.middleware.grouperClient.encryption.GcEncryptionInterface"} #changeLog.consumer.awsJira.encryptionImplementation = edu.internet2.middleware.grouperClient.encryption.GcSymmetricEncryptAesCbcPkcs5Padding # this is a key or could be encrypted in a file as well like other passwords # generate a key with: java -cp grouperClient.jar edu.internet2.middleware.grouperClient.encryption.GcGenerateKey # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.encryptionKey$"} #changeLog.consumer.awsJira.encryptionKey = abc123 # if you dont want to send the first 4 of the sha hash base 64 of the secret # {valueType: "boolean", regex: "^changeLog\\.consumer\\.([^.]+)\\.dontSendShaBase64secretFirst4$"} #changeLog.consumer.awsJira.dontSendShaBase64secretFirst4 = false # publisher class # {valueType: "class", readOnly: true, regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.class$", mustExtendClass: "edu.internet2.middleware.grouperAwsChangelog.GrouperAwsEsbPublisher"} #changeLog.consumer.awsJira.publisher.class = edu.internet2.middleware.grouperAwsChangelog.GrouperAwsEsbPublisher # aws access key # {valueType: "password", sensitive: true, regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.awsAccessKey$"} #changeLog.consumer.awsJira.publisher.awsAccessKey = ABCXYZ # aws secret key # {valueType: "password", sensitive: true, regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.awsSecretKey$"} #changeLog.consumer.awsJira.publisher.awsSecretKey = 123REWQ # aws region # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.awsRegion$"} #changeLog.consumer.awsJira.publisher.awsRegion = US_EAST_1 # aws sns topic arn # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.awsSnsTopicArn$"} #changeLog.consumer.awsJira.publisher.awsSnsTopicArn = arn:aws:sns:us-east-1:123:name # quartz cron # {valueType: "cron", regex: "^changeLog\\.consumer\\.([^.]+)\\.quartzCron$"} #changeLog.consumer.xmppTest.quartzCron = # class # {valueType: "class", readOnly: true, required: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer", regex: "^changeLog\\.consumer\\.([^.]+)\\.class$"} #changeLog.consumer.xmppTest.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer # el filter # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.elfilter$"} #changeLog.consumer.xmppTest.elfilter = event.eventType eq 'GROUP_DELETE' || event.eventType eq 'GROUP_ADD' || event.eventType eq 'MEMBERSHIP_DELETE' || event.eventType eq 'MEMBERSHIP_ADD' # publisher class # {valueType: "class", readOnly: true, regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.class$", mustExtendClass: "edu.internet2.middleware.grouperAwsChangelog.GrouperAwsEsbPublisher"} #changeLog.consumer.xmppTest.publisher.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbXmppPublisher # publisher server # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.server$"} #changeLog.consumer.xmppTest.publisher.server = jabber.school.edu # {valueType: "integer", required: true, regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.port$"} #changeLog.consumer.xmppTest.publisher.port = 5222 # user name # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.username$"} #changeLog.consumer.xmppTest.publisher.username = jabberuser # password # {valueType: "password", sensitive: true, regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.password$"} #changeLog.consumer.xmppTest.publisher.password = /home/whatever/pass/jabberuserEncrypted.pass # recipient # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.recipient$"} #changeLog.consumer.xmppTest.publisher.recipient = system1@school.edu # add subject attributes # {valueType: "string", multiple: true, regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.addSubjectAttributes$"} #changeLog.consumer.xmppTest.publisher.addSubjectAttributes = NETID #note, on the content type header, activemq might need: application/x-www-form-urlencoded # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.contentTypeHeader$"} #changeLog.consumer.xmppTest.publisher.contentTypeHeader = application/json; charset=utf-8 #note, on the stringRequestEntityPrefix, activemq might need: data= # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.stringRequestEntityPrefix$"} #changeLog.consumer.xmppTest.publisher.stringRequestEntityPrefix = #note, on the stringRequestEntityContentType, activemq might need: application/x-www-form-urlencoded # {valueType: "string", regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.stringRequestEntityContentType$"} #changeLog.consumer.xmppTest.publisher.stringRequestEntityContentType = application/json ################################ ## Other jobs built-in ## ## Configure other jobs. ## "jobName" is the name of your job. ## Class must implement org.quartz.Job. ## Priority is optional ## ## For jobs that run by default, you can disable them by setting an empty quartz cron in grouper-loader.properties. ################################ # Find and fix bad memberships class # {valueType: "class", readOnly: true, mustImplementInterface: "org.quartz.Job"} otherJob.findBadMemberships.class = edu.internet2.middleware.grouper.misc.FindBadMembershipsDaemon # Find and fix bad memberships cron # {valueType: "cron"} otherJob.findBadMemberships.quartzCron = 0 0 1 * * ? # Keep the current time in a database independent way # {valueType: "class", readOnly: true, mustImplementInterface: "org.quartz.Job"} otherJob.timeDaemon.class = edu.internet2.middleware.grouper.app.serviceLifecycle.GrouperTimeDaemon # Run the time daemon every minute # {valueType: "cron"} otherJob.timeDaemon.quartzCron = 45 * * * * ? # Find and fix scheduler issues class # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} otherJob.schedulerCheckDaemon.class = edu.internet2.middleware.grouper.app.loader.GrouperDaemonSchedulerCheck # Find and fix scheduler issues cron # {valueType: "cron"} otherJob.schedulerCheckDaemon.quartzCron = 25 0/30 * * * ? # If there hasnt been a success in the last X minutes, then kick this off from thread (not from daemon). Who is watching the watcher? # If this is -1, then do not run a watcher thread # {valueType: "integer", defaultValue: "35"} otherJob.schedulerCheckDaemon.maxMinutesSinceSuccess = 35 # If there has been a daemon run in the last X minutes, then dont run manually. -1 to not include. Note, if maxMinutesSinceSuccess is -1, then # this config will not be used # {valueType: "integer", defaultValue: "15"} otherJob.schedulerCheckDaemon.minMinutesSinceStarted = 15 # Atttestation Job class # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} otherJob.attestationDaemon.class = edu.internet2.middleware.grouper.app.attestation.GrouperAttestationJob # Atttestation Job cron # {valueType: "cron"} otherJob.attestationDaemon.quartzCron = 0 0 1 * * ? # Deprovisioning Job class # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} otherJob.deprovisioningDaemon.class = edu.internet2.middleware.grouper.app.deprovisioning.GrouperDeprovisioningJob # Deprovisioning Job cron # {valueType: "cron"} otherJob.deprovisioningDaemon.quartzCron = 0 0 2 * * ? # Object Type Job class # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} otherJob.grouperObjectTypeDaemon.class = edu.internet2.middleware.grouper.app.grouperTypes.GrouperObjectTypesJob # Object Type Job cron # {valueType: "cron"} otherJob.grouperObjectTypeDaemon.quartzCron = 0 0 3 * * ? # Provisioning Job class # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} otherJob.grouperProvisioningDaemon.class = edu.internet2.middleware.grouper.app.provisioning.GrouperProvisioningJob # Provisioning Job cron # {valueType: "cron"} otherJob.grouperProvisioningDaemon.quartzCron = 0 0 4 * * ? # Provisioning FullSync Job class # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} # otherJob.grouperProvisioningFullSyncDaemon.class = edu.internet2.middleware.grouper.app.provisioning.GrouperProvisioningFullSyncJob # Provisioning FullSync provisioner config id # {valueType: "string", required: true, formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.provisioning.ProvisionerConfigurationOptionValueDriver"} # otherJob.grouperProvisioningFullSyncDaemon.provisionerConfigId = # Provisioning Full sync Job cron # {valueType: "cron"} # otherJob.grouperProvisioningFullSyncDaemon.quartzCron = 0 0 4 * * ? # Provisioning Incremental sync Job class # {valueType: "class", required: true, readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer"} # changeLog.consumer.grouperProvisioningIncrementalSyncDaemon.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer # Provisioning Incremental provisioner config id # {valueType: "string", required: true, formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.provisioning.ProvisionerConfigurationOptionValueDriver"} # changeLog.consumer.grouperProvisioningIncrementalSyncDaemon.provisionerConfigId = # Provisioning Incremental sync Job cron # {valueType: "cron"} # changeLog.consumer.grouperProvisioningIncrementalSyncDaemon.quartzCron = 0 * * * * ? # publisher class # {valueType: "class", readOnly: true, regex: "^changeLog\\.consumer\\.([^.]+)\\.publisher\\.class$", mustExtendClass: "edu.internet2.middleware.grouper.app.provisioning.ProvisioningConsumer"} # changeLog.consumer.grouperProvisioningIncrementalSyncDaemon.publisher.class = edu.internet2.middleware.grouper.app.provisioning.ProvisioningConsumer # turns on the changelog consumer debug logging # {valueType: "boolean", defaultValue: "false"} # changeLog.consumer.grouperProvisioningIncrementalSyncDaemon.publisher.debug = false # Run upgrade tasks # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} otherJob.upgradeTasks.class = edu.internet2.middleware.grouper.app.upgradeTasks.UpgradeTasksJob # Run upgrade tasks cron # {valueType: "cron"} otherJob.upgradeTasks.quartzCron = 5 25 * * * ? # reports clear Job class # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} otherJob.grouperReportClearDaemon.class = edu.internet2.middleware.grouper.app.reports.GrouperReportClearJob # reports clear Job cron # {valueType: "cron"} otherJob.grouperReportClearDaemon.quartzCron = 0 0 3 * * ? # Workflow daemon that updates instances and send emails # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} otherJob.grouperWorkflowDaemon.class = edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowDaemonJob # Object Type Job cron # {valueType: "cron"} otherJob.grouperWorkflowDaemon.quartzCron = 0 0/5 * ? * * * # Workflow reminder email daemon # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} otherJob.grouperWorkflowReminderDaemon.class = edu.internet2.middleware.grouper.app.workflow.GrouperWorkflowReminderEmailJob # Object Type Job cron # {valueType: "cron"} otherJob.grouperWorkflowReminderDaemon.quartzCron = 0 0 4 * * ? ################################ ## Table sync jobs ## tableSync jobs should use class: edu.internet2.middleware.grouper.app.tableSync.TableSyncOtherJob ## and include a setting to point to the grouperClient config, if not same: otherJob..grouperClientTableSyncConfigKey = key ## this is the subtype of job to run: otherJob..syncType = fullSyncFull ## (can be: fullSyncFull, fullSyncGroupings, fullSyncChangeFlag, incrementalAllColumns, incrementalPrimaryKey) ################################ # Object Type Job class # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} # otherJob.membershipSync.class = edu.internet2.middleware.grouper.app.tableSync.TableSyncOtherJob # Object Type Job cron # {valueType: "cron"} # otherJob.membershipSync.quartzCron = 0 0/30 * * * ? # this is the key in the grouper.client.properties that represents this job # {valueType: "string"} # otherJob.membershipSync.grouperClientTableSyncConfigKey = memberships # fullSyncFull, fullSyncGroupings, fullSyncChangeFlag, incrementalAllColumns, incrementalPrimaryKey # {valueType: "string"} # otherJob.membershipSync.syncType = fullSyncFull # Object Type Job class # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} otherJob.recentMembershipsConfFull.class = edu.internet2.middleware.grouper.app.tableSync.TableSyncOtherJob # Object Type Job cron, every hour # {valueType: "cron"} otherJob.recentMembershipsConfFull.quartzCron = 0 0 * * * ? # this is the key in the grouper.client.properties that represents this job # {valueType: "string"} otherJob.recentMembershipsConfFull.grouperClientTableSyncConfigKey = recentMembershipsConf # fullSyncFull, fullSyncGroupings, fullSyncChangeFlag, incrementalAllColumns, incrementalPrimaryKey # {valueType: "string"} otherJob.recentMembershipsConfFull.syncType = fullSyncFull ################################ ## USDU ################################ # USDU Job class # {valueType: "class", mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} otherJob.usduDaemon.class = edu.internet2.middleware.grouper.app.usdu.UsduJob # USDU Job cron # {valueType: "cron"} otherJob.usduDaemon.quartzCron = 0 0 1 * * ? ################################ ## Other jobs ## ## Configure other jobs. ## "jobName" is the name of your job. ## Class must implement org.quartz.Job. Should extend edu.internet2.middleware.grouper.app.loader.OtherJobBase ## Priority is optional ## see edu.internet2.middleware.grouper.app.loader.GrouperLoaderIncrementalJob as an example ## ################################ # other job class # {valueType: "class", required: true, regex: "^otherJob.([^.]+).class$", mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} # otherJob.jobName.class = a.b.c.SomethingThatExtendsOtherJobBase # other job quartz cron # {valueType: "cron", regex: "^otherJob.([^.]+).quartzCron$"} # otherJob.jobName.quartzCron = # other job priority (optional) # {valueType: "integer", regex: "^otherJob.([^.]+).priority$", defaultValue: "5"} # otherJob.jobName.priority = ##################################### ## Message to WS Daemon Job ##################################### # message to ws daemon job class # {valueType: "class", mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} #otherJob.messageConsumerDaemon.class = edu.internet2.middleware.grouper.app.messaging.MessageConsumerDaemon # message to ws daemon job cron # {valueType: "cron"} #otherJob.messageConsumerDaemon.quartzCron = 0 * * ? * * # there can be multiple entries, "wsMessagingBridge" is the name of this one, change that for each config section # the messaging system name must correspond to a messaging system in the grouper.client.properties # {valueType: "string", regex: "^grouper\\.messaging\\.([^.]+)\\.messagingSystemName$"} # grouper.messaging.wsMessagingBridge.messagingSystemName = rabbitMqMessaging # the queue or topic to check # {valueType: "string", regex: "^grouper\\.messaging\\.([^.]+)\\.messagingSystemName$"} #grouper.messaging.wsMessagingBridge.queueOrTopicName = sampleWsMessagingQueue # routingKey is only valid for rabbitmq; for others, it's ignored # {valueType: "string", regex: "^grouper\\.messaging\\.([^.]+)\\.routingKey$"} #grouper.messaging.wsMessagingBridge.routingKey = # exchangeType is only valid for rabbitmq; for others, it's ignored. Valid options are DIRECT, TOPIC, HEADERS, FANOUT # {valueType: "string", required: false, regex: "^grouper\\.messaging\\.([^.]+)\\.exchangeType$"} #grouper.messaging.wsMessagingBridge.exchangeType = # if this is a "queue" or "topic", generally it will be queue # {valueType: "string", regex: "^grouper\\.messaging\\.([^.]+)\\.messageQueueType$"} #grouper.messaging.wsMessagingBridge.messageQueueType = queue # the source id of the source of the user to act as # {valueType: "string", regex: "^grouper\\.messaging\\.([^.]+)\\.actAsSubjectSourceId$"} #grouper.messaging.wsMessagingBridge.actAsSubjectSourceId = g:isa # the subject id of the user to act as # {valueType: "string", regex: "^grouper\\.messaging\\.([^.]+)\\.actAsSubjectId$"} #grouper.messaging.wsMessagingBridge.actAsSubjectId = GrouperSystem # the long polling seconds, listen to the queue for this many seconds for messages # {valueType: "integer", required: true, regex: "^grouper\\.messaging\\.([^.]+)\\.longPollingSeconds$"} #grouper.messaging.wsMessagingBridge.longPollingSeconds = 20 # grouper ws url # {valueType: "string", regex: "^grouper\\.messaging\\.([^.]+)\\.ws\\.url$"} #grouper.messaging.wsMessagingBridge.ws.url = # grouper ws username # {valueType: "string", regex: "^grouper\\.messaging\\.([^.]+)\\.ws\\.username$"} #grouper.messaging.wsMessagingBridge.ws.username = # grouper ws password # {valueType: "password", sensitive: true, regex: "^grouper\\.messaging\\.([^.]+)\\.ws\\.password$"} #grouper.messaging.wsMessagingBridge.ws.password = # optional queue argument keys for rabbitMQ, number from zero and increase sequentially # {valueType: "string", regex: "^grouper\\.messaging\\.([^.]+)\\.queueArgs\\.([0-9]+)\\.key$"} #grouper.messaging.wsMessagingBridge.queueArgs.0.key = x-queue-type # optional queue argument values for rabbitMQ # {valueType: "string", regex: "^grouper\\.messaging\\.([^.]+)\\.queueArgs\\.([0-9]+)\\.value$"} #grouper.messaging.wsMessagingBridge.queueArgs.0.value = quorum ##################################################### ## TIER Instrumentation daemon - send stats to TIER. ##################################################### # set this to enable the instrumentation # {valueType: "class", mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase"} otherJob.tierInstrumentationDaemon.class = edu.internet2.middleware.grouper.instrumentation.TierInstrumentationDaemon # cron string # {valueType: "cron"} otherJob.tierInstrumentationDaemon.quartzCron = 0 0 2 * * ? # collector url # {valueType: "string"} otherJob.tierInstrumentationDaemon.collectorUrl = http://collector.testbed.tier.internet2.edu:5001 ##################################################### ## Email notifications (e.g. daily) ##################################################### # set this class to enable the email notification # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase"} # otherJob.emailNotificationConfigId.class = edu.internet2.middleware.grouper.app.loader.NotificationDaemon # cron string # {valueType: "cron"} # otherJob.emailNotificationConfigId.quartzCron = 0 03 5 * * ? # is this a notification to each result, or a summary of the results (perhaps printing the list in the email) # {valueType: "string", required: true, regex: "^otherJob\\.([^.]+)\\.emailType$", formElement: "dropdown", optionValues: ["notification", "summary"]} # otherJob.emailNotificationConfigId.emailType = # is the population to get the email from a group or from a sql query? # {valueType: "string", required: true, regex: "^otherJob\\.([^.]+)\\.populationType$", formElement: "dropdown", optionValues: ["groupMembership", "sqlQuery"]} # otherJob.emailNotificationConfigId.populationType = # group name fully qualified of group which the population should receive the email, or that the summary is about. e.g. a:b:c # {valueType: "string", required: true, regex: "^otherJob\\.([^.]+)\\.emailListGroupName$", showEl: "${populationType == 'groupMembership'}"} # otherJob.emailNotificationConfigId.emailListGroupName = # sql connection id (of your database external systems) that the query runs where the results are the people to send emails to, or that the summary is about. # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.emailListDbConnection$", showEl: "${populationType == 'sqlQuery'}", formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.loader.db.DatabaseGrouperExternalSystem"} # otherJob.emailNotificationConfigId.emailListDbConnection = # sql query where each row represents a subject to send an email to, or a row in the email summary. # There must be a column of subject_id. There can optionally be a column email_address_to_send_to if you want to override the subject email address. # Any other columns will be available for the email body and subject template. # {valueType: "string", required: true, regex: "^otherJob\\.([^.]+)\\.emailListQuery$", showEl: "${populationType == 'sqlQuery'}"} # otherJob.emailNotificationConfigId.emailListQuery = # If this is a summary type email, then this is group to send email to. Each member of the group will receive the summary # {valueType: "string", required: true, regex: "^otherJob\\.([^.]+)\\.emailSummaryToGroupName$", showEl: "${emailType == 'summary'}"} # otherJob.emailNotificationConfigId.emailSummaryToGroupName = # Only send the summary email if there are records to report on # {valueType: "boolean", required: true, regex: "^otherJob\\.([^.]+)\\.emailSummaryOnlyIfRecordsExist$", showEl: "${emailType == 'summary'}"} # otherJob.emailNotificationConfigId.emailSummaryOnlyIfRecordsExist = # subject source id of subjects to send emails to (filter subjects from other sources) # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.subjectSourceId$", formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.subject.provider.SourceManagerOptionValueDriver"} # otherJob.emailNotificationConfigId.subjectSourceId = # subject of the email. Note, you can use any variables that the body uses. This is a jexl template # {valueType: "string", required: true, regex: "^otherJob\\.([^.]+)\\.emailSubjectTemplate$"} # otherJob.emailNotificationConfigId.emailSubjectTemplate = # body of the email. You can use any variables from the query or the subject. Uses a JEXL template. e.g. hello ${subject_name}, # subject_name, subject_id, subject_description, subject_attribute_firstname (where "firstname" is a lower case subject attribute key), # column_some_column_name where "some_column_name" is a lower case column name from query (if applicable). __NEWLINE__ will substitute # to a newline. If this is a summary report, then you can loop over the records to print a line per person. The JEXL template # code part starts with two dollar signs: $$ e.g. # ${size(listOfRecordMaps)}__NEWLINE__$$ for (var recordMap : listOfRecordMaps) {__NEWLINE__ Record subject ID: ${recordMap.get('subject_id')}__NEWLINE__$$} # {valueType: "string", required: true, regex: "^otherJob\\.([^.]+)\\.emailBodyTemplate$"} # otherJob.emailNotificationConfigId.emailBodyTemplate = # group name of a group that the user will be added to after an email is sent, with a membership attribute with value. # Note, this uses the attribute framework with PIT so you probably shouldnt use this "group of people who received emails" # for use cases with mass email sending. # of yyyy/mm/dd (string) of as email sent date # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.lastSentGroupName$"} # otherJob.emailNotificationConfigId.lastSentGroupName = # group name of a group that the user must be in, to be eligible to get emails sent to them, or eligible to be in the summary # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.eligibilityGroupName$"} # otherJob.emailNotificationConfigId.eligibilityGroupName = # email addresses to be emailed as bcc (comma separated) # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.bccsCommaSeparated$"} # otherJob.emailNotificationConfigId.bccsCommaSeparated = # if true then only sent to bcc and the "to" line will be in the email # only 20 emails will be sent max # {valueType: "boolean", defaultValue: "false", regex: "^otherJob\\.([^.]+)\\.sendToBccOnly$"} # otherJob.emailNotificationConfigId.sendToBccOnly = ##################################################### ## Sync to Grouper from SQL (or Grouper via SQL) ##################################################### # Set this class to enable the email notification # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase"} # otherJob.syncToGrouperFromSqlConfigId.class = edu.internet2.middleware.grouper.app.syncToGrouper.SyncToGrouperFromSqlDaemon # Cron string # {valueType: "cron"} # otherJob.syncToGrouperFromSqlConfigId.quartzCron = 0 03 5 * * ? # Readonly (true to not make changes in Grouper) # {valueType: "boolean", order: 1000, subSection: "sqlSyncToGrouper", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperReadonly$", required: true} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperReadonly = # Debug output # {valueType: "boolean", order: 2000, subSection: "sqlSyncToGrouper", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperLogOutput$", defaultValue: "false"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperLogOutput = # Sql connection id (of your database external systems) where the data table is # {valueType: "string", order: 3000, subSection: "sqlSyncToGrouper", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperDatabaseConfigId$", required: true, formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.loader.db.DatabaseGrouperExternalSystem"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperDatabaseConfigId = # Sync from another Grouper (true) will auto generate queries that work with Grouper. Select false to enter in arbitrary SQL queries. # {valueType: "boolean", order: 4000, subSection: "sqlSyncToGrouper", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperFromAnotherGrouper$", required: true} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperFromAnotherGrouper = # Set a schema to point to in the database connection if not connecting as the schema that either owns the objects or has synonyms to them without prefix # {valueType: "String", order: 5000, subSection: "sqlSyncToGrouper", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperDatabaseSyncFromAnotherGrouperSchema$", showEl: "${sqlSyncToGrouperFromAnotherGrouper}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperDatabaseSyncFromAnotherGrouperSchema = # Use SQL metadata to see which columns are available for syncing. Otherwise specify which columns to sync # {valueType: "boolean", order: 6000, subSection: "sqlSyncToGrouper", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperAutoconfigureColumns$", required: true} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperAutoconfigureColumns = # Specify the top level folders to sync by name comma separated # {valueType: "string", order: 7000, subSection: "sqlSyncToGrouper", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperTopLevelStems$", required: true, multiple: true} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperTopLevelStems = # True to sync folders to Grouper # {valueType: "boolean", order: 8000, subSection: "sqlSyncToGrouperStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperStemSync$", defaultValue: "false"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperStemSync = # SQL to get folders from database # {valueType: "string", formElement: "textarea", order: 9000, subSection: "sqlSyncToGrouperStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperStemSql$", required: true, showEl: "${sqlSyncToGrouperStemSync && !sqlSyncToGrouperFromAnotherGrouper}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperStemSql = # Insert folders into Grouper # {valueType: "boolean", order: 10000, subSection: "sqlSyncToGrouperStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperStemInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperStemSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperStemInsert = # Update folders in Grouper # {valueType: "boolean", order: 11000, subSection: "sqlSyncToGrouperStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperStemUpdate$", defaultValue: "false", showEl: "${sqlSyncToGrouperStemSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperStemUpdate = # Delete folders in Grouper which are in the "folders to sync" which are not in the other database # {valueType: "boolean", order: 12000, subSection: "sqlSyncToGrouperStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperStemDeleteExtra$", defaultValue: "false", showEl: "${sqlSyncToGrouperStemSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperStemDeleteExtra = # Sync folder alternate names from the alternate_name column label # {valueType: "boolean", order: 13000, subSection: "sqlSyncToGrouperStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperStemSyncFieldAlternateName$", defaultValue: "false", showEl: "${sqlSyncToGrouperStemSync && !sqlSyncToGrouperAutoconfigureColumns}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperStemSyncFieldAlternateName = # Sync folder descriptions from the description column label # {valueType: "boolean", order: 14000, subSection: "sqlSyncToGrouperStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperStemSyncFieldDescription$", defaultValue: "false", showEl: "${sqlSyncToGrouperStemSync && !sqlSyncToGrouperAutoconfigureColumns}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperStemSyncFieldDescription = # Sync folder display names from the display_name column label # {valueType: "boolean", order: 15000, subSection: "sqlSyncToGrouperStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperStemSyncFieldDisplayName$", defaultValue: "false", showEl: "${sqlSyncToGrouperStemSync && !sqlSyncToGrouperAutoconfigureColumns}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperStemSyncFieldDisplayName = # Sync folder ID index from the id_index column label # {valueType: "boolean", order: 16000, subSection: "sqlSyncToGrouperStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperStemSyncFieldIdIndexOnInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperStemSync && !sqlSyncToGrouperAutoconfigureColumns && sqlSyncToGrouperStemInsert}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperStemSyncFieldIdIndexOnInsert = # Sync folder ID (UUID) from the id column label # {valueType: "boolean", order: 17000, subSection: "sqlSyncToGrouperStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperStemSyncFieldIdOnInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperStemSync && !sqlSyncToGrouperAutoconfigureColumns && sqlSyncToGrouperStemInsert}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperStemSyncFieldIdOnInsert = # True to sync groups to Grouper # {valueType: "boolean", order: 18000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupSync$", defaultValue: "false"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupSync = # SQL to get groups from database # {valueType: "string", formElement: "textarea", order: 19000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupSql$", required: true, showEl: "${sqlSyncToGrouperGroupSync && !sqlSyncToGrouperFromAnotherGrouper}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupSql = # Insert groups into Grouper # {valueType: "boolean", order: 20000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperGroupSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupInsert = # Update groups in Grouper # {valueType: "boolean", order: 21000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupUpdate$", defaultValue: "false", showEl: "${sqlSyncToGrouperGroupSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupUpdate = # Delete groups from Grouper # {valueType: "boolean", order: 22000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupDeleteExtra$", defaultValue: "false", showEl: "${sqlSyncToGrouperGroupSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupDeleteExtra = # Sync group alternate name from the alternate_name column label # {valueType: "boolean", order: 23000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupSyncFieldAlternateName$", defaultValue: "false", showEl: "${sqlSyncToGrouperGroupSync && !sqlSyncToGrouperAutoconfigureColumns}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupSyncFieldAlternateName = # Sync group description from the description column label # {valueType: "boolean", order: 24000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupSyncFieldDescription$", defaultValue: "false", showEl: "${sqlSyncToGrouperGroupSync && !sqlSyncToGrouperAutoconfigureColumns}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupSyncFieldDescription = # Sync group display name from the display_name column label # {valueType: "boolean", order: 25000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupSyncFieldDisplayName$", defaultValue: "false", showEl: "${sqlSyncToGrouperGroupSync && !sqlSyncToGrouperAutoconfigureColumns}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupSyncFieldDisplayName = # Sync group enabled and disabled dates from the disabled_timestamp and enabled_timestamp column label # {valueType: "boolean", order: 26000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupSyncFieldEnabledDisabled$", defaultValue: "false", showEl: "${sqlSyncToGrouperGroupSync && !sqlSyncToGrouperAutoconfigureColumns}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupSyncFieldEnabledDisabled = # Sync group ID index from the id_index column label # {valueType: "boolean", order: 27000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupSyncFieldIdIndexOnInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperGroupSync && !sqlSyncToGrouperAutoconfigureColumns && sqlSyncToGrouperGroupInsert}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupSyncFieldIdIndexOnInsert = # Sync group ID from the id column label # {valueType: "boolean", order: 28000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupSyncFieldIdOnInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperGroupSync && !sqlSyncToGrouperAutoconfigureColumns && sqlSyncToGrouperGroupInsert}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupSyncFieldIdOnInsert = # Sync group group type from the type_of_group column label # {valueType: "boolean", order: 29000, subSection: "sqlSyncToGrouperGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperGroupSyncFieldTypeOfGroup$", defaultValue: "false", showEl: "${sqlSyncToGrouperGroupSync && !sqlSyncToGrouperAutoconfigureColumns}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperGroupSyncFieldTypeOfGroup = # True to sync composites to Grouper # {valueType: "boolean", order: 30000, subSection: "sqlSyncToGrouperCompositeSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperCompositeSync$", defaultValue: "false"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperCompositeSync = # SQL to get composites from database # {valueType: "string", formElement: "textarea", order: 31000, subSection: "sqlSyncToGrouperCompositeSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperCompositeSql$", required: true, showEl: "${sqlSyncToGrouperCompositeSync && !sqlSyncToGrouperFromAnotherGrouper}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperCompositeSql = # Insert composites into Grouper # {valueType: "boolean", order: 32000, subSection: "sqlSyncToGrouperCompositeSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperCompositeInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperCompositeSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperCompositeInsert = # Update composites in Grouper # {valueType: "boolean", order: 33000, subSection: "sqlSyncToGrouperCompositeSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperCompositeUpdate$", defaultValue: "false", showEl: "${sqlSyncToGrouperCompositeSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperCompositeUpdate = # Delete composites in Grouper which are in the "folders to sync" which are not in the other database # {valueType: "boolean", order: 34000, subSection: "sqlSyncToGrouperCompositeSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperCompositeDeleteExtra$", defaultValue: "false", showEl: "${sqlSyncToGrouperCompositeSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperCompositeDeleteExtra = # Sync composite ID (UUID) from the id column label # {valueType: "boolean", order: 35000, subSection: "sqlSyncToGrouperCompositeSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperCompositeSyncFieldIdOnInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperCompositeSync && !sqlSyncToGrouperAutoconfigureColumns && sqlSyncToGrouperCompositeInsert}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperCompositeSyncFieldIdOnInsert = # True to sync memberships to Grouper # {valueType: "boolean", order: 36000, subSection: "sqlSyncToGrouperMembershipSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperMembershipSync$", defaultValue: "false"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperMembershipSync = # SQL to get memberships from database # {valueType: "string", formElement: "textarea", order: 37000, subSection: "sqlSyncToGrouperMembershipSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperMembershipSql$", required: true, showEl: "${sqlSyncToGrouperMembershipSync && !sqlSyncToGrouperFromAnotherGrouper}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperMembershipSql = # Insert memberships into Grouper # {valueType: "boolean", order: 38000, subSection: "sqlSyncToGrouperMembershipSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperMembershipInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperMembershipSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperMembershipInsert = # Update memberships in Grouper # {valueType: "boolean", order: 39000, subSection: "sqlSyncToGrouperMembershipSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperMembershipUpdate$", defaultValue: "false", showEl: "${sqlSyncToGrouperMembershipSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperMembershipUpdate = # Delete memberships in Grouper which are in the "memberships to sync" which are not in the other database # {valueType: "boolean", order: 40000, subSection: "sqlSyncToGrouperMembershipSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperMembershipDeleteExtra$", defaultValue: "false", showEl: "${sqlSyncToGrouperMembershipSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperMembershipDeleteExtra = # Sync membership enabled and disabled times from immediate_mship_disabled_time and immediate_mship_enabled_time column labels # {valueType: "boolean", order: 41000, subSection: "sqlSyncToGrouperMembershipSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperMembershipSyncFieldsEnabledDisabled$", defaultValue: "false", showEl: "${sqlSyncToGrouperMembershipSync && !sqlSyncToGrouperAutoconfigureColumns}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperMembershipSyncFieldsEnabledDisabled = # Sync membership ID from the immediate_membership_id column label # {valueType: "boolean", order: 42000, subSection: "sqlSyncToGrouperMembershipSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperMembershipSyncFieldIdOnInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperMembershipSync && !sqlSyncToGrouperAutoconfigureColumns && sqlSyncToGrouperMembershipInsert}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperMembershipSyncFieldIdOnInsert = # True to sync group privileges to Grouper # {valueType: "boolean", order: 43000, subSection: "sqlSyncToGrouperPrivilegeGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperPrivilegeGroupSync$", defaultValue: "false"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperPrivilegeGroupSync = # SQL to get group privileges from database # {valueType: "string", formElement: "textarea", order: 44000, subSection: "sqlSyncToGrouperPrivilegeGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperPrivilegeGroupSql$", required: true, showEl: "${sqlSyncToGrouperPrivilegeGroupSync && !sqlSyncToGrouperFromAnotherGrouper}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperPrivilegeGroupSql = # Insert group privileges into Grouper # {valueType: "boolean", order: 45000, subSection: "sqlSyncToGrouperPrivilegeGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperPrivilegeGroupInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperPrivilegeGroupSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperPrivilegeGroupInsert = # Delete group privileges in Grouper which are in the "group privileges to sync" which are not in the other database # {valueType: "boolean", order: 46000, subSection: "sqlSyncToGrouperPrivilegeGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperPrivilegeGroupDeleteExtra$", defaultValue: "false", showEl: "${sqlSyncToGrouperPrivilegeGroupSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperPrivilegeGroupDeleteExtra = # Sync group privilege ID from the immediate_membership_id column label # {valueType: "boolean", order: 47000, subSection: "sqlSyncToGrouperPrivilegeGroupSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperPrivilegeGroupSyncFieldIdOnInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperPrivilegeGroupSync && !sqlSyncToGrouperAutoconfigureColumns && sqlSyncToGrouperPrivilegeGroupInsert}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperPrivilegeGroupSyncFieldIdOnInsert = # True to sync stem privileges to Grouper # {valueType: "boolean", order: 48000, subSection: "sqlSyncToGrouperPrivilegeStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperPrivilegeStemSync$", defaultValue: "false"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperPrivilegeStemSync = # SQL to get stem privileges from database # {valueType: "string", formElement: "textarea", order: 49000, subSection: "sqlSyncToGrouperPrivilegeStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperPrivilegeStemSql$", required: true, showEl: "${sqlSyncToGrouperPrivilegeStemSync && !sqlSyncToGrouperFromAnotherGrouper}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperPrivilegeStemSql = # Insert stem privileges into Grouper # {valueType: "boolean", order: 50000, subSection: "sqlSyncToGrouperPrivilegeStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperPrivilegeStemInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperPrivilegeStemSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperPrivilegeStemInsert = # Delete stem privileges in Grouper which are in the "stem privileges to sync" which are not in the other database # {valueType: "boolean", order: 51000, subSection: "sqlSyncToGrouperPrivilegeStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperPrivilegeStemDeleteExtra$", defaultValue: "false", showEl: "${sqlSyncToGrouperPrivilegeStemSync}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperPrivilegeStemDeleteExtra = # Sync stem privilege ID from the immediate_membership_id column label # {valueType: "boolean", order: 52000, subSection: "sqlSyncToGrouperPrivilegeStemSync", regex: "^otherJob\\.([^.]+)\\.sqlSyncToGrouperPrivilegeStemSyncFieldIdOnInsert$", defaultValue: "false", showEl: "${sqlSyncToGrouperPrivilegeStemSync && !sqlSyncToGrouperAutoconfigureColumns && sqlSyncToGrouperPrivilegeStemInsert}"} # otherJob.syncToGrouperFromSqlConfigId.sqlSyncToGrouperPrivilegeStemSyncFieldIdOnInsert = ##################################################### ## LDAP to SQL sync ##################################################### # Set this class to enable the email notification # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase"} # otherJob.ldapToSqlSyncConfigId.class = edu.internet2.middleware.grouper.app.ldapToSql.LdapToSqlSyncDaemon # Cron string # {valueType: "cron"} # otherJob.ldapToSqlSyncConfigId.quartzCron = 0 03 5 * * ? # Sql connection id (of your database external systems) where the data table is # {valueType: "string", order: 1000, subSection: "ldapToSqlLdap", regex: "^otherJob\\.([^.]+)\\.ldapSqlLdapConnection$", required: true, formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.externalSystem.LdapGrouperExternalSystem"} # otherJob.ldapToSqlSyncConfigId.ldapSqlLdapConnection = # Base DN where LDAP filter should search for records, e.g. (&(employeeID=*)(pwdLastSet=*)) # {valueType: "string", order: 2000, subSection: "ldapToSqlLdap", regex: "^otherJob\\.([^.]+)\\.ldapSqlBaseDn$", required: true} # otherJob.ldapToSqlSyncConfigId.ldapSqlBaseDn = # Search scope: OBJECT_SCOPE, ONELEVEL_SCOPE, SUBTREE_SCOPE # {valueType: "string", order: 3000, subSection: "ldapToSqlLdap", regex: "^otherJob\\.([^.]+)\\.ldapSqlSearchScope$", required: true, formElement: "dropdown", optionValues: ["OBJECT_SCOPE", "ONELEVEL_SCOPE", "SUBTREE_SCOPE"]} # otherJob.ldapToSqlSyncConfigId.ldapSqlSearchScope = # LDAP filter that pulls data back from LDAP # {valueType: "string", order: 4000, subSection: "ldapToSqlLdap", regex: "^otherJob\\.([^.]+)\\.ldapSqlFilter$", required: true} # otherJob.ldapToSqlSyncConfigId.ldapSqlFilter = # Comma-separated extra attributes if one column has multiple attributes concatenated used in translations # {valueType: "string", order: 5000, subSection: "ldapToSqlLdap", regex: "^otherJob\\.([^.]+)\\.ldapSqlExtraAttributes$"} # otherJob.ldapToSqlSyncConfigId.ldapSqlExtraAttributes = # Sql connection id (of your database external systems) where the data table is # {valueType: "string", order: 20000, subSection: "ldapToSqlDatabase", regex: "^otherJob\\.([^.]+)\\.ldapSqlDbConnection$", required: true, formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.loader.db.DatabaseGrouperExternalSystem"} # otherJob.ldapToSqlSyncConfigId.ldapSqlDbConnection = # Table name where ldap data should sync to, note you need to prefix the schema if not in the connecting schema # {valueType: "string", order: 21000, subSection: "ldapToSqlDatabase", regex: "^otherJob\\.([^.]+)\\.ldapSqlTableName$", required: true} # otherJob.ldapToSqlSyncConfigId.ldapSqlTableName = # Number of attributes and columns # {valueType: "string", order: 22000, subSection: "ldapToSqlDatabase", regex: "^otherJob\\.([^.]+)\\.ldapSqlNumberOfAttributes$", required: true, formElement: "dropdown", optionValues: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30"]} # otherJob.ldapToSqlSyncConfigId.ldapSqlNumberOfAttributes = # Name of SQL column or use # {valueType: "string", order: 30000, regex: "^otherJob\\.([^.]+)\\.ldapSqlAttribute\\.\\d+\\.sqlColumn$", required: true, showEl: "${ldapSqlNumberOfAttributes > $i$}", repeatGroup: "ldapToSqlAttribute", repeatCount: 30} # otherJob.ldapToSqlSyncConfigId.ldapSqlAttribute.$i$.sqlColumn = # Name of LDAP attribute or use dn for the distinguishedName. If the attribute is multi-valued, then there should only be two columns, a single-valued attribute and a multi-valued attribute # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.ldapSqlAttribute\\.\\d+\\.ldapName$", showEl: "${ldapSqlNumberOfAttributes > $i$}", repeatGroup: "ldapToSqlAttribute", repeatCount: 30} # otherJob.ldapToSqlSyncConfigId.ldapSqlAttribute.$i$.ldapName = # Enter a translation if there is no ldap attribute or if it needs to be adjusted. "dn" is a variable, and ldapAttribute__<attributename> (attribute name is lower case). # All attributes and extraAttributes can be used. loaderLdapElUtils can be used, and ldapLookup. e.g. ${ldapAttribute__lastname + ", + ldapAttribute__firstname} # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.ldapSqlAttribute\\.\\d+\\.translation$", showEl: "${ldapSqlNumberOfAttributes > $i$}", repeatGroup: "ldapToSqlAttribute", repeatCount: 30} # otherJob.ldapToSqlSyncConfigId.ldapSqlAttribute.$i$.translation = # If this is the unique or one column in a composite key # {valueType: "boolean", regex: "^otherJob\\.([^.]+)\\.ldapSqlAttribute\\.\\d+\\.uniqueKey$", defaultValue: "false", showEl: "${ldapSqlNumberOfAttributes > $i$}", repeatGroup: "ldapToSqlAttribute", repeatCount: 30} # otherJob.ldapToSqlSyncConfigId.ldapSqlAttribute.$i$.uniqueKey = ##################################################### ## Script daemons ## "scriptDaemonConfigKey" is the key of the config, change that for your script daemon ##################################################### # set this to enable the script daemon # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase"} # otherJob.scriptDaemonConfigKey.class = edu.internet2.middleware.grouper.app.loader.OtherJobScript # cron string # {valueType: "cron", required: true} # otherJob.scriptDaemonConfigKey.quartzCron = 0 38 6 * * ? # script type. note: in SQL you should commit after DML commands. # {valueType: "string", required: true, regex: "^otherJob\\.([^.]+)\\.scriptType$", formElement: "dropdown", optionValues: ["gsh", "sql"]} # otherJob.scriptDaemonConfigKey.scriptType = # file type, you can run a script in config, or run a file in your container # {valueType: "string", required: true, regex: "^otherJob\\.([^.]+)\\.fileType$", formElement: "dropdown", optionValues: ["script", "file"]} # otherJob.scriptDaemonConfigKey.fileType = # source of script # {valueType: "string", required: true, regex: "^otherJob\\.([^.]+)\\.scriptSource$", formElement: "textarea", showEl: "${fileType == 'script'}"} # otherJob.scriptDaemonConfigKey.scriptSource = # file name in container to run # {valueType: "string", required: true, regex: "^otherJob\\.([^.]+)\\.fileName$", showEl: "${fileType == 'file'}"} # otherJob.scriptDaemonConfigKey.fileName = # if SQL this is the connection name to use # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.connectionName$", showEl: "${scriptType == 'sql'}", formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.loader.db.DatabaseGrouperExternalSystem"} # otherJob.scriptDaemonConfigKey.connectionName = # if this is a lightweight script, i.e. not as many imports # {valueType: "boolean", regex: "^otherJob\\.([^.]+)\\.lightWeight$", showEl: "${scriptType == 'gsh'}", defaultValue: "false"} # otherJob.scriptDaemonConfigKey.lightWeight = ##################################################### ## CSV reports ## "reportId" is the key of the config, change that for your csv report ##################################################### # set this to enable the report # {valueType: "class", readOnly: true, mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase"} # otherJob.reportId.class = edu.internet2.middleware.grouper.app.reports.GrouperCsvReportJob # cron string # {valueType: "cron"} # otherJob.reportId.quartzCron = 0 21 7 * * ? # query to run # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.csvReport\\.query$"} # otherJob.reportId.csvReport.query = select USER_ID, USER_NAME, EMAIL_ADDRESS, AUTH_TYPE, TITLE, DEPARTMENT, CUSTOM_STRING, DAY_PASS, CUSTOM_STRING2, GROUPS from some_view # database to hit # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.csvReport\\.database$"} # otherJob.reportId.csvReport.database = pennCommunity # remove underscores and capitalize headers, go from USER_NAME to UserName # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.csvReport\\.removeUnderscoresAndCapitalizeHeaders$"} # otherJob.reportId.csvReport.removeUnderscoresAndCapitalizeHeaders = false # fileName, e.g. myFile.csv or /opt/whatever/myFile.csv. If blank will create a name # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.csvReport\\.database$"} # otherJob.reportId.csvReport.fileName = MyFile.csv # sftp config id (from grouper.properties) if sftp'ing this file somewhere, otherwise blank # https://spaces.at.internet2.edu/display/Grouper/Grouper+Sftp+files # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.csvReport\\.sftp\\.configId$"} # otherJob.reportId.csvReport.sftp.configId = someSftpServer # remote file to sftp to if sftp'ing # {valueType: "string", regex: "^otherJob\\.([^.]+)\\.csvReport\\.sftp\\.fileNameRemote$"} # otherJob.reportId.csvReport.sftp.fileNameRemote = /data01/whatever/MyFile.csv # if the file should be deleted from the grouper daemon server after sending it # {valueType: "boolean", regex: "^otherJob\\.([^.]+)\\.csvReport\\.deleteFile$"} # otherJob.reportId.csvReport.deleteFile = true ############################ ## Incremental loader jobs ############################ # incremental loader job class # {valueType: "class", readOnly: true, regex: "^otherJob.([^.]+).class$", mustExtendClass: "edu.internet2.middleware.grouper.app.loader.GrouperLoaderIncrementalJob"} # otherJob.incrementalLoader1.class = edu.internet2.middleware.grouper.app.loader.GrouperLoaderIncrementalJob # incremental loader job cron # {valueType: "cron", regex: "^otherJob.([^.]+).quartzCron$"} # otherJob.incrementalLoader1.quartzCron = 0 * * * * ? # incremental loader job database name # {valueType: "string", regex: "^otherJob.([^.]+).databaseName$"} # otherJob.incrementalLoader1.databaseName=warehouse # incremental loader job table name # {valueType: "string", regex: "^otherJob.([^.]+).tableName$"} # otherJob.incrementalLoader1.tableName=myincrementaltable # incremental loader full sync threshold # If there are more than this many changes for a single loader job, then invoke the full sync instead. This could improve performance but also handle fail safe which isn't part of the incremental sync. # {valueType: "integer", regex: "^otherJob.([^.]+).fullSyncThreshold$"} # otherJob.incrementalLoader1.fullSyncThreshold=100 # whether subject lookups in the data source should be case insensitive. only applicable for sql loader jobs. note, if true, for some databases (e.g. oracle), you may need a function based index in your data source for the function "lower" for better performance # {valueType: "boolean", regex: "^otherJob.([^.]+).caseInsensitiveSubjectLookupsInDataSource$"} # otherJob.incrementalLoader1.caseInsensitiveSubjectLookupsInDataSource=false ############# ## Quartz settings ############# # quartz schedule instance name # {valueType: "string", required: true} org.quartz.scheduler.instanceName = DefaultQuartzScheduler # quartz scheduler instnace id # {valueType: "string", required: true} org.quartz.scheduler.instanceId = AUTO # quartz scheduler rmi export # {valueType: "boolean", required: true} org.quartz.scheduler.rmi.export = false # quartz scheduler rmi proxy # {valueType: "boolean", required: true} org.quartz.scheduler.rmi.proxy = false # quartz scheduler wrap job executiong transaction # {valueType: "boolean", required: true} org.quartz.scheduler.wrapJobExecutionInUserTransaction = false # quartz scheduler thread pool class # {valueType: "class", required: true, mustImplementInterface: "org.quartz.spi.ThreadPool"} org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool # quartz scheduler thread count # {valueType: "integer", required: true} org.quartz.threadPool.threadCount = 10 # quartz scheduler thread priority # {valueType: "integer", required: true} org.quartz.threadPool.threadPriority = 5 # quartz scheduler threads inherit context class # {valueType: "boolean", required: true} org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true # quartz scheduler misfire threshold # {valueType: "integer", required: true} org.quartz.jobStore.misfireThreshold = 60000 # quartz scheduler jobstore class # {valueType: "class", required: true, mustImplementInterface: "org.quartz.spi.JobStore"} org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX # quartz scheduler data source # {valueType: "string"} org.quartz.jobStore.dataSource = myDS # quartz scheduler table prefix # {valueType: "string"} org.quartz.jobStore.tablePrefix = grouper_QZ_ # quartz scheduler is clustered # {valueType: "boolean", required: true} org.quartz.jobStore.isClustered = true # quartz scheduler check in interval # {valueType: "integer", required: true} org.quartz.jobStore.clusterCheckinInterval = 20000 # automatically determined but can override # {valueType: "class"} org.quartz.jobStore.driverDelegateClass = # get connections from grouper's database pool # {valueType: "class"} org.quartz.dataSource.myDS.connectionProvider.class = edu.internet2.middleware.grouper.app.loader.GrouperQuartzConnectionProvider # Quartz seems to have issues where sometimes a job is running twice at the same time, usually after a misfire. # We have our own check to make sure jobs don't overlap based on data in the grouper_loader_log table if a job's status is STARTED. # However, if the daemon is killed, it may be stuck on the STARTED state until the row is deleted. So we'll consider a job's # STARTED state to be invalid if it hasn't been updated in the number of seconds below. # {valueType: "integer", required: true} loader.assumeJobKilledIfNoUpdateInSeconds=300 ############# ## Provisioning and sync settings ############# # delete metadata information about things not provisioned anymore and removed from target (default 1 week) # {valueType: "integer"} grouper.provisioning.removeSyncRowsAfterSecondsOutOfTarget = 604800 # If there are this number of memberships or more for a single provisionable group, then perform a "group sync" instead of the individual operations instead, for efficiency # {valueType: "integer", defaultValue: "500"} provisionerDefault.membershipsConvertToGroupSyncThreshold = # If there are this number of memberships or more for a single provisionable group, then perform a "group sync" instead of the individual operations instead, for efficiency # {valueType: "integer", defaultValue: "500"} provisionerDefault.membershipsConvertToGroupSyncThreshold = # In incremental processing, each provisionable group/entity to sync memberships counts as 10, # each provisionable membership to sync counts as 1. If the total score is more than this number, # it will convert the incrementals to a a full sync. e.g. 10000 individual memberships to sync # (and not more than 500 in a single group), or 1000 groups to sync, or a combination. # -1 means do not convert to full sync. This is an overridable default. Each provisioner can override. # {valueType: "integer", defaultValue: "10000"} provisionerDefault.scoreConvertToFullSyncThreshold = ####################################### ## common provisioner settings ####################################### # Operate on grouper memberships # {valueType: "boolean", order: 500, defaultValue: "false", subSection: "membership"} # provisioner.genericProvisioner.operateOnGrouperMemberships = # groupAttributes: group ldap object has attribute to hold memberships. # entityAttributes: user ldap object has attribute to hold memberships # {valueType: "string", required: true, order: 1000, subSection: "membership", showEl: "${operateOnGrouperMemberships}", formElement: "dropdown", optionValues: ["groupAttributes", "entityAttributes", "membershipObjects"]} # provisioner.genericProvisioner.provisioningType = # Select memberships # {valueType: "boolean", order: 1500, defaultValue: "false", subSection: "membership", showEl: "${operateOnGrouperMemberships}"} # provisioner.genericProvisioner.selectMemberships = # Insert memberships # {valueType: "boolean", order: 2500, defaultValue: "false", subSection: "membership", showEl: "${operateOnGrouperMemberships}"} # provisioner.genericProvisioner.insertMemberships = # Delete memberships # {valueType: "boolean", order: 3500, defaultValue: "false", subSection: "membership", showEl: "${operateOnGrouperMemberships}"} # provisioner.genericProvisioner.deleteMemberships = # Delete memberships if not exist in grouper # {valueType: "boolean", order: 4500, defaultValue: "false", subSection: "membership", showEl: "${operateOnGrouperMemberships && deleteMemberships}"} # provisioner.genericProvisioner.deleteMembershipsIfNotExistInGrouper = # Delete memberships if deleted in grouper # {valueType: "boolean", order: 5500, defaultValue: "false", subSection: "membership", showEl: "${operateOnGrouperMemberships && deleteMemberships && deleteMembershipsIfNotExistInGrouper == false}"} # provisioner.genericProvisioner.deleteMembershipsIfGrouperDeleted = # Delete memberships if deleted in grouper # {valueType: "boolean", order: 5600, defaultValue: "false", subSection: "membership", showEl: "${operateOnGrouperMemberships && deleteMemberships && deleteMembershipsIfNotExistInGrouper == false && deleteMembershipsIfGrouperDeleted == false}"} # provisioner.genericProvisioner.deleteMembershipsIfGrouperCreated = # Operate on grouper groups # {valueType: "boolean", order: 7500, defaultValue: "false", subSection: "group"} # provisioner.genericProvisioner.operateOnGrouperGroups = # Select groups # {valueType: "boolean", order: 8500, defaultValue: "false", subSection: "group", showEl: "${operateOnGrouperGroups}"} # provisioner.genericProvisioner.selectGroups = # Insert groups # {valueType: "boolean", order: 9000, subSection: "group", defaultValue: "false", showEl: "${operateOnGrouperGroups}"} # provisioner.genericProvisioner.insertGroups = # Delete groups # {valueType: "boolean", order: 9500, defaultValue: "false", subSection: "group", showEl: "${operateOnGrouperGroups}"} # provisioner.genericProvisioner.deleteGroups = # Delete groups if not exist in grouper # {valueType: "boolean", order: 10000, defaultValue: "false", subSection: "group", showEl: "${operateOnGrouperGroups && deleteGroups}"} # provisioner.genericProvisioner.deleteGroupsIfNotExistInGrouper = # Delete groups if deleted in grouper # {valueType: "boolean", order: 10500, defaultValue: "false", subSection: "group", showEl: "${operateOnGrouperGroups && deleteGroups && deleteGroupsIfNotExistInGrouper == false}"} # provisioner.genericProvisioner.deleteGroupsIfGrouperDeleted = # Delete groups if not exist in grouper # {valueType: "boolean", order: 10600, defaultValue: "false", subSection: "group", showEl: "${operateOnGrouperGroups && deleteGroups && deleteGroupsIfNotExistInGrouper == false && deleteGroupsIfGrouperDeleted == false}"} # provisioner.genericProvisioner.deleteGroupsIfGrouperCreated = # Update groups # {valueType: "boolean", order: 11500, defaultValue: "false", subSection: "group", showEl: "${operateOnGrouperGroups}"} # provisioner.genericProvisioner.updateGroups = # if the groups need to be resolved in target # {valueType: "boolean", defaultValue: "false", subSection: "group", showEl:"${operateOnGrouperGroups && selectGroups}", order: 12000} # provisioner.genericProvisioner.hasTargetGroupLink = # number of attributes for target groups # {valueType: "integer", order: 19999, subSection: "group", defaultValue: "0", showEl:"${operateOnGrouperGroups}", formElement: "dropdown", optionValues: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20"] } # provisioner.genericProvisioner.numberOfGroupAttributes = # Is field else attribute? # {valueType: "boolean", order: 20000, required: "true", showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.isFieldElseAttribute = # Name of the attribute # {valueType: "string", order: 21000, required: true, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && !targetGroupAttribute.$i$.isFieldElseAttribute}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.name = # Name of the field # {valueType: "string", order: 21001, required: true, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && targetGroupAttribute.$i$.isFieldElseAttribute}", formElement: "dropdown", optionValues: ["id", "idIndex", "name", "displayName"], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.fieldName = # Value type # {valueType: "string", order: 22000, defaultValue: "string", showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$}", formElement: "dropdown", optionValues: ["string", "long", "int"], repeatGroup: "targetGroupAttribute", repeatCount: 20 } # provisioner.genericProvisioner.targetGroupAttribute.$i$.valueType = # Multi-valued attribute? # {valueType: "boolean", order: 22100, defaultValue: "false", showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.multiValued = # Membership attribute? # {valueType: "boolean", order: 22200, defaultValue: "false", showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && provisioningType == 'groupAttributes' && targetGroupAttribute.$i$.multiValued}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.membershipAttribute = # During the translation, use this sync field. If not using a built-in (e.g. subjectId), you can map an entity field to a gcGrouperSyncMember field # {valueType: "string", required: true, order: 22300, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && targetGroupAttribute.$i$.membershipAttribute && provisioningType == 'groupAttributes' && targetGroupAttribute.$i$.multiValued}", formElement: "dropdown", optionValues: ["memberId", "subjectId", "subjectIdentifier", "memberFromId2", "memberFromId3", "memberToId2", "memberToId3"], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.translateFromMemberSyncField = # Select attribute? # {valueType: "boolean", order: 22500, defaultValue: "false", showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && selectGroups && !targetGroupAttribute.$i$.membershipAttribute}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.select = # Insert attribute? # {valueType: "boolean", order: 23000, defaultValue: "false", showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && insertGroups && !targetGroupAttribute.$i$.membershipAttribute}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.insert = # Update attribute? # {valueType: "boolean", order: 24000, defaultValue: "false", showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && updateGroups && !targetGroupAttribute.$i$.membershipAttribute}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.update = # Ignore this group if this attribute matches any of these values (comma separated) # {valueType: "string", order: 25500, multiple: true, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.ignoreIfMatchesValue = # Matching id attribute? # {valueType: "boolean", order: 27000, defaultValue: "false", showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.matchingId = # Default value if there is not a value # {valueType: "string", order: 29000, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.defaultValue = # If a value is required to provision this group # {valueType: "boolean", order: 29250, defaultValue: "false", showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.required = # Maximum length of this field to be valid for provisioning # {valueType: "integer", order: 29500, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.maxlength = # Validate value with jexl to see if valid for provisioning, the variable 'value' represents the current value. return true if valid and false if invalid # {valueType: "string", order: 29750, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.validExpression = # Search attribute? # {valueType: "boolean", order: 31000, defaultValue: "false", showEl: "${operateOnGrouperGroups && selectGroups && numberOfGroupAttributes > $i$ && !targetGroupAttribute.$i$.multiValued && targetGroupAttribute.$i$.select}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.searchAttribute = # Translate expression create only type # {valueType: "string", order: 31300, required: false, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && targetGroupAttribute.$i$.membershipAttribute == false && targetGroupAttribute.$i$.insert && targetGroupAttribute.$i$.update}", formElement: "dropdown", optionValues: ["grouperProvisioningGroupField", "translationScript"], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.translateExpressionTypeCreateOnly = # Translate from field create only # {valueType: "string", order: 31600, required: true, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && !targetGroupAttribute.$i$.membershipAttribute && targetGroupAttribute.$i$.translateExpressionTypeCreateOnly == 'grouperProvisioningGroupField'}", formElement: "dropdown", optionValues: ["id", "idIndex", "idIndexString", "displayExtension", "displayName", "extension", "name", "attribute__description"], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.translateFromGrouperProvisioningGroupFieldCreateOnly = # Translate expression create only # {valueType: "string", order: 32000, required: false, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && targetGroupAttribute.$i$.membershipAttribute == false && targetGroupAttribute.$i$.insert && targetGroupAttribute.$i$.update && targetGroupAttribute.$i$.translateExpressionType == 'translationScript'}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.translateExpressionCreateOnly = # Translate type # {valueType: "string", order: 32300, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && targetGroupAttribute.$i$.membershipAttribute == false}", formElement: "dropdown", optionValues: ["grouperProvisioningGroupField", "translationScript"], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.translateExpressionType = # Translate from field # {valueType: "string", order: 32600, required: true, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && !targetGroupAttribute.$i$.membershipAttribute && targetGroupAttribute.$i$.translateExpressionType == 'grouperProvisioningGroupField'}", formElement: "dropdown", optionValues: ["id", "idIndex", "idIndexString", "displayExtension", "displayName", "extension", "name", "attribute__description"], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.translateFromGrouperProvisioningGroupField = # Translate expression # {valueType: "string", order: 33000, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && targetGroupAttribute.$i$.membershipAttribute == false && targetGroupAttribute.$i$.translateExpressionType == 'translationScript'}", repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.translateExpression = # During 'group link' copy this value from the target into the sync field # {valueType: "string", order: 35500, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && !targetGroupAttribute.$i$.membershipAttribute && hasTargetGroupLink}", formElement: "dropdown", optionValues: ["groupFromId2", "groupFromId3", "groupToId2", "groupToId3"], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.translateToGroupSyncField = # After calculating the Grouper value store that in a sync field # {valueType: "string", order: 35700, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && !targetGroupAttribute.$i$.membershipAttribute}", formElement: "dropdown", optionValues: ["groupFromId2", "groupFromId3", "groupToId2", "groupToId3"], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetGroupAttribute.$i$.translateGrouperToGroupSyncField = # Operate on grouper entities # {valueType: "boolean", order: 37000, defaultValue: "false", subSection: "entity"} # provisioner.genericProvisioner.operateOnGrouperEntities = # Select entities # {valueType: "boolean", order: 37500, defaultValue: "false", subSection: "entity", showEl: "${operateOnGrouperEntities}"} # provisioner.genericProvisioner.selectEntities = # Insert entities # {valueType: "boolean", order: 38000, subSection: "entity", defaultValue: "false", showEl: "${operateOnGrouperEntities}"} # provisioner.genericProvisioner.insertEntities = # Delete entities # {valueType: "boolean", order: 39000, subSection: "entity", defaultValue: "false", showEl: "${operateOnGrouperEntities}"} # provisioner.genericProvisioner.deleteEntities = # Delete entities if not exist in grouper # {valueType: "boolean", order: 39500, defaultValue: "false", subSection: "entity", showEl: "${operateOnGrouperEntities && deleteEntities}"} # provisioner.genericProvisioner.deleteEntitiesIfNotExistInGrouper = # Delete entities if deleted in grouper # {valueType: "boolean", order: 40000, defaultValue: "false", subSection: "entity", showEl: "${operateOnGrouperEntities && deleteEntities && !deleteEntitiesIfNotExistInGrouper}"} # provisioner.genericProvisioner.deleteEntitiesIfGrouperDeleted = # Delete entities if not exist in grouper # {valueType: "boolean", order: 40100, defaultValue: "false", subSection: "entity", showEl: "${operateOnGrouperEntities && deleteEntities && !deleteEntitiesIfNotExistInGrouper && !deleteEntitiesIfGrouperDeleted}"} # provisioner.genericProvisioner.deleteEntitiesIfGrouperCreated = # Update entities # {valueType: "boolean", order: 41000, defaultValue: "false", subSection: "entity", showEl: "${operateOnGrouperEntities}"} # provisioner.genericProvisioner.updateEntities = # subject sources to provision # {valueType: "string", required: true, order: 45000, multiple: true, subSection: "entity", showEl: "${operateOnGrouperEntities}", formElement: "checkbox", checkboxValuesFromClass: "edu.internet2.middleware.grouper.SubjectFinder"} # provisioner.genericProvisioner.subjectSourcesToProvision = # If the subject api is needed before provisioning to ldap # {valueType: "boolean", defaultValue: "false", order: 46000, subSection: "entity", showEl: "${operateOnGrouperEntities}"} # provisioner.genericProvisioner.hasSubjectLink = # if the entities need to be resolved in target # {valueType: "boolean", defaultValue: "false", showEl:"${operateOnGrouperEntities && selectEntities}", order: 53000, subSection: "entity"} # provisioner.genericProvisioner.hasTargetEntityLink = # number of attributes for target entities # {valueType: "integer", order: 59000, subSection: "entity", defaultValue: "0", showEl:"${operateOnGrouperEntities}", formElement: "dropdown", optionValues: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20"] } # provisioner.genericProvisioner.numberOfEntityAttributes = # Is field else attribute? # {valueType: "boolean", order: 60000, subSection: "entity", showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.isFieldElseAttribute = # Name of the attribute # {valueType: "string", order: 61000, required: true, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && !targetEntityAttribute.$i$.isFieldElseAttribute}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.name = # Name of the field # {valueType: "string", order: 61001, required: true, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && targetEntityAttribute.$i$.isFieldElseAttribute}", formElement: "dropdown", optionValues: ["id", "loginId", "subjectId", "name", "email"], repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.fieldName = # Value type # {valueType: "string", order: 62000, defaultValue: "string", showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$}", formElement: "dropdown", optionValues: ["string", "long", "int"], repeatGroup: "targetEntityAttribute", repeatCount: 20 } # provisioner.genericProvisioner.targetEntityAttribute.$i$.valueType = # Multi-valued attribute? # {valueType: "boolean", order: 62200, defaultValue: "false", showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.multiValued = # Membership attribute? # {valueType: "boolean", order: 62400, defaultValue: "false", showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && provisioningType == 'entityAttributes' && targetEntityAttribute.$i$.multiValued}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.membershipAttribute = # During the translation, use this sync field # {valueType: "string", order: 62600, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && provisioningType == 'entityAttributes' && targetEntityAttribute.$i$.membershipAttribute}", formElement: "dropdown", optionValues: ["groupId", "groupIdIndex", "groupExtension", "groupName", "groupFromId2", "groupFromId3", "groupToId2", "groupToId3"], repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.translateFromGroupSyncField = # Insert attribute? # {valueType: "boolean", order: 63000, defaultValue: "false", showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && insertEntities && !targetEntityAttribute.$i$.membershipAttribute}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.insert = # Update attribute? # {valueType: "boolean", order: 64000, defaultValue: "false", showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && updateEntities && !targetEntityAttribute.$i$.membershipAttribute}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.update = # Ignore entity if this attribute matches any of these values (comma separated) # {valueType: "string", order: 65500, multiple: true, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.ignoreIfMatchesValue = # Select attribute? # {valueType: "boolean", order: 66000, defaultValue: "false", showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && selectEntities && !targetEntityAttribute.$i$.membershipAttribute}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.select = # Matching id attribute? # {valueType: "boolean", order: 67000, defaultValue: "false", showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.matchingId = # Default value if there is not a value # {valueType: "string", order: 69000, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.defaultValue = # If a value is required to provision this entity # {valueType: "boolean", order: 69250, defaultValue: "false", showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.required = # Maximum length of this field to be valid for provisioning # {valueType: "string", order: 69500, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.maxlength = # Validate value with jexl to see if valid for provisioning # {valueType: "string", order: 69750, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.validExpression = # Search attribute? # {valueType: "boolean", order: 70500, defaultValue: "false", showEl: "${operateOnGrouperEntities && selectEntities && numberOfEntityAttributes > $i$ && !targetEntityAttribute.$i$.multiValued && targetEntityAttribute.$i$.select}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.searchAttribute = # Translate expression create only type # {valueType: "string", order: 70650, required: false, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && targetEntityAttribute.$i$.membershipAttribute == false && targetEntityAttribute.$i$.insert && targetEntityAttribute.$i$.update}", formElement: "dropdown", optionValues: ["grouperProvisioningEntityField", "translationScript"], repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.translateExpressionTypeCreateOnly = # Translate from field create only # {valueType: "string", order: 70750, required: true, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && !targetEntityAttribute.$i$.membershipAttribute && targetEntityAttribute.$i$.translateExpressionTypeCreateOnly == 'grouperProvisioningEntityField'}", formElement: "dropdown", optionValues: ["id", "email", "loginid", "name", "subjectId", "attribute__subjectSourceId", "attribute__description", "attribute__subjectIdentifier0"], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.translateFromGrouperProvisioningEntityFieldCreateOnly = # Translate expression create only # {valueType: "string", order: 72000, required: false, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && targetEntityAttribute.$i$.membershipAttribute == false && targetEntityAttribute.$i$.insert && targetEntityAttribute.$i$.translateExpressionTypeCreateOnly == 'translationScript'}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.translateExpressionCreateOnly = # Translate type # {valueType: "string", order: 72300, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && targetEntityAttribute.$i$.membershipAttribute == false}", formElement: "dropdown", optionValues: ["grouperProvisioningEntityField", "translationScript"], repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.translateExpressionType = # Translate from field # {valueType: "string", order: 72600, required: true, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && !targetEntityAttribute.$i$.membershipAttribute && targetEntityAttribute.$i$.translateExpressionType == 'grouperProvisioningEntityField'}", formElement: "dropdown", optionValues: ["id", "email", "loginid", "name", "subjectId", "attribute__subjectSourceId", "attribute__description", "attribute__subjectIdentifier0"], repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.translateFromGrouperProvisioningEntityField = # Translate expression # {valueType: "string", order: 73000, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && targetEntityAttribute.$i$.membershipAttribute == false && targetEntityAttribute.$i$.translateExpressionType == 'translationScript'}", repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.translateExpression = # During the entity link, copy this attribute to the sync field # {valueType: "string", order: 76000, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && targetEntityAttribute.$i$.membershipAttribute == false && hasTargetEntityLink}", formElement: "dropdown", optionValues: ["memberFromId2", "memberFromId3", "memberToId2", "memberToId3"], repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.translateToMemberSyncField = # After calculating the Grouper value store that in a sync field # {valueType: "string", order: 76200, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && !targetEntityAttribute.$i$.membershipAttribute}", formElement: "dropdown", optionValues: ["memberFromId2", "memberFromId3", "memberToId2", "memberToId3"], repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.translateGrouperToMemberSyncField = # Show provisioning diagnostics # {valueType: "boolean", order: 77000, defaultValue: "false", subSection: "provisioningDiagnostics"} # provisioner.genericProvisioner.showProvisioningDiagnostics = # Select all groups during diagnostics # {valueType: "boolean", order: 78000, defaultValue: "false", subSection: "provisioningDiagnostics", showEl: "${showProvisioningDiagnostics}"} # provisioner.genericProvisioner.selectAllGroupsDuringDiagnostics = # Select all entities during diagnostics # {valueType: "boolean", order: 79000, defaultValue: "false", subSection: "provisioningDiagnostics", showEl: "${showProvisioningDiagnostics}"} # provisioner.genericProvisioner.selectAllEntitiesDuringDiagnostics = # Select all memberships during diagnostics # {valueType: "boolean", order: 80000, defaultValue: "false", subSection: "provisioningDiagnostics", showEl: "${showProvisioningDiagnostics}"} # provisioner.genericProvisioner.selectAllMembershipsDuringDiagnostics = # Test group name # {valueType: "string", order: 81000, subSection: "provisioningDiagnostics", showEl: "${showProvisioningDiagnostics}"} # provisioner.genericProvisioner.testGroupName = # create group during diagnostics # {valueType: "boolean", order: 82000, defaultValue: "false", subSection: "provisioningDiagnostics", showEl: "${showProvisioningDiagnostics}"} # provisioner.genericProvisioner.createGroupDuringDiagnostics = # delete group during diagnostics # {valueType: "boolean", order: 83000, defaultValue: "false", subSection: "provisioningDiagnostics", showEl: "${showProvisioningDiagnostics}"} # provisioner.genericProvisioner.deleteGroupDuringDiagnostics = # Test subject id or identifier # {valueType: "string", order: 84000, subSection: "provisioningDiagnostics", showEl: "${showProvisioningDiagnostics}"} # provisioner.genericProvisioner.testSubjectIdOrIdentifier = # create entity during diagnostics # {valueType: "boolean", order: 85000, defaultValue: "false", subSection: "provisioningDiagnostics", showEl: "${showProvisioningDiagnostics}"} # provisioner.genericProvisioner.createEntityDuringDiagnostics = # delete entity during diagnostics # {valueType: "boolean", order: 86000, defaultValue: "false", subSection: "provisioningDiagnostics", showEl: "${showProvisioningDiagnostics}"} # provisioner.genericProvisioner.deleteEntityDuringDiagnostics = # Show assigning provisioning # {valueType: "boolean", subSection: "assigningProvisioning", order: 86500, defaultValue: "false"} # provisioner.genericProvisioner.showAssigningProvisioning = # Group allowed to assign # {valueType: "string", subSection: "assigningProvisioning", order: 86550, showEl: "${showAssigningProvisioning}"} # provisioner.genericProvisioner.groupAllowedToAssign = # Allow assignment only on one stem # {valueType: "boolean", subSection: "assigningProvisioning", defaultValue: "false", order: 86600, showEl: "${showAssigningProvisioning}"} # provisioner.genericProvisioner.allowAssignmentsOnlyOnOneStem = # Only provision policy groups # {valueType: "boolean", order: 86700, defaultValue: "false", subSection: "assigningProvisioning", showEl: "${showAssigningProvisioning}"} # provisioner.genericProvisioner.onlyProvisionPolicyGroups = # If you want a metadata item on folders for specifying if provision only policy groups # {valueType: "boolean", order: 86750, defaultValue: "true", subSection: "assigningProvisioning", showEl: "${showAssigningProvisioning}"} # provisioner.genericProvisioner.allowPolicyGroupOverride = # If you want to filter for groups in a provisionable folder by a regex on its name, specify here. If the regex matches then the group in the folder is provisionable. e.g. folderExtension matches ^.*_someExtension folderName matches ^.*_someExtension groupExtension matches ^.*_someExtension groupName matches ^.*_someExtension$ # {valueType: "String", order: 86775, subSection: "assigningProvisioning", showEl: "${showAssigningProvisioning}"} # provisioner.genericProvisioner.provisionableRegex = # If you want a metadata item on folders for specifying regex of names of objects to provision # {valueType: "boolean", order: 86800, defaultValue: "true", subSection: "assigningProvisioning", showEl: "${showAssigningProvisioning}"} # provisioner.genericProvisioner.allowProvisionableRegexOverride = # Configure metadata # {valueType: "boolean", order: 86790, defaultValue: "false", subSection: "metadata"} # provisioner.genericProvisioner.configureMetadata = # number of metadata # {valueType: "integer", order: 86800, subSection: "metadata", defaultValue: "0", formElement: "dropdown", showEl: "${configureMetadata}", optionValues: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20"] } # provisioner.genericProvisioner.numberOfMetadata = # name of metadata item. This will be the name in the json attribute and can be assigned to a group, entity, or membership attribute. # this should be unique across metadata for this provisioner. Must start with md_ # {valueType: "string", order: 86810, showEl: "${configureMetadata && numberOfMetadata > $i$}", repeatGroup: "metadata", repeatCount: 20} # provisioner.genericProvisioner.metadata.$i$.name = # if this metadata item should show when marking a folder as provisionable # {valueType: "boolean", order: 86840, defaultValue: "false", showEl: "${configureMetadata && numberOfMetadata > $i$}", repeatGroup: "metadata", repeatCount: 20} # provisioner.genericProvisioner.metadata.$i$.showForFolder = # if this metadata item should show when marking a group as provisionable # {valueType: "boolean", order: 86850, defaultValue: "false", showEl: "${configureMetadata && numberOfMetadata > $i$}", repeatGroup: "metadata", repeatCount: 20} # provisioner.genericProvisioner.metadata.$i$.showForGroup = # if this metadata item should show when marking a member (entity) as provisionable # {valueType: "boolean", order: 86860, defaultValue: "false", showEl: "${configureMetadata && numberOfMetadata > $i$}", repeatGroup: "metadata", repeatCount: 20} # provisioner.genericProvisioner.metadata.$i$.showForMember = # if this metadata item should show when marking a membership as provisionable # {valueType: "boolean", order: 86870, defaultValue: "false", showEl: "${configureMetadata && numberOfMetadata > $i$}", repeatGroup: "metadata", repeatCount: 20} # provisioner.genericProvisioner.metadata.$i$.showForMembership = # value type from the web form # {valueType: "string", order: 86870, defaultValue: "string", showEl: "${configureMetadata && numberOfMetadata > $i$}", repeatGroup: "metadata", repeatCount: 20, formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.provisioning.GrouperProvisioningObjectMetadataItemValueType" } # provisioner.genericProvisioner.metadata.$i$.valueType = # if this item is required # {valueType: "boolean", order: 86875, defaultValue: "false", showEl: "${configureMetadata && numberOfMetadata > $i$}", repeatGroup: "metadata", repeatCount: 20 } # provisioner.genericProvisioner.metadata.$i$.required = # default value of the metadata if the user does not enter anything # {valueType: "string", order: 86880, showEl: "${configureMetadata && numberOfMetadata > $i$ && !metadata.$i$.required}", repeatGroup: "metadata", repeatCount: 20 } # provisioner.genericProvisioner.metadata.$i$.defaultValue = # form element type for value # {valueType: "string", order: 86890, defaultValue: "text", showEl: "${configureMetadata && numberOfMetadata > $i$ && metadata.$i$.valueType != 'boolean'}", repeatGroup: "metadata", repeatCount: 20, formElement: "dropdown", optionValues: ["text", "textarea", "dropdown"] } # provisioner.genericProvisioner.metadata.$i$.formElementType = # comma-separated drop down values, escape commas in values with the hex code &#x2c; # {valueType: "string", order: 86900, showEl: "${configureMetadata && numberOfMetadata > $i$ && metadata.$i$.formElementType == 'dropdown'}", repeatGroup: "metadata", repeatCount: 20 } # provisioner.genericProvisioner.metadata.$i$.dropdownValues = # group id that can update this value # {valueType: "string", order: 86920, showEl: "${configureMetadata && numberOfMetadata > $i$}", repeatGroup: "metadata", repeatCount: 20 } # provisioner.genericProvisioner.metadata.$i$.groupIdThatCanView = # group id that can update this value # {valueType: "string", order: 86930, showEl: "${configureMetadata && numberOfMetadata > $i$}", repeatGroup: "metadata", repeatCount: 20 } # provisioner.genericProvisioner.metadata.$i$.groupIdThatCanUpdate = # Show advanced options # {valueType: "boolean", order: 87000, defaultValue: "false", subSection: "advanced"} # provisioner.genericProvisioner.showAdvanced = # Can full sync # {valueType: "boolean", order: 88000, defaultValue: "true", subSection: "advanced", showEl: "${showAdvanced}"} # provisioner.genericProvisioner.canFullSync = # if the target should be checked before sending actions. e.g. if an addMember is made to a provisionable group, then check the target to see if the entity is already a member first. # {valueType: "boolean", order: 89000, defaultValue: "false", subSection: "advanced", showEl: "${showAdvanced}"} # provisioner.genericProvisioner.recalculateAllOperations = # enable debug log # {valueType: "boolean", subSection: "advanced", defaultValue: "false", order: 90000, showEl: "${showAdvanced}"} # provisioner.genericProvisioner.debugLog = # log all objects verbose # {valueType: "boolean", subSection: "advanced", defaultValue: "false", order: 91000, showEl: "${showAdvanced}"} # provisioner.genericProvisioner.logAllObjectsVerbose = # if the target should be checked before sending actions. e.g. if an addMember is made to a provisionable # group, then check the target to see if the entity is already a member first. # default to provisionerDefault.membershipsConvertToGroupSyncThreshold = 500 # {valueType: "integer", order: 92000, subSection: "advanced", showEl: "${showAdvanced}"} # provisioner.genericProvisioner.membershipsConvertToGroupSyncThreshold = # In incremental processing, each provisionable group/entity to sync memberships counts as 10, # each provisionable membership to sync counts as 1. If the total score is more than this number, # it will convert the incrementals to a a full sync. e.g. 10000 individual memberships to sync # (and not more than 500 in a single group), or 1000 groups to sync, or a combination. # -1 means do not convert to full sync # default to provisionerDefault.scoreConvertToFullSyncThreshold = 10000 # {valueType: "integer", order: 93000, subSection: "advanced", showEl: "${showAdvanced}"} # provisioner.genericProvisioner.scoreConvertToFullSyncThreshold = # Read only # {valueType: "boolean", subSection: "advanced", defaultValue: "false", order: 94000, showEl: "${showAdvanced}"} # provisioner.genericProvisioner.readOnly = # refresh target group link if less than this amount # {valueType: "integer", defaultValue: 20, subSection: "advanced", showEl: "${operateOnGrouperGroups && hasTargetGroupLink && showAdvanced}", order: 95000} # provisioner.genericProvisioner.refreshGroupLinkIfLessThanAmount = # Target group link - groupFromId2 # {valueType: "string", subSection: "advanced", showEl: "${operateOnGrouperGroups && hasTargetGroupLink && showAdvanced}", order: 96000} # provisioner.genericProvisioner.common.groupLink.groupFromId2 = # Target group link - groupFromId3 # {valueType: "string", subSection: "advanced", showEl: "${operateOnGrouperGroups && hasTargetGroupLink && showAdvanced}", order: 97000} # provisioner.genericProvisioner.common.groupLink.groupFromId3 = # Target group link - groupToId2 # {valueType: "string", subSection: "advanced", showEl: "${operateOnGrouperGroups && hasTargetGroupLink && showAdvanced}", order: 98000} # provisioner.genericProvisioner.common.groupLink.groupToId2 = # Target group link - groupToId3 # {valueType: "string", subSection: "advanced", showEl: "${operateOnGrouperGroups && hasTargetGroupLink && showAdvanced}", order: 99000} # provisioner.genericProvisioner.common.groupLink.groupToId3 = # refresh subject link if less than this amount # {valueType: "integer", defaultValue: 20, showEl: "${hasSubjectLink && operateOnGrouperEntities && showAdvanced}", order: 100000, subSection: "advanced"} # provisioner.genericProvisioner.refreshSubjectLinkIfLessThanAmount = # Subject link - memberFromId2 # {valueType: "string", showEl: "${hasSubjectLink && operateOnGrouperEntities && showAdvanced}", order: 101000, subSection: "advanced"} # provisioner.genericProvisioner.common.subjectLink.memberFromId2 = # Subject link - memberFromId3 # {valueType: "string", showEl: "${hasSubjectLink && operateOnGrouperEntities && showAdvanced}", order: 102000, subSection: "advanced"} # provisioner.genericProvisioner.common.subjectLink.memberFromId3 = # Subject link - memberToId2 # {valueType: "string", showEl: "${hasSubjectLink && operateOnGrouperEntities && showAdvanced}", order: 103000, subSection: "advanced"} # provisioner.genericProvisioner.common.subjectLink.memberToId2 = # Subject link - memberToId3 # {valueType: "string", showEl: "${hasSubjectLink && operateOnGrouperEntities && showAdvanced}", order: 104000, subSection: "advanced"} # provisioner.genericProvisioner.common.subjectLink.memberToId3 = # refresh target user link if less than this amount # {valueType: "integer", defaultValue: 20, showEl: "${hasTargetEntityLink && operateOnGrouperEntities && showAdvanced}", order: 105000, subSection: "advanced"} # provisioner.genericProvisioner.refreshEntityLinkIfLessThanAmount = # Target user link - memberFromId2 # {valueType: "string", showEl: "${hasTargetEntityLink && operateOnGrouperEntities && showAdvanced}", order: 106000, subSection: "advanced"} # provisioner.genericProvisioner.common.entityLink.memberFromId2 = # Target user link - memberFromId3 # {valueType: "string", showEl: "${hasTargetEntityLink && operateOnGrouperEntities && showAdvanced}", order: 107000, subSection: "advanced"} # provisioner.genericProvisioner.common.entityLink.memberFromId3 = # Target user link - memberToId2 # {valueType: "string", showEl: "${hasTargetEntityLink && operateOnGrouperEntities && showAdvanced}", order: 108000, subSection: "advanced"} # provisioner.genericProvisioner.common.entityLink.memberToId2 = # Target user link - memberToId3 # {valueType: "string", showEl: "${hasTargetEntityLink && operateOnGrouperEntities && showAdvanced}", order: 109000, subSection: "advanced"} # provisioner.genericProvisioner.common.entityLink.memberToId3 = # if provisioning normal memberships or privileges # {valueType: "string", order: 110000, formElement: "dropdown", subSection: "advanced", showEl: "${operateOnGrouperMemberships && showAdvanced}", defaultValue: "members", optionValues: ["members", "read, admin", "update, admin", "admin"]} # provisioner.genericProvisioner.membershipFields = # overall group of entities to provision. If not specified, then provision entities with any memberships optional # {valueType: "string", order: 111000, showEl: "${operateOnGrouperEntities && showAdvanced}", subSection: "advanced"} # provisioner.genericProvisioner.groupIdOfUsersToProvision = ######################################## ## box provisioner ######################################## # Generic provisioner key suffixes (comma separated) to ignore for box provisioner # {valueType: "string"} provisionerPropertiesToIgnore.GrouperBoxProvisioner.keySuffixes = debugLog,logAllObjectsVerbose # Generic provisioner key suffixes based on regex (comma separated) to ignore for box provisioner. delimiter is "," and U+002C is part of regex and substitute for comma # {valueType: "string"} # provisionerPropertiesToIgnore.GrouperBoxProvisioner.keySuffixRegexes = # Subsections to ignore for box provisioner # {valueType: "string"} provisionerPropertiesToIgnore.GrouperBoxProvisioner.subsections = group,user # provisioner class # {valueType: "class", required: true, readOnly: true, order: 10} # provisioner.myBoxProvisioner.class = edu.internet2.middleware.grouperBox.GrouperBoxProvisioner # this is the box external system config id # {valueType: "string", required: true, order: 20, formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouperBox.BoxGrouperExternalSystem"} # provisioner.myBoxProvisioner.boxExternalSystemConfigId = # specifies who can invite the group to collaborate on folders. # {valueType: "string", formElement: "dropdown", order: 30, defaultValue: "admins_and_members", optionValues: ["admins_and_members", "admins_only", "all_managed_users"]} # provisioner.myBoxProvisioner.invitabilityLevel = # specifies who can see the members of the group. # {valueType: "string", order: 40, formElement: "dropdown", defaultValue: "admins_and_members", optionValues: ["admins_and_members", "admins_only", "all_managed_users"]} # provisioner.myBoxProvisioner.memberViewabilityLevel = ######################################## ## ldap provisioner ######################################## # provisioner class # {valueType: "class", required: true, readOnly: true, order: 10} # provisioner.myLdapProvisioner.class = edu.internet2.middleware.grouper.app.ldapProvisioning.LdapSync # this is the ldap external system config id # {valueType: "string", required: true, order: 20, formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.externalSystem.LdapGrouperExternalSystem"} # provisioner.myLdapProvisioner.ldapExternalSystemConfigId = # groupAttributes: group ldap object has attribute to hold memberships. # entityAttributes: user ldap object has attribute to hold memberships # {valueType: "string", required: true, order: 1000, subSection: "membership", showEl: "${operateOnGrouperMemberships}", formElement: "dropdown", optionValues: ["groupAttributes", "entityAttributes"]} # provisioner.myLdapProvisioner.provisioningType = # Name of the field # {valueType: "string", order: 21001, required: true, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && targetGroupAttribute.$i$.isFieldElseAttribute}", formElement: "dropdown", optionValues: ["name"], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.myLdapProvisioner.targetGroupAttribute.$i$.fieldName = # Name of the field # {valueType: "string", order: 61001, required: true, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && targetEntityAttribute.$i$.isFieldElseAttribute}", formElement: "dropdown", optionValues: ["name"], repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.genericProvisioner.targetEntityAttribute.$i$.fieldName = # where users are # {valueType: "string", subSection: "entity", order: 58010, showEl: "${operateOnGrouperEntities && provisioningType == 'entityAttributes' || hasTargetEntityLink}"} # provisioner.myLdapProvisioner.userSearchBaseDn = # how to find a user # {valueType: "string", subSection: "entity", order: 58020, showEl: "${operateOnGrouperEntities && provisioningType == 'entityAttributes' || hasTargetEntityLink}"} # provisioner.myLdapProvisioner.userSearchFilter = # filter users when searching all # {valueType: "string", subSection: "entity", order: 58030, showEl: "${operateOnGrouperEntities && provisioningType == 'entityAttributes' || hasTargetEntityLink}"} # provisioner.myLdapProvisioner.userSearchAllFilter = # group search base dn, this is below the ldap connection base dn which is in the external system url. e.g. ou=Groups,dc=example,dc=edu # {valueType: "string", subSection: "group", order: 18600, showEl: "${ operateOnGrouperGroups && (provisioningType == 'groupAttributes' || hasTargetGroupLink) }"} # provisioner.myLdapProvisioner.groupSearchBaseDn = # find a single group. You can use the variable 'targetGroup'. e.g. (gidNumber=${targetGroup.retrieveAttributeValue('gidNumber')}) # e.g. (dn=${targetGroup.getName()}) # {valueType: "string", subSection: "group", order: 18650, showEl: "${ operateOnGrouperGroups && (provisioningType == 'groupAttributes' || hasTargetGroupLink) }"} # provisioner.myLdapProvisioner.groupSearchFilter = # find all groups. e.g. (objectClass=posixGroup) # e.g. (objectClass=groupOfNames) # {valueType: "string", subSection: "group", order: 18700, showEl: "${ operateOnGrouperGroups && (provisioningType == 'groupAttributes' || hasTargetGroupLink) }"} # provisioner.myLdapProvisioner.groupSearchAllFilter = # bushy makes an ou for each folder and cn is extension. flat is cn is group name # {valueType: "string", subSection: "group", order: 18750, required: true, formElement: "dropdown", optionValues: ["bushy", "flat"], showEl: "${ operateOnGrouperGroups && provisioningType == 'groupAttributes'}"} # provisioner.myLdapProvisioner.groupDnType = ######################################## ## sql provisioner ######################################## # provisioner class # {valueType: "class", required: true, readOnly: true, order: 10} # provisioner.someSqlProvisioner.class = edu.internet2.middleware.grouper.app.sqlProvisioning.SqlProvisioner # this is the sql external system config id # {valueType: "string", order: 20, required: true, formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.loader.db.DatabaseGrouperExternalSystem"} # provisioner.someSqlProvisioner.dbExternalSystemConfigId = # users table to query to lookup users required if hasTargetEntityLink # {valueType: "string", order: 49010, subSection: "entity", showEl: "${ operateOnGrouperEntities }"} # provisioner.someSqlProvisioner.userTableName = # users table primary key column(s) of user table # {valueType: "string", order: 49020, subSection: "entity", showEl: "${operateOnGrouperEntities}"} # provisioner.someSqlProvisioner.userPrimaryKey = # if this is more complicated than just a simple select, put the query here optional, select * from users where ... # {valueType: "string", order: 49040, subSection: "entity", showEl: "${operateOnGrouperEntities }"} # provisioner.someSqlProvisioner.userSearchQuery = # memberships table where memberships go. include schema name if necessary # {valueType: "string", required: true, order: 6600, subSection: "membership", showEl: "${operateOnGrouperMemberships }"} # provisioner.someSqlProvisioner.membershipTableName = # if this is more complicated than just a simple select, put the query here optional, select * from memberships where ... # {valueType: "string", order: 6700, subSection: "membership", showEl: "${operateOnGrouperMemberships }"} # provisioner.someSqlProvisioner.membershipSearchQuery = # groups table to query to lookup users required if hasTargetEntityLink # {valueType: "string", subSection: "group", order: 15010, showEl: "${operateOnGrouperGroups }"} # provisioner.someSqlProvisioner.groupTableName = # groups table primary key column(s) of group table # {valueType: "string", subSection: "group", order: 15020, showEl: "${operateOnGrouperGroups }"} # provisioner.someSqlProvisioner.groupPrimaryKey = # if this is more complicated than just a simple select, put the query here optional, select * from groups where ... # {valueType: "string", subSection: "group", order: 15040, showEl: "${operateOnGrouperGroups }"} # provisioner.someSqlProvisioner.groupSearchQuery = ######################################## ## scim provisioner ######################################## # provisioner class # {valueType: "class", required: true, readOnly: true, order: 10} # provisioner.myScimProvisioner.class = edu.internet2.middleware.grouper.app.scim2Provisioning.GrouperScim2Provisioner # bearer token external system id # {valueType: "string", required: true, order: 20, formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.externalSystem.WsBearerTokenExternalSystem"} # provisioner.myScimProvisioner.bearerTokenExternalSystemConfigId = # {valueType: "string", required: true, order: 1000, subSection: "membership", showEl: "${operateOnGrouperMemberships}", readOnly: true} # provisioner.myScimProvisioner.provisioningType = membershipObjects # Select memberships # {valueType: "string", readOnly: true, order: 1500, subSection: "membership", showEl: "${operateOnGrouperMemberships}"} # provisioner.myScimProvisioner.selectMemberships = false # Replace memberships # {valueType: "boolean", order: 2491, defaultValue: "false", subSection: "membership", showEl: "${operateOnGrouperMemberships}"} # provisioner.myScimProvisioner.replaceMemberships = # Update groups # {valueType: "string", readOnly: true, order: 11500, subSection: "group", showEl: "${operateOnGrouperGroups}"} # provisioner.myScimProvisioner.updateGroups = false # if the groups need to be resolved in target # {valueType: "string", readOnly: true, defaultValue: "false", subSection: "group", showEl:"${operateOnGrouperGroups && selectGroups}", order: 12000} # provisioner.myScimProvisioner.hasTargetGroupLink = true # if the entities need to be resolved in target # {valueType: "string", readOnly: true, showEl:"${operateOnGrouperEntities && selectEntities}", order: 53000, subSection: "entity"} # provisioner.myScimProvisioner.hasTargetEntityLink = # Name of the attribute # {valueType: "string", order: 21000, required: true, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && !targetGroupAttribute.$i$.isFieldElseAttribute}", formElement: "dropdown", optionValues: [""], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.myScimProvisioner.targetGroupAttribute.$i$.name = # Name of the field # {valueType: "string", order: 21001, required: true, showEl: "${operateOnGrouperGroups && numberOfGroupAttributes > $i$ && targetGroupAttribute.$i$.isFieldElseAttribute}", formElement: "dropdown", optionValues: ["displayName", "id"], repeatGroup: "targetGroupAttribute", repeatCount: 20} # provisioner.myScimProvisioner.targetGroupAttribute.$i$.fieldName = # Name of the attribute # {valueType: "string", order: 61000, required: true, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && !targetEntityAttribute.$i$.isFieldElseAttribute}", formElement: "dropdown", optionValues: ["active", "costCenter", "displayName", "emailType", "emailValue", "employeeNumber", "externalId", "familyName", "formattedName", "givenName", "middleName", "userName", "userType"], repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.myScimProvisioner.targetEntityAttribute.$i$.name = # Name of the field # {valueType: "string", order: 61001, required: true, showEl: "${operateOnGrouperEntities && numberOfEntityAttributes > $i$ && targetEntityAttribute.$i$.isFieldElseAttribute}", formElement: "dropdown", optionValues: ["id"], repeatGroup: "targetEntityAttribute", repeatCount: 20} # provisioner.myScimProvisioner.targetEntityAttribute.$i$.fieldName = ############## ## Zoom ############## # endpoint of zoom including the version # {valueType: "string", defaultValue: "https://api.zoom.us/v2"} # zoom.myConfigId.endpoint = https://api.zoom.us/v2 # zoom jwt api key # {valueType: "string"} # zoom.myConfigId.jwtApiKey = # zoom jwt api key # {valueType: "password", sensitive: true} # zoom.myConfigId.jwtApiSecretPassword = # cache jwt for minutes, must be at least 2, or could be 0 to not cache. If it is 1 it will be changed to 2. # {valueType: "integer", defaultValue: "30"} # zoom.myConfigId.cacheJwtForMinutes = 30 # master account id (used in custom ui) # {valueType: "string"} # zoom.myConfigId.masterAccountId = # page size when retrieving members, max is 300 # {valueType: "integer", defaultValue: "300"} # zoom.myConfigId.pageSizeMemberships = 300 # base folder # {valueType: "string"} # zoom.myConfigId.folderToProvision = # if provisioning groups should remove only # {valueType: "boolean", defaultValue: "false"} # zoom.myConfigId.groupProvisionRemoveOnly = # base folder # {valueType: "string"} # zoom.myConfigId.roleFolderToProvision = # if provisioning roles should remove only # {valueType: "boolean", defaultValue: "false"} # zoom.myConfigId.roleProvisionRemoveOnly = # subject sources to provision # {valueType: "string", multiple: true} # zoom.myConfigId.sourcesForSubjects = # ignore user ids in zoom (dont remove them) e.g. admin ids # {valueType: "string", multiple: true} # zoom.myConfigId.ignoreUserIds = # subject attribute to match zoom email address (generally eppn) # {valueType: "string"} # zoom.myConfigId.subjectAttributeForZoomEmail = # if deleting users, this is the group of users to delete. Load this group with your grace period policy # {valueType: "string"} # zoom.myConfigId.groupNameToDeleteUsers = a:b:c # if deleting users, this will just log instead of actually deleting # {valueType: "boolean", defaultValue: "false"} # zoom.myConfigId.logUserDeletesInsteadOfDeleting = false # if deleting users, this will remove the user from the grouper group (of users to delete), after the deleting occurs (if they have an immediate membership there) # {valueType: "boolean", defaultValue: "false"} # zoom.myConfigId.removeGrouperMembershipFromDeletedGroupAfterDeleteZoomUser = false # if deactivating users, this is the group of users to deactivate. Load this group with your grace period policy # {valueType: "string"} # zoom.myConfigId.groupNameToDeactivateUsers = a:b:c # if deactivating users, this will just log instead of actually deactivating # {valueType: "boolean", defaultValue: "false"} # zoom.myConfigId.logUserDeactivatesInsteadOfDeactivating = false # if deactivating users, this will remove the user from the grouper group (of users to deactivate), after the deactivating occurs (if they have an immediate membership there) # {valueType: "boolean", defaultValue: "false"} # zoom.myConfigId.removeGrouperMembershipFromDeactivatedGroupAfterDeactivateZoomUser = false # $$lowerEmailAddresses$$ will be the bind variables to lookup email addresses. the first col is the email, the second col is the subject id, # the third col is the source_id # e.g. select LOWER_EMAIL_ADDRESS, CHAR_PENN_ID, 'pennperson' as subject_source_id from person_source_email_lookup_v where lower_email_address in ($$lowerEmailAddresses$$) # {valueType: "string"} # zoom.myConfigId.emailLookupQuery = # database where the email lookup occurs # {valueType: "string"} # zoom.myConfigId.emailLookupDbConfigId = # if there are unresolvables then log them so they can be dealt with # {valueType: "boolean", defaultValue: "false"} # zoom.myConfigId.logUnresolvables = false ################# ## Zoom full provisioning ################# # {valueType: "class", mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} # otherJob.myZoomFull.class = edu.internet2.middleware.grouper.app.zoom.GrouperZoomFullSync # zoom full cron, default to 2:20 # {valueType: "string"} # otherJob.myZoomFull.quartzCron = 0 20 2 * * ? # links to zoom config id # {valueType: "string"} # otherJob.myZoomFull.zoomConfigId = myConfigId ################# ## Zoom incremental provisioning ################# # esb consumer # {valueType: "class", required: true, mustExtendClass: "edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer"} # changeLog.consumer.zoomEsbProd.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer # zoom incremental cron, defualt to every hour except 2am (to not conflict with full) # {valueType: "string"} # changeLog.consumer.zoomEsbProd.quartzCron = 0 * 0,1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 * * ? # zoom publishing class # {valueType: "class", mustExtendClass: "edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbMessagingPublisher"} # changeLog.consumer.zoomEsbProd.publisher.class = edu.internet2.middleware.grouper.app.zoom.ZoomEsbPublisher # el filter # {valueType: "string"} # changeLog.consumer.zoomEsbProd.elfilter = (event.sourceId == null || event.sourceId eq 'pennperson') && (event.groupName =~ '^penn\:isc\:ait\:apps\:zoom\:service\:policy\:groups\:.*$' || event.name =~ '^penn\:isc\:ait\:apps\:zoom\:service\:policy\:groups\:.*$' ) && (event.eventType eq 'GROUP_DELETE' || event.eventType eq 'GROUP_ADD' || event.eventType eq 'GROUP_UPDATE' || event.eventType eq 'MEMBERSHIP_DELETE' || event.eventType eq 'MEMBERSHIP_ADD' || event.eventType eq 'MEMBERSHIP_UPDATE') # add subject attributes # {valueType: "string", multiple: true} # changeLog.consumer.zoomEsbProd.publisher.addSubjectAttributes = EPPN # zoom config id # {valueType: "string"} # changeLog.consumer.zoomEsbProd.zoomConfigId = myConfigId ################# ## Zoom loading ################# # {valueType: "class", mustExtendClass: "edu.internet2.middleware.grouper.app.loader.OtherJobBase", mustImplementInterface: "org.quartz.Job"} # otherJob.myZoomLoader.class = edu.internet2.middleware.grouper.app.zoom.GrouperZoomLoader # zoom full cron, default to every hour at 40 minutes after # {valueType: "string"} # otherJob.myZoomLoader.quartzCron = 0 40 * * * ? # links to zoom config id # {valueType: "string"} # otherJob.myZoomLoader.zoomConfigId = myConfigId # if loading groups from zoom to grouper # {valueType: "boolean", defaultValue: "false"} # otherJob.myZoomLoader.zoomLoadGroups = false # if zoomLoadGroups is true then load groups into this folder # {valueType: "string"} # otherJob.myZoomLoader.zoomLoadGroupsFolderName = a:b # if loading roles from zoom to grouper # {valueType: "boolean", defaultValue: "false"} # otherJob.myZoomLoader.zoomLoadRoles = false # if zoomLoadRoles is true then load roles into this folder # {valueType: "string"} # otherJob.myZoomLoader.zoomLoadRolesFolderName = c:d # if loading user types from zoom to grouper # {valueType: "boolean", defaultValue: "false"} # otherJob.myZoomLoader.zoomLoadUserTypes = false # if zoomLoadUserTypes is true then load userTypes into this folder # {valueType: "string"} # otherJob.myZoomLoader.zoomLoadUserTypesFolderName = d:e # if loading user statuses from zoom to grouper # {valueType: "boolean", defaultValue: "false"} # otherJob.myZoomLoader.zoomLoadUserStatuses = false # if zoomLoadUserStatuses is true then load user statuses into this folder # {valueType: "string"} # otherJob.myZoomLoader.zoomLoadUserStatusesFolderName = d:e ############################################ ## Azure external system ## specify the azure connection with user, pass, endpoint etc ## the string after "azureConnector." is the name of the connection, and it should not have ## spaces or other special chars in it ############################################ # azure login base uri to get a token. Should end in a slash # {valueType: "string", required: true, regex: "^grouper\\.azureConnector\\.([^.]+)\\.loginEndpoint$"} # grouper.azureConnector.myAzure.loginEndpoint = https://login.microsoftonline.com/ # azure directory id. eg: 6c4dxxx0d # {valueType: "string", required: true, regex: "^grouper\\.azureConnector\\.([^.]+)\\.tenantId$"} # grouper.azureConnector.myAzure.tenantId = # client id. eg: fd805xxxxdfb # {valueType: "string", required: true, regex: "^grouper\\.azureConnector\\.([^.]+)\\.clientId"} # grouper.azureConnector.myAzure.clientId = # client secret # {valueType: "password", sensitive: true, regex: "^db\\.([^.]+)\\.clientSecret"} #grouper.azureConnector.myAzure.clientSecret = # resource. generally same as graph endpoint. eg: https://graph.microsoft.com # {valueType: "string", required: true, regex: "^grouper\\.azureConnector\\.([^.]+)\\.resource$"} # grouper.azureConnector.myAzure.resource = # azure resource base uri. Should include the version and end in a slash # {valueType: "string", required: true, regex: "^grouper\\.azureConnector\\.([^.]+)\\.resourceEndpoint$"} # grouper.azureConnector.myAzure.resourceEndpoint = https://graph.microsoft.com/v1.0/ # graph endpoint. eg: https://graph.microsoft.com # {valueType: "string", required: true, regex: "^grouper\\.azureConnector\\.([^.]+)\\.graphEndpoint$"} # grouper.azureConnector.myAzure.graphEndpoint = # graph version. eg: v1.0 # {valueType: "string", required: true, regex: "^grouper\\.azureConnector\\.([^.]+)\\.graphVersion$"} # grouper.azureConnector.myAzure.graphVersion = # group lookup attribute. eg: displayName # {valueType: "string", required: true, regex: "^grouper\\.azureConnector\\.([^.]+)\\.groupLookupAttribute$"} # grouper.azureConnector.myAzure.groupLookupAttribute = # group lookup value format. eg: ${group.getName()} # {valueType: "string", required: true, regex: "^grouper\\.azureConnector\\.([^.]+)\\.groupLookupValueFormat$"} # grouper.azureConnector.myAzure.groupLookupValueFormat = # require subject attribute. eg: netId # {valueType: "string", required: true, regex: "^grouper\\.azureConnector\\.([^.]+)\\.requireSubjectAttribute$"} # grouper.azureConnector.myAzure.requireSubjectAttribute = # subject id value format. eg: ${subject.getAttributeValue("netId")}@school.edu # {valueType: "string", required: true, regex: "^grouper\\.azureConnector\\.([^.]+)\\.subjectIdValueFormat$"} # grouper.azureConnector.myAzure.subjectIdValueFormat = # if this azure connector is enabled # {valueType: "boolean", regex: "^grouper\\.azureConnector\\.([^.]+)\\.enabled$", defaultValue: "true"} # grouper.azureConnector.myAzure.enabled = ############################################ ## WS bearer token external system ## this is a simple URL with an Authorization bearer token secret ############################################ # Base website URL for WS with bearer token authn. e.g. https://scim.us-east-1.amazonaws.com/abc123/scim/v2/ # {valueType: "string", required: true, regex: "^grouper\\.myWsBearerToken\\.([^.]+)\\.endpoint$"} # grouper.wsBearerToken.myWsBearerToken.endpoint = # Bearer token secret, e.g. AWS access token # {valueType: "password", sensitive: true, required: true, regex: "^grouper\\.myWsBearerToken\\.([^.]+)\\.accessTokenPassword$"} # grouper.wsBearerToken.myWsBearerToken.accessTokenPassword = # if this WS endpoing connector is enabled # {valueType: "boolean", regex: "^grouper\\.myWsBearerToken\\.([^.]+)\\.enabled$", defaultValue: "true"} # grouper.wsBearerToken.myWsBearerToken.enabled = # Test URL suffix that returns a 200 # {valueType: "string", regex: "^grouper\\.myWsBearerToken\\.([^.]+)\\.testUrlSuffix$"} # grouper.wsBearerToken.myWsBearerToken.testUrlSuffix = # Test URL method, defaults to GET. Could be POST or whatever. # {valueType: "string", defaultValue: "GET", regex: "^grouper\\.myWsBearerToken\\.([^.]+)\\.testHttpMethod$"} # grouper.wsBearerToken.myWsBearerToken.testHttpMethod = # Test URL response code. Defaults to 200 # {valueType: "integer", defaultValue: "200", regex: "^grouper\\.myWsBearerToken\\.([^.]+)\\.testHttpResponseCode$"} # grouper.wsBearerToken.myWsBearerToken.testHttpResponseCode = # Test URL response regex to match to see if valid (optional) # {valueType: "string", regex: "^grouper\\.myWsBearerToken\\.([^.]+)\\.testUrlResponseBodyRegex$"} # grouper.wsBearerToken.myWsBearerToken.testUrlResponseBodyRegex = ######################################## ## Azure provisioner ######################################## # provisioner class # {valueType: "class", required: true, readOnly: true} # provisioner.myAzureProvisioner.class = edu.internet2.middleware.grouper.app.azure.GrouperAzureProvisioner # this is the Azure external system config id # {valueType: "string", required: true, formElement: "dropdown", optionValuesFromClass: "edu.internet2.middleware.grouper.app.azure.AzureGrouperExternalSystem"} # provisioner.myAzureProvisioner.azureExternalSystemConfigId =