Repository: qpid-dispatch
Updated Branches:
refs/heads/crolke-DISPATCH-188-1 49e64e597 -> cd4b30222
Add accessors for username and the AMQP Open remote_hostname.
Add tests/policy-2 folder with generated SASL setup that plays with
test policyserver configuration.
Run qdrouter with:
qdrouterd -c <builddir>/tests/policy-2/test-router-with-policy.json \
-I <sourcedir>/python
Test it with:
qdmanage -b amqp://u1:[email protected]:21000 --type policyStats query
Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/cd4b3022
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/cd4b3022
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/cd4b3022
Branch: refs/heads/crolke-DISPATCH-188-1
Commit: cd4b302224694b9235740951784573dcab947d2d
Parents: 49e64e5
Author: Chuck Rolke <[email protected]>
Authored: Sat Feb 6 10:49:25 2016 -0500
Committer: Chuck Rolke <[email protected]>
Committed: Sat Feb 6 10:49:25 2016 -0500
----------------------------------------------------------------------
src/policy.c | 2 +-
tests/CMakeLists.txt | 4 +-
tests/policy-1/test-router-with-policy.json | 182 --------------------
tests/policy-2/make-sasl.sh | 63 +++++++
tests/policy-2/policy-photoserver-sasl.conf.in | 4 +
tests/policy-2/policy-photoserver-sasl.sasldb | Bin 0 -> 12288 bytes
tests/policy-2/ssl_certs/gencerts.sh | 39 +++++
tests/policy-2/test-router-with-policy.json.in | 147 ++++++++++++++++
8 files changed, 257 insertions(+), 184 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cd4b3022/src/policy.c
----------------------------------------------------------------------
diff --git a/src/policy.c b/src/policy.c
index 2d285fa..3661636 100644
--- a/src/policy.c
+++ b/src/policy.c
@@ -232,7 +232,7 @@ void qd_policy_amqp_open(void *context, bool discard)
const char *username = pn_transport_get_user(pn_trans);
const char *hostip = qdpn_connector_hostip(qd_conn->pn_cxtr);
- const char *app = "fixme";
+ const char *app = pn_connection_remote_hostname(conn);
const char *conn_name = qdpn_connector_name(qd_conn->pn_cxtr);
if ( qd_policy_open_lookup_user(policy, username, hostip, app,
conn_name) ) {
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cd4b3022/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index b43903a..82041b1 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -122,6 +122,9 @@ file(COPY
${CMAKE_CURRENT_SOURCE_DIR}/sasl_configs/tests-mech-EXTERNAL.conf DEST
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/sasl_configs/tests-mech-NOEXTERNAL.conf
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/sasl_configs)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/ssl_certs DESTINATION
${CMAKE_CURRENT_BINARY_DIR})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sasl_configs/tests-mech-PLAIN.conf.in
${CMAKE_CURRENT_BINARY_DIR}/sasl_configs/tests-mech-PLAIN.conf)
+file(COPY
${CMAKE_CURRENT_SOURCE_DIR}/policy-2/policy-photoserver-sasl.sasldb
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/policy-2)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/policy-2/policy-photoserver-sasl.conf.in
${CMAKE_CURRENT_BINARY_DIR}/policy-2/policy-photoserver-sasl.conf)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/policy-2/test-router-with-policy.json.in
${CMAKE_CURRENT_BINARY_DIR}/policy-2/test-router-with-policy.json)
# following install() functions will be called only if you do a make "install"
install(FILES ${SYSTEM_TEST_FILES}
@@ -140,4 +143,3 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/config-2
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ssl_certs
DESTINATION ${QPID_DISPATCH_HOME_INSTALLED}/tests)
-
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cd4b3022/tests/policy-1/test-router-with-policy.json
----------------------------------------------------------------------
diff --git a/tests/policy-1/test-router-with-policy.json
b/tests/policy-1/test-router-with-policy.json
deleted file mode 100644
index 3e92b49..0000000
--- a/tests/policy-1/test-router-with-policy.json
+++ /dev/null
@@ -1,182 +0,0 @@
-[
- ["container", {
- "containerName": "QdstatSslTest",
- "saslConfigName": "tests-mech-PLAIN",
- "saslConfigPath": "/home/chug/Research/qdr/standaloneSsl/sasl_configs",
- "debugDump": "qddebug.txt"
- }],
- ["sslProfile", {
- "certFile":
"/home/chug/Research/qdr/standaloneSsl/ssl_certs/server-certificate.pem",
- "keyFile":
"/home/chug/Research/qdr/standaloneSsl/ssl_certs/server-private-key.pem",
- "password": "server-password",
- "name": "server-ssl",
- "certDb":
"/home/chug/Research/qdr/standaloneSsl/ssl_certs/ca-certificate.pem"
- }],
- ["listener", {
- "saslMechanisms": "ANONYMOUS PLAIN",
- "authenticatePeer": "no",
- "idleTimeoutSeconds": "120",
- "port": 21000,
- "addr": "0.0.0.0"
- }],
- ["listener", {
- "addr": "0.0.0.0",
- "requireSsl": "yes",
- "idleTimeoutSeconds": "120",
- "saslMechanisms": "PLAIN",
- "sslProfile": "server-ssl",
- "authenticatePeer": "no",
- "port": 21001
- }],
- ["listener", {
- "addr": "0.0.0.0",
- "requireSsl": "no",
- "idleTimeoutSeconds": "120",
- "saslMechanisms": "ANONYMOUS",
- "sslProfile": "server-ssl",
- "authenticatePeer": "no",
- "port": 21002
- }],
- ["listener", {
- "addr": "0.0.0.0",
- "requireSsl": "yes",
- "idleTimeoutSeconds": "120",
- "saslMechanisms": "EXTERNAL",
- "sslProfile": "server-ssl",
- "authenticatePeer": "yes",
- "port": 21003
- }],
- ["listener", {
- "addr": "0.0.0.0",
- "requireSsl": "no",
- "idleTimeoutSeconds": "120",
- "saslMechanisms": "ANONYMOUS",
- "authenticatePeer": "yes",
- "port": 21004
- }],
- ["log", {
- "source": "true",
- "enable": "trace+",
- "module": "DEFAULT"
- }],
- ["policy", {
- "maximumConnections": 2
- }],
- ["policyRuleset", {
- "applicationName": "photoserver",
- "maxConnections": 50,
- "maxConnPerUser": 5,
- "maxConnPerHost": 20,
- "userGroups": {
- "anonymous": "anonymous",
- "users": "u1, u2",
- "paidsubscribers": "p1, p2",
- "test": "zeke, ynot",
- "admin": "alice, bob",
- "superuser": "ellen"
- },
- "connectionGroups": {
- "Ten18": "10.18.0.0-10.18.255.255",
- "EllensWS": "72.135.2.9",
- "TheLabs": "10.48.0.0-10.48.255.255, 192.168.100.0-192.168.100.255",
- "localhost": "127.0.0.1, ::1",
- "TheWorld": "*"
- },
- "connectionIngressPolicies": {
- "anonymous": "TheWorld",
- "users": "TheWorld",
- "paidsubscribers": "TheWorld",
- "test": "TheLabs",
- "admin": "Ten18, TheLabs, localhost",
- "superuser": "EllensWS, localhost"
- },
- "connectionAllowDefault": true,
- "settings": {
- "anonymous" : {
- "maxFrameSize": 111111,
- "maxMessageSize": 111111,
- "maxSessionWindow": 111111,
- "maxSessions": 1,
- "maxSenders": 11,
- "maxReceivers": 11,
- "allowDynamicSrc": false,
- "allowAnonymousSender": false,
- "sources": "public",
- "targets": ""
- },
- "users" : {
- "maxFrameSize": 222222,
- "maxMessageSize": 222222,
- "maxSessionWindow": 222222,
- "maxSessions": 2,
- "maxSenders": 22,
- "maxReceivers": 22,
- "allowDynamicSrc": false,
- "allowAnonymousSender": false,
- "sources": "public, private",
- "targets": "public"
- },
- "paidsubscribers" : {
- "maxFrameSize": 333333,
- "maxMessageSize": 333333,
- "maxSessionWindow": 333333,
- "maxSessions": 3,
- "maxSenders": 33,
- "maxReceivers": 33,
- "allowDynamicSrc": true,
- "allowAnonymousSender": false,
- "sources": "public, private",
- "targets": "public, private"
- },
- "test" : {
- "maxFrameSize": 444444,
- "maxMessageSize": 444444,
- "maxSessionWindow": 444444,
- "maxSessions": 4,
- "maxSenders": 44,
- "maxReceivers": 44,
- "allowDynamicSrc": true,
- "allowAnonymousSender": true,
- "sources": "private",
- "targets": "private"
- },
- "admin" : {
- "maxFrameSize": 555555,
- "maxMessageSize": 555555,
- "maxSessionWindow": 555555,
- "maxSessions": 5,
- "maxSenders": 55,
- "maxReceivers": 55,
- "allowDynamicSrc": true,
- "allowAnonymousSender": true,
- "sources": "public, private, management",
- "targets": "public, private, management"
- },
- "superuser" : {
- "maxFrameSize": 666666,
- "maxMessageSize": 666666,
- "maxSessionWindow": 666666,
- "maxSessions": 6,
- "maxSenders": 66,
- "maxReceivers": 66,
- "allowDynamicSrc": false,
- "allowAnonymousSender": false,
- "sources": "public, private, management, root",
- "targets": "public, private, management, root"
- },
- "default" : {
- "maxFrameSize": 222222,
- "maxMessageSize": 222222,
- "maxSessionWindow": 222222,
- "maxSessions": 2,
- "maxSenders": 22,
- "maxReceivers": 22,
- "allowDynamicSrc": false,
- "allowAnonymousSender": false,
- "sources": "public, private",
- "targets": "public"
- }
- }
- }
- ]
-]
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cd4b3022/tests/policy-2/make-sasl.sh
----------------------------------------------------------------------
diff --git a/tests/policy-2/make-sasl.sh b/tests/policy-2/make-sasl.sh
new file mode 100755
index 0000000..d56d529
--- /dev/null
+++ b/tests/policy-2/make-sasl.sh
@@ -0,0 +1,63 @@
+#!/bin/bash -ex
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+#
+# Generate sasl files for policy tests using test setup for 'photoserver'
+# This file is used to generate the files which are then committed to git
+# and distributed in the make install.
+#
+# sasldb file is generated and copied to tests/policy-2/ by cmake
+#
+export sasl_file=./policy-photoserver-sasl.sasldb
+
+echo password | saslpasswd2 -c -p -f ${sasl_file} -u qdrouterd anonymous
+echo password | saslpasswd2 -c -p -f ${sasl_file} -u qdrouterd u1
+echo password | saslpasswd2 -c -p -f ${sasl_file} -u qdrouterd u2
+echo password | saslpasswd2 -c -p -f ${sasl_file} -u qdrouterd p1
+echo password | saslpasswd2 -c -p -f ${sasl_file} -u qdrouterd p2
+echo password | saslpasswd2 -c -p -f ${sasl_file} -u qdrouterd zeke
+echo password | saslpasswd2 -c -p -f ${sasl_file} -u qdrouterd ynot
+echo password | saslpasswd2 -c -p -f ${sasl_file} -u qdrouterd alice
+echo password | saslpasswd2 -c -p -f ${sasl_file} -u qdrouterd bob
+echo password | saslpasswd2 -c -p -f ${sasl_file} -u qdrouterd ellen
+echo password | saslpasswd2 -c -p -f ${sasl_file} -u qdrouterd charlie
+
+echo password | saslpasswd2 -c -p -f ${sasl_file} anonymous
+echo password | saslpasswd2 -c -p -f ${sasl_file} u1
+echo password | saslpasswd2 -c -p -f ${sasl_file} u2
+echo password | saslpasswd2 -c -p -f ${sasl_file} p1
+echo password | saslpasswd2 -c -p -f ${sasl_file} p2
+echo password | saslpasswd2 -c -p -f ${sasl_file} zeke
+echo password | saslpasswd2 -c -p -f ${sasl_file} ynot
+echo password | saslpasswd2 -c -p -f ${sasl_file} alice
+echo password | saslpasswd2 -c -p -f ${sasl_file} bob
+echo password | saslpasswd2 -c -p -f ${sasl_file} ellen
+echo password | saslpasswd2 -c -p -f ${sasl_file} charlie
+
+sasldblistusers2 -f ${sasl_file}
+
+# Make sasl conf file
+# sasl.conf is generated and 'config'd by cmake
+cat > ./policy-photoserver-sasl.conf.in << "EOF"
+pwcheck_method: auxprop
+auxprop_plugin: sasldb
+sasldb_path:
${CMAKE_CURRENT_BINARY_DIR}/policy-2/policy-photoserver-sasl.sasldb
+mech_list: PLAIN ANONYMOUS
+EOF
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cd4b3022/tests/policy-2/policy-photoserver-sasl.conf.in
----------------------------------------------------------------------
diff --git a/tests/policy-2/policy-photoserver-sasl.conf.in
b/tests/policy-2/policy-photoserver-sasl.conf.in
new file mode 100644
index 0000000..e9650b6
--- /dev/null
+++ b/tests/policy-2/policy-photoserver-sasl.conf.in
@@ -0,0 +1,4 @@
+pwcheck_method: auxprop
+auxprop_plugin: sasldb
+sasldb_path:
${CMAKE_CURRENT_BINARY_DIR}/policy-2/policy-photoserver-sasl.sasldb
+mech_list: PLAIN ANONYMOUS
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cd4b3022/tests/policy-2/policy-photoserver-sasl.sasldb
----------------------------------------------------------------------
diff --git a/tests/policy-2/policy-photoserver-sasl.sasldb
b/tests/policy-2/policy-photoserver-sasl.sasldb
new file mode 100644
index 0000000..f145b16
Binary files /dev/null and b/tests/policy-2/policy-photoserver-sasl.sasldb
differ
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cd4b3022/tests/policy-2/ssl_certs/gencerts.sh
----------------------------------------------------------------------
diff --git a/tests/policy-2/ssl_certs/gencerts.sh
b/tests/policy-2/ssl_certs/gencerts.sh
new file mode 100755
index 0000000..faca0a2
--- /dev/null
+++ b/tests/policy-2/ssl_certs/gencerts.sh
@@ -0,0 +1,39 @@
+#!/bin/bash -ex
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+export SERVER=A1.Good.Server.domain.com
+export CLIENT=127.0.0.1
+
+keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca
-keypass ca-password -genkey -dname "O=Trust Me Inc.,CN=Trusted.CA.com"
-validity 99999
+openssl pkcs12 -nokeys -passin pass:ca-password -in ca.pkcs12 -passout
pass:ca-password -out ca-certificate.pem
+
+keytool -storetype pkcs12 -keystore bad-ca.pkcs12 -storepass bad-ca-password
-alias bad-ca -keypass bad-ca-password -genkey -dname "O=Trust Me
Inc.,CN=Trusted.CA.com" -validity 99999
+openssl pkcs12 -nokeys -passin pass:bad-ca-password -in bad-ca.pkcs12 -passout
pass:bad-ca-password -out bad-ca-certificate.pem
+
+keytool -storetype pkcs12 -keystore server.pkcs12 -storepass server-password
-alias server-certificate -keypass server-password -genkey -dname
"O=Server,CN=$SERVER" -validity 99999
+keytool -storetype pkcs12 -keystore server.pkcs12 -storepass server-password
-alias server-certificate -keypass server-password -certreq -file
server-request.pem
+keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca
-keypass ca-password -gencert -rfc -validity 99999 -infile server-request.pem
-outfile server-certificate.pem
+openssl pkcs12 -nocerts -passin pass:server-password -in server.pkcs12
-passout pass:server-password -out server-private-key.pem
+
+keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password
-alias client-certificate -keypass client-password -genkey -dname
"O=Client,CN=$CLIENT" -validity 99999
+keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password
-alias client-certificate -keypass client-password -certreq -file
client-request.pem
+keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca
-keypass ca-password -gencert -rfc -validity 99999 -infile client-request.pem
-outfile client-certificate.pem
+openssl pkcs12 -nocerts -passin pass:client-password -in client.pkcs12
-passout pass:client-password -out client-private-key.pem
http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/cd4b3022/tests/policy-2/test-router-with-policy.json.in
----------------------------------------------------------------------
diff --git a/tests/policy-2/test-router-with-policy.json.in
b/tests/policy-2/test-router-with-policy.json.in
new file mode 100644
index 0000000..f7b7326
--- /dev/null
+++ b/tests/policy-2/test-router-with-policy.json.in
@@ -0,0 +1,147 @@
+[
+ ["container", {
+ "containerName": "dispatch",
+ "saslConfigName": "policy-photoserver-sasl",
+ "saslConfigPath": "${CMAKE_CURRENT_BINARY_DIR}/policy-2",
+ "debugDump": "qddebug.txt"
+ }],
+ ["listener", {
+ "addr": "0.0.0.0",
+ "saslMechanisms": "ANONYMOUS PLAIN",
+ "authenticatePeer": "no",
+ "idleTimeoutSeconds": "120",
+ "port": 21000
+ }],
+ ["listener", {
+ "addr": "0.0.0.0",
+ "saslMechanisms": "PLAIN",
+ "authenticatePeer": "no",
+ "idleTimeoutSeconds": "120",
+ "port": 21001
+ }],
+ ["log", {
+ "source": "true",
+ "enable": "trace+",
+ "module": "DEFAULT"
+ }],
+ ["policy", {
+ "maximumConnections": 2
+ }],
+ ["policyRuleset", {
+ "applicationName": "photoserver",
+ "maxConnections": 50,
+ "maxConnPerUser": 5,
+ "maxConnPerHost": 20,
+ "userGroups": {
+ "anonymous": "anonymous",
+ "users": "u1, u2",
+ "paidsubscribers": "p1, p2",
+ "test": "zeke, ynot",
+ "admin": "alice, bob",
+ "superuser": "ellen"
+ },
+ "connectionGroups": {
+ "Ten18": "10.18.0.0-10.18.255.255",
+ "EllensWS": "72.135.2.9",
+ "TheLabs": "10.48.0.0-10.48.255.255, 192.168.100.0-192.168.100.255",
+ "localhost": "127.0.0.1, ::1",
+ "TheWorld": "*"
+ },
+ "connectionIngressPolicies": {
+ "anonymous": "TheWorld",
+ "users": "TheWorld",
+ "paidsubscribers": "TheWorld",
+ "test": "TheLabs",
+ "admin": "Ten18, TheLabs, localhost",
+ "superuser": "EllensWS, localhost"
+ },
+ "connectionAllowDefault": true,
+ "settings": {
+ "anonymous" : {
+ "maxFrameSize": 111111,
+ "maxMessageSize": 111111,
+ "maxSessionWindow": 111111,
+ "maxSessions": 1,
+ "maxSenders": 11,
+ "maxReceivers": 11,
+ "allowDynamicSrc": false,
+ "allowAnonymousSender": false,
+ "sources": "public",
+ "targets": ""
+ },
+ "users" : {
+ "maxFrameSize": 222222,
+ "maxMessageSize": 222222,
+ "maxSessionWindow": 222222,
+ "maxSessions": 2,
+ "maxSenders": 22,
+ "maxReceivers": 22,
+ "allowDynamicSrc": false,
+ "allowAnonymousSender": false,
+ "sources": "public, private",
+ "targets": "public"
+ },
+ "paidsubscribers" : {
+ "maxFrameSize": 333333,
+ "maxMessageSize": 333333,
+ "maxSessionWindow": 333333,
+ "maxSessions": 3,
+ "maxSenders": 33,
+ "maxReceivers": 33,
+ "allowDynamicSrc": true,
+ "allowAnonymousSender": false,
+ "sources": "public, private",
+ "targets": "public, private"
+ },
+ "test" : {
+ "maxFrameSize": 444444,
+ "maxMessageSize": 444444,
+ "maxSessionWindow": 444444,
+ "maxSessions": 4,
+ "maxSenders": 44,
+ "maxReceivers": 44,
+ "allowDynamicSrc": true,
+ "allowAnonymousSender": true,
+ "sources": "private",
+ "targets": "private"
+ },
+ "admin" : {
+ "maxFrameSize": 555555,
+ "maxMessageSize": 555555,
+ "maxSessionWindow": 555555,
+ "maxSessions": 5,
+ "maxSenders": 55,
+ "maxReceivers": 55,
+ "allowDynamicSrc": true,
+ "allowAnonymousSender": true,
+ "sources": "public, private, management",
+ "targets": "public, private, management"
+ },
+ "superuser" : {
+ "maxFrameSize": 666666,
+ "maxMessageSize": 666666,
+ "maxSessionWindow": 666666,
+ "maxSessions": 6,
+ "maxSenders": 66,
+ "maxReceivers": 66,
+ "allowDynamicSrc": false,
+ "allowAnonymousSender": false,
+ "sources": "public, private, management, root",
+ "targets": "public, private, management, root"
+ },
+ "default" : {
+ "maxFrameSize": 222222,
+ "maxMessageSize": 222222,
+ "maxSessionWindow": 222222,
+ "maxSessions": 2,
+ "maxSenders": 22,
+ "maxReceivers": 22,
+ "allowDynamicSrc": false,
+ "allowAnonymousSender": false,
+ "sources": "public, private",
+ "targets": "public"
+ }
+ }
+ }
+ ]
+]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]