Skip to content

Commit

Permalink
Add demo/complex scenario
Browse files Browse the repository at this point in the history
This is a rework/update of the original "Grouper-midPoint" demo.
It is a work in progress. Do not use yet.
  • Loading branch information
mederly committed Sep 24, 2018
1 parent 2613570 commit 6e3c0d0
Show file tree
Hide file tree
Showing 102 changed files with 11,389 additions and 0 deletions.
14 changes: 14 additions & 0 deletions demo/complex/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
AUTHENTICATION=internal
ENV=demo
USERTOKEN=
REPO_DATABASE_TYPE=mariadb
REPO_JDBC_URL=default
REPO_HOST=midpoint-data
REPO_PORT=default
REPO_DATABASE=midpoint
REPO_USER=root
REPO_PASSWORD_FILE=/run/secrets/m_database_password.txt
KEYSTORE_PASSWORD_FILE=/run/secrets/m_keystore_password.txt
MEM=2048m
LOGOUT_URL=https://localhost:8443/Shibboleth.sso/Logout
SSO_HEADER=uid
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#################################
## LDAP connections
#################################
# specify the ldap connection with user, pass, url
# the string after "ldap." is the ID of the connection, and it should not have
# spaces or other special chars in it. In this case is it "personLdap"

#note the URL should start with ldap: or ldaps: if it is SSL.
#It should contain the server and port (optional if not default), and baseDn,
#e.g. ldaps://ldapserver.school.edu:636/dc=school,dc=edu
#ldap.demo.url = ldap://directory:389/dc=internet2,dc=edu
ldap.demo.url = ldap://directory:389

#optional, if authenticated
ldap.demo.user = cn=admin,dc=internet2,dc=edu

#optional, if authenticated note the password can be stored encrypted in an external file
#ldap.demo.pass = ${java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD_FILE') != null ? org.apache.commons.io.FileUtils.readFileToString(java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD_FILE'), "utf-8") : java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD')}
ldap.demo.pass=password

#optional, if you are using tls, set this to true. Generally you will not be using an SSL URL to use TLS...
ldap.demo.tls = false

#optional, if using sasl
#ldap.personLdap.saslAuthorizationId =
#ldap.personLdap.saslRealm =

#optional (note, time limit is for search operations, timeout is for connection timeouts),
#most of these default to vt-ldap defaults. times are in millis
#validateOnCheckout defaults to true if all other validate methods are false
#ldap.personLdap.batchSize =
#ldap.personLdap.countLimit =
#ldap.personLdap.timeLimit =
#ldap.personLdap.timeout =
#ldap.personLdap.minPoolSize =
#ldap.personLdap.maxPoolSize =
#ldap.personLdap.validateOnCheckIn =
#ldap.personLdap.validateOnCheckOut =
#ldap.personLdap.validatePeriodically =
#ldap.personLdap.validateTimerPeriod =
#ldap.personLdap.pruneTimerPeriod =
#if connections expire after a certain amount of time, this is it, in millis, defaults to 300000 (5 minutes)
#ldap.personLdap.expirationTime =

#make the paths fully qualified and not relative to the loader group.
loader.ldap.requireTopStemAsStemFromConfigGroup=false

#####################################
## Messaging integration with change log
#####################################
changeLog.consumer.rabbitMqMessagingSample.quartzCron = 0 * * * * ?

# note, change "messagingSample" in key to be the name of the consumer. e.g. changeLog.consumer.someNameAnyName.class
changeLog.consumer.rabbitMqMessagingSample.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbConsumer

changeLog.consumer.rabbitMqMessagingSample.publisher.class = edu.internet2.middleware.grouper.changeLog.esb.consumer.EsbMessagingPublisher
changeLog.consumer.rabbitMqMessagingSample.publisher.messagingSystemName = rabbitmq
# note, routingKey property is valid only for rabbitmq. For other messaging systems, it is ignored.
changeLog.consumer.rabbitMqMessagingSample.publisher.routingKey =
## queue or topic
changeLog.consumer.rabbitMqMessagingSample.publisher.messageQueueType = queue
changeLog.consumer.rabbitMqMessagingSample.publisher.queueOrTopicName = sampleQueue
## this is optional if not using "id" for subjectId, need to be a subject attribute in the sources.xml
#changeLog.consumer.rabbitMqMessagingSample.publisher.addSubjectAttributes = email
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#
# Copyright 2014 Internet2
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

#
# Grouper client configuration
# $Id: grouper.client.example.properties,v 1.24 2009-12-30 04:23:02 mchyzer Exp $
#

# The grouper client uses Grouper Configuration Overlays (documented on wiki)
# By default the configuration is read from grouper.client.base.properties
# (which should not be edited), and the grouper.client.properties overlays
# the base settings. See the grouper.client.base.properties for the possible
# settings that can be applied to the grouper.client.properties

########################################
## LDAP connection settings
########################################

# url of directory, including the base DN (distinguished name)
# e.g. ldap://server.school.edu/dc=school,dc=edu
# e.g. ldaps://server.school.edu/dc=school,dc=edu
grouperClient.ldap.url =

# kerberos principal used to connect to ldap
grouperClient.ldap.login =

# password for shared secret authentication to ldap
# or you can put a filename with an encrypted password
grouperClient.ldap.password =

########################################
## Web service Connection settings
########################################

# url of web service, should include everything up to the first resource to access
# e.g. http://groups.school.edu:8090/grouper-ws/servicesRest
# e.g. https://groups.school.edu/grouper-ws/servicesRest
grouperClient.webService.url = https://grouper-ws/grouper-ws/servicesRest

# kerberos principal used to connect to web service
grouperClient.webService.login = banderson

# password for shared secret authentication to web service
# or you can put a filename with an encrypted password
grouperClient.webService.password.elConfig = ${java.lang.System.getenv().get('GROUPER_CLIENT_WEBSERVICE_PASSWORD_FILE') != null ? org.apache.commons.io.FileUtils.readFileToString(java.lang.System.getenv().get('GROUPER_CLIENT_WEBSERVICE_PASSWORD_FILE'), "utf-8") : java.lang.System.getenv().get('GROUPER_CLIENT_WEBSERVICE_PASSWORD') }


################################
## Grouper Messaging System
################################

# name of messaging system which is the default
grouper.messaging.default.name.of.messaging.system = rabbitmq

# name of a messaging system. note, "grouperBuiltinMessaging" can be arbitrary
# grouper.messaging.system.grouperBuiltinMessaging.name = grouperBuiltinMessaging

# class that implements edu.internet2.middleware.grouperClient.messaging.GrouperMessagingSystem
# grouper.messaging.system.grouperBuiltinMessaging.class = edu.internet2.middleware.grouper.messaging.GrouperBuiltinMessagingSystem

# name of a messaging system. note, "grouperBuiltinMessaging" can be arbitrary
grouper.messaging.system.rabbitmqSystem.name = rabbitmqSystem

# class that implements edu.internet2.middleware.grouperClient.messaging.GrouperMessagingSystem
grouper.messaging.system.rabbitmqSystem.class = edu.internet2.middleware.grouperMessagingRabbitmq.GrouperMessagingRabbitmqSystem

# host address of rabbitmq queue
grouper.messaging.system.rabbitmqSystem.host = mq

# virtual host of rabbitmq queue
grouper.messaging.system.rabbitmqSystem.virtualhost =

# port of rabbitmq queue
grouper.messaging.system.rabbitmqSystem.port =

grouper.messaging.system.rabbitmqSystem.defaultPageSize = 10

grouper.messaging.system.rabbitmqSystem.maxPageSize = 50


# name of a messaging system, required
grouper.messaging.system.rabbitmq.name = rabbitmq

# default system settings to this messaging system, note, there is only one level of inheritance
grouper.messaging.system.rabbitmq.defaultSystemName = rabbitmqSystem

grouper.messaging.system.rabbitmq.user = guest

#pass
grouper.messaging.system.rabbitmq.password.elConfig = ${java.lang.System.getenv().get('RABBITMQ_PASSWORD_FILE') != null ? org.apache.commons.io.FileUtils.readFileToString(java.lang.System.getenv().get('RABBITMQ_PASSWORD_FILE'), "utf-8") : java.lang.System.getenv().get('RABBITMQ_PASSWORD') }
# set the following three properties if you want to use TLS connection to rabbitmq. All three need to be populated.
# TLS Version
#grouper.messaging.system.rabbitmqSystem.tlsVersion = TLSv1.1

# path to trust store file
#grouper.messaging.system.rabbitmqSystem.pathToTrustStore =

# trust passphrase
#grouper.messaging.system.rabbitmqSystem.trustPassphrase =
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#
# Grouper Hibernate Configuration
# $Id: grouper.hibernate.example.properties,v 1.9 2009-08-11 20:18:09 mchyzer Exp $
#

# The grouper hibernate config uses Grouper Configuration Overlays (documented on wiki)
# By default the configuration is read from grouper.hibernate.base.properties
# (which should not be edited), and the grouper.hibernate.properties overlays
# the base settings. See the grouper.hibernate.base.properties for the possible
# settings that can be applied to the grouper.hibernate.properties

########################################
## DB settings
########################################

# e.g. mysql: jdbc:mysql://localhost:3306/grouper
# e.g. p6spy (log sql): [use the URL that your DB requires]
# e.g. oracle: jdbc:oracle:thin:@server.school.edu:1521:sid
# e.g. hsqldb (a): jdbc:hsqldb:dist/run/grouper;create=true
# e.g. hsqldb (b): jdbc:hsqldb:hsql://localhost:9001/grouper
# e.g. postgres: jdbc:postgresql://localhost:5432/database
# e.g. mssql: jdbc:sqlserver://localhost:3280;databaseName=grouper
hibernate.connection.url = jdbc:mysql://grouper-data:3306/grouper?CharSet=utf8&useUnicode=true&characterEncoding=utf8

hibernate.connection.username = root
# If you are using an empty password, depending upon your version of
# Java and Ant you may need to specify a password of "".
# Note: you can keep passwords external and encrypted: https://bugs.internet2.edu/jira/browse/GRP-122
hibernate.connection.password.elConfig = ${java.lang.System.getenv().get('GROUPER_DATABASE_PASSWORD_FILE') != null ? org.apache.commons.io.FileUtils.readFileToString(java.lang.System.getenv().get('GROUPER_DATABASE_PASSWORD_FILE'), "utf-8") : java.lang.System.getenv().get('GROUPER_DATABASE_PASSWORD') }
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#
# Grouper Configuration
# $Id: grouper.example.properties,v 1.48 2009-12-16 06:02:30 mchyzer Exp $
#

# Grouper uses Grouper Configuration Overlays (documented on wiki)
# By default the configuration is read from grouper.base.properties
# (which should not be edited), and the grouper.properties overlays
# the base settings. See the grouper.base.properties for the possible
# settings that can be applied to the grouper.properties

#if groups like the wheel group should be auto-created for convenience (note: check config needs to be on)
configuration.autocreate.system.groups = true

# A wheel group allows you to enable non-GrouperSystem subjects to act
# like a root user when interacting with the registry.
groups.wheel.use = true

# Set to the name of the group you want to treat as the wheel group.
# The members of this group will be treated as root-like users.
groups.wheel.group = etc:sysadmingroup

# Used to allow Include Exclude groups
grouperIncludeExclude.use = true
grouperIncludeExclude.requireGroups.use = true
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
guest
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
subject.sources.xml.location =

subjectApi.source.ldap.id = ldap
subjectApi.source.ldap.name = EDU Ldap
subjectApi.source.ldap.types = person
subjectApi.source.ldap.adapterClass = edu.internet2.middleware.grouper.subj.GrouperJndiSourceAdapter
subjectApi.source.ldap.param.INITIAL_CONTEXT_FACTORY.value = com.sun.jndi.ldap.LdapCtxFactory
subjectApi.source.ldap.param.PROVIDER_URL.value = ldap://directory:389
subjectApi.source.ldap.param.SECURITY_AUTHENTICATION.value = simple
subjectApi.source.ldap.param.SECURITY_PRINCIPAL.value = cn=admin,dc=internet2,dc=edu
subjectApi.source.ldap.param.SECURITY_CREDENTIALS.value.elConfig = ${java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD_FILE') != null ? org.apache.commons.io.FileUtils.readFileToString(java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD_FILE'), "utf-8") : java.lang.System.getenv().get('SUBJECT_SOURCE_LDAP_PASSWORD')}
subjectApi.source.ldap.param.SubjectID_AttributeType.value = uid
subjectApi.source.ldap.param.SubjectID_formatToLowerCase.value = false
subjectApi.source.ldap.param.Name_AttributeType.value = cn
subjectApi.source.ldap.param.Description_AttributeType.value = cn
subjectApi.source.ldap.param.VTLDAP_VALIDATOR.value = ConnectLdapValidator
subjectApi.source.ldap.param.subjectVirtualAttribute_0_searchAttribute0.value = ${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('uid'), "")},${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('cn'), "")},${subjectUtils.defaultIfBlank(subject.getAttributeValueOrCommaSeparated('exampleEduRegId'), "")}
subjectApi.source.ldap.param.sortAttribute0.value = cn
subjectApi.source.ldap.param.searchAttribute0.value = searchAttribute0

# STATUS SECTION for searches to filter out inactives and allow
# the user to filter by status with e.g. status=all
# this is optional, and advanced
#
# field in database or ldap or endpoint that is the status field
#subjectApi.source.example.param.statusDatastoreFieldName.value = status

# search string from user which represents the status. e.g. status=active
#subjectApi.source.example.param.statusLabel.value = status

# available statuses from screen (if not specified, any will be allowed). comma separated list.
# Note, this is optional and you probably dont want to configure it, it is mostly necessary
# when you have multiple sources with statuses... if someone types an invalid status
# and you have this configured, it will not filter by it
#subjectApi.source.example.param.statusesFromUser.value = Active, Inactive, Pending, All

# all label from the user
#subjectApi.source.example.param.statusAllFromUser.value = All

# if no status is specified, this will be used (e.g. for active only). Note, the value should be of the
# form the user would type in
#subjectApi.source.example.param.statusSearchDefault.value = status=active

# translate between screen values of status, and the data store value. Increment the 0 to 1, 2, etc for more translations.
# so the user could enter: status=active, and that could translate to status_col=A. The 'user' is what the user types in,
# the 'datastore' is what is in the datastore. The user part is not case-sensitive. Note, this could be a many to one
#subjectApi.source.example.param.statusTranslateUser0.value = active
#subjectApi.source.example.param.statusTranslateDatastore0.value = A

# subject identifier to store in grouper's member table. this is used to increase speed of loader and perhaps for provisioning
# you can have up to max 1 subject identifier
#subjectApi.source.example.param.subjectIdentifierAttribute0.value = uid

#searchSubject: find a subject by ID. ID is generally an opaque and permanent identifier, e.g. 12345678.
# Each subject has one and only on ID. Returns one result when searching for one ID.
subjectApi.source.ldap.search.searchSubject.param.filter.value = (&(uid=%TERM%)(objectclass=person))
subjectApi.source.ldap.search.searchSubject.param.scope.value = SUBTREE_SCOPE
subjectApi.source.ldap.search.searchSubject.param.base.value = ou=people,dc=internet2,dc=edu

#searchSubjectByIdentifier: find a subject by identifier. Identifier is anything that uniquely
# identifies the user, e.g. jsmith or jsmith@institution.edu.
# Subjects can have multiple identifiers. Note: it is nice to have if identifiers are unique
# even across sources. Returns one result when searching for one identifier.
subjectApi.source.ldap.search.searchSubjectByIdentifier.param.filter.value = (&(|(uid=%TERM%)(employeeNumber=%TERM%))(objectclass=person))
subjectApi.source.ldap.search.searchSubjectByIdentifier.param.scope.value = SUBTREE_SCOPE
subjectApi.source.ldap.search.searchSubjectByIdentifier.param.base.value = ou=people,dc=internet2,dc=edu

# search: find subjects by free form search. Returns multiple results.

subjectApi.source.ldap.search.search.param.filter.value = (&(|(|(uid=%TERM%)(cn=*%TERM%*))(uid=%TERM%*))(objectclass=person))
subjectApi.source.ldap.search.search.param.scope.value = SUBTREE_SCOPE
subjectApi.source.ldap.search.search.param.base.value = ou=people,dc=internet2,dc=edu

subjectApi.source.ldap.attributes = givenName, sn, uid, mail, employeeNumber
subjectApi.source.ldap.internalAttributes = searchAttribute0
Empty file.
20 changes: 20 additions & 0 deletions demo/complex/configs-and-secrets/grouper/httpd/host-cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDPDCCAiQCCQDNZe8r0hVtuTANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCTUkxEjAQBgNVBAcMCUFubiBBcmJvcjEXMBUGA1UECgwOSW50
ZXJuZXQyL1RJRVIxFzAVBgNVBAMMDnNwLmV4YW1wbGUub3JnMB4XDTE3MDkyMjE5
NTAzNVoXDTI3MDkyMDE5NTAzNVowYDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1J
MRIwEAYDVQQHDAlBbm4gQXJib3IxFzAVBgNVBAoMDkludGVybmV0Mi9USUVSMRcw
FQYDVQQDDA5zcC5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAMTNJmsNpTpR4NrDJwOgK/o3UYlNdi1c6xBflt+liLAsQc160QReV4dS
SGK8LZvN58a/BTIsH8dLhQlUQ8qQUY2AfolVrNxb7Waumeh/POzYUTRylnoGpU3W
bGMEPxE/AdgP5U/adYvyu4XI5epv7wjZJOTqcVag15SalY+aso+ZC/5l+UzRxmWB
ZxKTsSL1y7PFehY4/Zl3Y3oGVsVl/zspt5lteoZQeeVxUX29S3Af11yHY4xpEp+7
rvAzY/nlsTiHAsUoCFK/NFQ2evvSRx52B9Fk1cWP1MDVDm2QjQqD9xBGYSnX6bhQ
ejVx7JUJHlblu2Q5p5XdW0BihgFluoECAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
n/qhYnIviPs4tglCdrw+M7gbqKNWadDC3F9HDYzlJMFeS/ae2turhEUgQPbYPDQQ
eO3oOILtvCXNFUPM58jf8V5YFRrOqrTgx44kexQDaHO5YYNft5tF5TdvBYE2gOVr
GdYrH2iSP8WX+Yy7JH5uqkfwWzEntWHJdey39rCWKAUCCB35+/2b4N53Qmlv2+ug
CpNJYFtXInd4YMmM5HjXLyoWXtjnKiwDqYUCeYPSwAajnCqRqRXUX0gYTFDRiwRP
HbmO9We0nqoc/71nikmGGoSRMO/zWVMFjwmAx1fGiWdU61sjGX8sHifzmVyJVEBI
Z75p+JrWYZJYrx/vpWxL8g==
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions demo/complex/configs-and-secrets/grouper/httpd/host-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEzSZrDaU6UeDa
wycDoCv6N1GJTXYtXOsQX5bfpYiwLEHNetEEXleHUkhivC2bzefGvwUyLB/HS4UJ
VEPKkFGNgH6JVazcW+1mrpnofzzs2FE0cpZ6BqVN1mxjBD8RPwHYD+VP2nWL8ruF
yOXqb+8I2STk6nFWoNeUmpWPmrKPmQv+ZflM0cZlgWcSk7Ei9cuzxXoWOP2Zd2N6
BlbFZf87KbeZbXqGUHnlcVF9vUtwH9dch2OMaRKfu67wM2P55bE4hwLFKAhSvzRU
Nnr70kcedgfRZNXFj9TA1Q5tkI0Kg/cQRmEp1+m4UHo1ceyVCR5W5btkOaeV3VtA
YoYBZbqBAgMBAAECggEAA/5t0ypZug9DUu0283niqpdIzlKGHXGPS6vE8hD37ytW
wobFiyMm/5YJ5gcPnePV2lCyGEyQ8Ih10LSnE4tOPGLpLnxQn8A11ymf8fnzEJNr
Qnc42o0b+bJqTLAfX4g5z1qzOqWiUQ7CA3sKP3G6FiHh/8tKNYnaFif09Q8cpJFb
YDDkvm48NJgsrIoCgmaFIQIn+yDzGQKWwTNMIks+RByWpc67j1x1kiyQM1RfrEev
Yyq/ZkP66IYZzmZKpFCWGs5qbRZdxyXNpq85DjwA99lAH7vxtMJHQM4z1h1eDH4L
Ma5hEnmmHu4D5lF2GDQYflvuFdDGH5tThO6MV0IrSQKBgQD+kvEtNxJCMxLOVFyV
NWF3pk/i2nkD+53t/VPXjMPtW7IesouEGzU82I/fT2wUTkNwFdkVpv37qoLypKZm
npJFxr6abQNjiDh2Fsh8/iuJfvdZUFJbCEY6NS58qgjix8XCQKRD06EugK7uekIZ
zJnttF3qVBBD8Z8Uwxz8i+jF1wKBgQDF51y/5XB6Bz47cdxw7P8NsfnTz2V3H0HU
OnlEBANbhmBadjU8dqbM54Nxbn7VOdooXPuSnAKJ9vPDg1n5Y/GO+lgldNzfyK6g
HnbldSu0zBvAaGvmAjLjetEtOkBqYkrHJlT6JAems/Kc/YX5uooAz9/jNJFXP9++
KbjH3CzHZwKBgQC6ppxEDZPKi83nD/2NvMTIyFzcNFj0LaEepFW7vc7NkiSn0zrt
0lEXWqUqEv5oaPWTEcHH2VdxFRTLuSL0LKGMnWqUqQcKDA9xrcSzuFvNhRTwHC81
5XwwI1wBNV4sgFKj2WdW/6y2/szDt0oNxnC50zvkmlwOpPKBc4kmNaKmowKBgBmC
uXIDIXyZcmw3QTNNWZNqXcnv8iRo4xN4dilOWyBxMfp3QmWI5feD4G2+0Jqr2nNZ
iRRdB/bA3qtVQ0PinkDQBIzPg6lVNS1uv+TUNc4YgXtL+pyrq+Om8U/jMmqEQR9q
0YltG49houSZyatnYGK6aSHgpNuaYD0jI66fsyYBAoGAMefyD0I/ncArjuf58hVQ
zSjxfcvlja9okrC8ZgqsVluezcm4rQNcSjBnESGTCjJC7O29AofGLHkvnsBQDiGk
hE38IRisd+okXdApr41ifWDhmtASud5q6wlhOpMmQxg+OALf1rTvFYhbnFEXV/KY
e5A4iXLRIbxbmXZDa35Rebw=
-----END PRIVATE KEY-----
Loading

0 comments on commit 6e3c0d0

Please sign in to comment.