From dd92ffbddbb8e87305e895d2237a6cd087ded81b Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Tue, 20 Aug 2024 21:36:49 +0800 Subject: [PATCH 01/23] Add mtls test. --- .../mqtt3/fusesource/proxy/ProxyMtlsTest.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java new file mode 100644 index 000000000..4e5c08ab5 --- /dev/null +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java @@ -0,0 +1,85 @@ +package io.streamnative.pulsar.handlers.mqtt.mqtt3.fusesource.proxy; + +import io.streamnative.pulsar.handlers.mqtt.MQTTCommonConfiguration; +import io.streamnative.pulsar.handlers.mqtt.base.MQTTTestBase; +import org.fusesource.mqtt.client.BlockingConnection; +import org.fusesource.mqtt.client.MQTT; +import org.fusesource.mqtt.client.Message; +import org.fusesource.mqtt.client.QoS; +import org.fusesource.mqtt.client.Topic; +import org.testng.Assert; +import org.testng.annotations.Test; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.File; +import java.io.FileInputStream; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.util.Random; + +public class ProxyMtlsTest extends MQTTTestBase { + + String path = "./src/test/resources/mtls/"; + + private final Random random = new Random(); + + @Override + protected MQTTCommonConfiguration initConfig() throws Exception { + enableTls = true; + MQTTCommonConfiguration mqtt = super.initConfig(); + + mqtt.setMqttProxyEnabled(true); + mqtt.setMqttProxyTlsEnabled(true); + mqtt.setMqttTlsCertificateFilePath(path + "server.crt"); + mqtt.setMqttTlsKeyFilePath(path + "server.key"); + + return mqtt; + } + + public SSLContext createSSLContext() throws Exception { + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + try (FileInputStream fis = new FileInputStream(path + "client.p12")) { + keyStore.load(fis, "".toCharArray()); + } + + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(keyStore, "".toCharArray()); + + File crtFile = new File(path + "server.crt"); + Certificate certificate = CertificateFactory + .getInstance("X.509").generateCertificate(new FileInputStream(crtFile)); + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null, null); + trustStore.setCertificateEntry("server", certificate); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(trustStore); + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new java.security.SecureRandom()); + + return sslContext; + } + + @Test + public void testProduceAndConsume() throws Exception { + SSLContext sslContext = createSSLContext(); + MQTT mqtt = createMQTTProxyTlsClient(); + mqtt.setSslContext(sslContext); + + String topicName = "testProduceAndConsume"; + BlockingConnection connection = mqtt.blockingConnection(); + connection.connect(); + Topic[] topics = { new Topic(topicName, QoS.AT_MOST_ONCE) }; + connection.subscribe(topics); + String message = "Hello MQTT"; + connection.publish(topicName, message.getBytes(), QoS.AT_MOST_ONCE, false); + Message received = connection.receive(); + Assert.assertEquals(received.getTopic(), topicName); + Assert.assertEquals(new String(received.getPayload()), message); + received.ack(); + connection.disconnect(); + } +} From 871ac6142d470e4cc16d278b2b35e2127c9947a9 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Tue, 20 Aug 2024 21:42:36 +0800 Subject: [PATCH 02/23] add license header --- .../mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java index 4e5c08ab5..a0aa0ae77 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java @@ -1,3 +1,16 @@ +/** + * 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. + */ package io.streamnative.pulsar.handlers.mqtt.mqtt3.fusesource.proxy; import io.streamnative.pulsar.handlers.mqtt.MQTTCommonConfiguration; From 3ac5d4fe4b89b809b5d50a9636334efb3c888a81 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Tue, 20 Aug 2024 21:48:17 +0800 Subject: [PATCH 03/23] fix checkstyle --- .../mqtt3/fusesource/proxy/ProxyMtlsTest.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java index a0aa0ae77..b9babbd40 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java @@ -15,6 +15,15 @@ import io.streamnative.pulsar.handlers.mqtt.MQTTCommonConfiguration; import io.streamnative.pulsar.handlers.mqtt.base.MQTTTestBase; +import java.io.File; +import java.io.FileInputStream; +import java.security.KeyStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.util.Random; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; import org.fusesource.mqtt.client.BlockingConnection; import org.fusesource.mqtt.client.MQTT; import org.fusesource.mqtt.client.Message; @@ -22,15 +31,6 @@ import org.fusesource.mqtt.client.Topic; import org.testng.Assert; import org.testng.annotations.Test; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; -import java.io.File; -import java.io.FileInputStream; -import java.security.KeyStore; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import java.util.Random; public class ProxyMtlsTest extends MQTTTestBase { From 2dd00d6d47c29a43ec879c89d098bdd9e44680b5 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Tue, 20 Aug 2024 21:49:18 +0800 Subject: [PATCH 04/23] add cert file --- tests/src/test/resources/mtls/ca.cer | 18 +++++++++++++++ tests/src/test/resources/mtls/ca.csr | 15 ++++++++++++ tests/src/test/resources/mtls/ca.key | 28 +++++++++++++++++++++++ tests/src/test/resources/mtls/ca.p12 | Bin 0 -> 2483 bytes tests/src/test/resources/mtls/ca.srl | 1 + tests/src/test/resources/mtls/client.cer | 18 +++++++++++++++ tests/src/test/resources/mtls/client.csr | 15 ++++++++++++ tests/src/test/resources/mtls/client.key | 28 +++++++++++++++++++++++ tests/src/test/resources/mtls/client.p12 | Bin 0 -> 2531 bytes tests/src/test/resources/mtls/server.cer | 18 +++++++++++++++ tests/src/test/resources/mtls/server.crt | 18 +++++++++++++++ tests/src/test/resources/mtls/server.csr | 15 ++++++++++++ tests/src/test/resources/mtls/server.key | 28 +++++++++++++++++++++++ tests/src/test/resources/mtls/server.p12 | Bin 0 -> 2531 bytes 14 files changed, 202 insertions(+) create mode 100644 tests/src/test/resources/mtls/ca.cer create mode 100644 tests/src/test/resources/mtls/ca.csr create mode 100644 tests/src/test/resources/mtls/ca.key create mode 100644 tests/src/test/resources/mtls/ca.p12 create mode 100644 tests/src/test/resources/mtls/ca.srl create mode 100644 tests/src/test/resources/mtls/client.cer create mode 100644 tests/src/test/resources/mtls/client.csr create mode 100644 tests/src/test/resources/mtls/client.key create mode 100644 tests/src/test/resources/mtls/client.p12 create mode 100644 tests/src/test/resources/mtls/server.cer create mode 100644 tests/src/test/resources/mtls/server.crt create mode 100644 tests/src/test/resources/mtls/server.csr create mode 100644 tests/src/test/resources/mtls/server.key create mode 100644 tests/src/test/resources/mtls/server.p12 diff --git a/tests/src/test/resources/mtls/ca.cer b/tests/src/test/resources/mtls/ca.cer new file mode 100644 index 000000000..7a6113eed --- /dev/null +++ b/tests/src/test/resources/mtls/ca.cer @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC0zCCAbugAwIBAgIUOmhPX7hCH5pdeph+Wi4iitxLPswwDQYJKoZIhvcNAQEL +BQAwETEPMA0GA1UEAwwGUk9PVENBMCAXDTI0MDgyMDExMzgyMloYDzIxMjQwNzI3 +MTEzODIyWjARMQ8wDQYDVQQDDAZST09UQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDRl9g6I8aXzi77QY7ARHRl/ArCj38sQFjdQa848afsNqRD1P55 +jaiM9YXwJokkWSmr2xbkNI55Lz4zq1jx6ydRFeEuwYXocLagUWGdudKjhv6eghpY +Yfl9xumV9+SgG78nwLfeGvzDJ6KIFdfP4uiTFcfJjNlsoISkXQaQuVpPso+Le+FA +TjymshjXRx04sKYnJS/XT3ppukXTcGiGRjlTSe4cAJDcUJs7HCRTzEgSffOiFQ0m +2DUpQ9XKsURsNaKaaJBxiiX/d+5u6a+EWMPUIe70lXFrj/vbWf7pdLlKVzaqmo6D +JSF6P5ucjqb0ype7dgYl7zWjHM+Zfxvgtmu3AgMBAAGjITAfMB0GA1UdDgQWBBS/ +tRdSUQkupbbdv9y5/ala7bN1lTANBgkqhkiG9w0BAQsFAAOCAQEAVEVXzWFwZWpJ +ubpKuBYe9VFAT/dOj08rUaI82ea9wqFq8YIenKhmvlEkL6Xyj5MntE539iIzsL2w +hTDbMAxZ82SkRG1sOmRoGH9v0h58urmWlDLBK/wlIATJoKgbdzuRxsbEK97WPZZ1 +A+GuWwXGpcMoH9wxEDxUnWD+wg+5ftqfrOggxuw1BQpo0tYbTUsAVpr9z9YU9rdd +0GYL3RB8tlC4ja+zh/sZ4jz2S1ZEB6ykTZ+mq2/kTWZ/k7Zcss7+r7O3UZP5UQ1C +43g50rkrFsMkiJKNYOdeHsYtFeiVaSYjE2huGcky96nhgQ1ExTdTGOo48Skqt/qA +xIPGX242jw== +-----END CERTIFICATE----- diff --git a/tests/src/test/resources/mtls/ca.csr b/tests/src/test/resources/mtls/ca.csr new file mode 100644 index 000000000..815f163d6 --- /dev/null +++ b/tests/src/test/resources/mtls/ca.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICVjCCAT4CAQAwETEPMA0GA1UEAwwGUk9PVENBMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA0ZfYOiPGl84u+0GOwER0ZfwKwo9/LEBY3UGvOPGn7Dak +Q9T+eY2ojPWF8CaJJFkpq9sW5DSOeS8+M6tY8esnURXhLsGF6HC2oFFhnbnSo4b+ +noIaWGH5fcbplffkoBu/J8C33hr8wyeiiBXXz+LokxXHyYzZbKCEpF0GkLlaT7KP +i3vhQE48prIY10cdOLCmJyUv1096abpF03BohkY5U0nuHACQ3FCbOxwkU8xIEn3z +ohUNJtg1KUPVyrFEbDWimmiQcYol/3fubumvhFjD1CHu9JVxa4/721n+6XS5Slc2 +qpqOgyUhej+bnI6m9MqXu3YGJe81oxzPmX8b4LZrtwIDAQABoAAwDQYJKoZIhvcN +AQELBQADggEBAAm0yuYvm9muZ09eMTPwOd+PGuqkRlOsXuua8llPAhQQUriz/Mft +ayzQ4KwVueviQDxPxFJPjIJ7C4sMTqkgVJbO36iT4ugzqDn59gVKrUcglDk/VScR +SJBk1cKbvbjyJZ/orxYZ15vzn7rVqxpmEjhgR4zWMxdALkpHd5H/ebqc184GIH9F +L5tY/G1JSxq4Ez5y4gX1HNsBo9+4i3bYOsxkE3Am8gMhFcJOzhmT5UgfXs61fZeJ +Y3NR9oPaYfHQPXGwFgonWs/eiL5q6IWyfCclqjbWUIa6ROc5efX5rROEtdJkcFup +3k6OcAX8WCbR8Yq64MMuf0PnSLStQh+AORA= +-----END CERTIFICATE REQUEST----- diff --git a/tests/src/test/resources/mtls/ca.key b/tests/src/test/resources/mtls/ca.key new file mode 100644 index 000000000..55ccbf439 --- /dev/null +++ b/tests/src/test/resources/mtls/ca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDRl9g6I8aXzi77 +QY7ARHRl/ArCj38sQFjdQa848afsNqRD1P55jaiM9YXwJokkWSmr2xbkNI55Lz4z +q1jx6ydRFeEuwYXocLagUWGdudKjhv6eghpYYfl9xumV9+SgG78nwLfeGvzDJ6KI +FdfP4uiTFcfJjNlsoISkXQaQuVpPso+Le+FATjymshjXRx04sKYnJS/XT3ppukXT +cGiGRjlTSe4cAJDcUJs7HCRTzEgSffOiFQ0m2DUpQ9XKsURsNaKaaJBxiiX/d+5u +6a+EWMPUIe70lXFrj/vbWf7pdLlKVzaqmo6DJSF6P5ucjqb0ype7dgYl7zWjHM+Z +fxvgtmu3AgMBAAECggEAIMdgJDubH/u5gkcO9cfe8mI4JpR9naSUoUnYBw5YJkun +ZgpmIAmFDkKJx3SnZx1gtIVnr5n+nDpEvpzyJKeTtw02cfMHJ8KU9T61Bw9cP4Hp +yU1spFzyQXb96hviUB32x9dOijhrRnQo6aKM5XDF0dcKr11NVb1G8VOxJqouUx8/ +9mf9W1Umf2JQ4SetQ/vktYMCke3BVgdnKPsNZbPTruWPXl28miVl/zWs++DEkwTL +4ZJrl3J+4D+2HGlxIJ9QVroA1D4RskXVdDqe0aE8wBME3wS/JYQSacG/pisvpAUz +ivXSWZGzv7OCzupB7ewRSNzZcsDTio3wXy3rZzHUKQKBgQDsrBHfteg0094iFuZ/ +Sp9nNLbryc9Ag+CNIqiAhiJbkgaGWtUaRhU3AaAYg2CJoJMAVY6fb1jYdAb4tgh7 +xq8+o7JS+ERVLcW1BgUOR4W8xjctKvNVqZ2x2AVNYcNwlJIb0nQyF4BLV+YzrHIV +NdDCkJzpB5+MjlJGNeOfc7W1yQKBgQDitaduEcKi6pK3wrlMk49S9+H4DL5TDg6k +gx4xFsBC8WZqipSN1KlcZEDIpm20rzOfet/kOQAME5989EzuNcrnJBlFmPiJ9rxv +IiHCab5mUhjXMRv6jo0Y5n21MPO9WL9ol9mzCvhDfDJnikeIiZztHAIuLM2pRYJL +BNzsW0nVfwKBgE4hQ8lJYP3Hj4ZLbw5IkTTd5yERvzR6FLAi5+N95Gu8WiESbVU+ +G5TMGZDeFgl5E+5BUFL7zCWwr/h9B3HtFj8khSL0yIIiGSl4ckTTgafe+6oSisAV +vXRPbvirtHw+37kFkcxTi8vTmbAnVoX//Qmt+c7H8HjTJv/8nEcwSKVZAoGAIP2w +VLsu6Mhb+3PRxUv/4mICNzebhriX9ubBwQD/j35TmhN6lL0qvDA2oTxe4JlSWNXn +uO12jUtZvTRL8apQUZyWNOOS33jRaRa9dO4wb/FofgA+gxK1g7ce+fwarCY7DHx0 +iLKC+EcdiqW7zSnBdVvLEW8hqo1b7ZDSmW6bav8CgYEAkT6msKVPZzADJlAAfc6N +cN8nXc5WH86V3qKwQUR4p2EP0ti67UE4t1tenuS61IeeQux22g9mO7KLc4os+35D +QmGtbaDa1oPBI5qgTM9SoLTSRQAnZRUWcSZN2RbmJym0EKswKjQzL2B3CyGOg0Mv +nSw7JE+3k6fSrJEb9rIuMZc= +-----END PRIVATE KEY----- diff --git a/tests/src/test/resources/mtls/ca.p12 b/tests/src/test/resources/mtls/ca.p12 new file mode 100644 index 0000000000000000000000000000000000000000..bffb33375b2df0f6552228a62b247dbf72318e84 GIT binary patch literal 2483 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 literal 0 HcmV?d00001 diff --git a/tests/src/test/resources/mtls/server.cer b/tests/src/test/resources/mtls/server.cer new file mode 100644 index 000000000..713cbc6fb --- /dev/null +++ b/tests/src/test/resources/mtls/server.cer @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC9zCCAd+gAwIBAgIUIv6phwXlPa0CN34gK4Z2YAOafs0wDQYJKoZIhvcNAQEL +BQAwETEPMA0GA1UEAwwGUk9PVENBMCAXDTI0MDgyMDExMzg1NloYDzIxMjQwNzI3 +MTEzODU2WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQC3VcW68VdUowsRYxwc8yH6cjIMYAFtTDQVjiu9eqMPUW0j +aj/tXwVql/gHBLkuRd0DCDgXaW5qSofykyOtU8hjAduNycDf4Qb7bv8Pan91j9x8 +UgBORk0fBqhm1pD2bDqVXdKvZF7Nj60ofeU3mWv6xg9FILUK3c5FD3bQVhTELbUi +JC4ay4jDMIuw+5D82f60s8RUmfOlSTtT1LZrCfJdNGnk7QNPefZbwMjl2MwnoY/8 +0IgVXvc3hg1bk9qgi0s2zaYvZomiE4mvo6FbfREFkuztqr0jtNBRep3Tilsq2zRl +9E0Sg1GBvr9Kegaa8g8IPpZ5oqr0YqOh1xX/WAPPAgMBAAGjQjBAMB0GA1UdDgQW +BBR9qjLZLqBi4ssG9re0LvL9gy6zFDAfBgNVHSMEGDAWgBS/tRdSUQkupbbdv9y5 +/ala7bN1lTANBgkqhkiG9w0BAQsFAAOCAQEAFQ++gIJmZXhSuKXPi3QlA1Wk6un7 +/0coZDWJg8EpVjw6stBHedNbf8RiKc8L+OVFkWqKna7/oFbcq+kAN/KZ8Zh/+3bH +jCJD8olPUCMKQUVefawuzEyv0q9t5f41XPoe9Gs2vieh6hIWtSpjobZAVxp4MPwG +k6SVqYxq305OBSfrNl7QMakv/GRvs37/2VRo3/v5e9/W/UbS4IQHmfIiEfPtuRyd +iCmuxppW1BgFcwLWt2buX2k8xkNGy5709wRIq+f6K6qdYRSfoPMZLJzHlW7r/pWb +OzBCSFlz7eFZxzqoSd3l2/qHk2tg+cY3pl+GkvubsXJTlsVn3mpxjiUCYw== +-----END CERTIFICATE----- diff --git a/tests/src/test/resources/mtls/server.crt b/tests/src/test/resources/mtls/server.crt new file mode 100644 index 000000000..030c99786 --- /dev/null +++ b/tests/src/test/resources/mtls/server.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC1zCCAb+gAwIBAgIUbAr8zoEcK7TWWvvVQcEY7FkeZ2MwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDgyMDExNTMyN1oXDTM0MDgx +ODExNTMyN1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAt1XFuvFXVKMLEWMcHPMh+nIyDGABbUw0FY4rvXqjD1Ft +I2o/7V8Fapf4BwS5LkXdAwg4F2luakqH8pMjrVPIYwHbjcnA3+EG+27/D2p/dY/c +fFIATkZNHwaoZtaQ9mw6lV3Sr2RezY+tKH3lN5lr+sYPRSC1Ct3ORQ920FYUxC21 +IiQuGsuIwzCLsPuQ/Nn+tLPEVJnzpUk7U9S2awnyXTRp5O0DT3n2W8DI5djMJ6GP +/NCIFV73N4YNW5PaoItLNs2mL2aJohOJr6OhW30RBZLs7aq9I7TQUXqd04pbKts0 +ZfRNEoNRgb6/SnoGmvIPCD6WeaKq9GKjodcV/1gDzwIDAQABoyEwHzAdBgNVHQ4E +FgQUfaoy2S6gYuLLBva3tC7y/YMusxQwDQYJKoZIhvcNAQELBQADggEBADOtJsIo +KICWLZNNqzbjQnmq4muHkkECEU+QPk3VSGmb6BtbgsNI+ZjNkYZhYkhVWiDWLYRM +6IuKbkm4qG29CJInBkMjsbjMqWa9o2C00GnK2E/WXIZOTNcTMqjPOTJt3LkfBoNt +J0MelOd+imHB+0NA7HyfnrQnH4veknhhLXImL0brgrdED8kieylenzm9DHIJ8pPY +FQEzDwjVAWjaErWgfd/j+ip2adD90Gf6lkC+uBDA84sQvdboChLbTGlH4FE0PBe+ +ILAu3rlvbULJUqDYnk4z6m7rn+T2SxWd/0VgFWFqcxol5A6zpcSVZm1EyakAh7hc +zfIyqHCXDHg7fec= +-----END CERTIFICATE----- diff --git a/tests/src/test/resources/mtls/server.csr b/tests/src/test/resources/mtls/server.csr new file mode 100644 index 000000000..83800fd4c --- /dev/null +++ b/tests/src/test/resources/mtls/server.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAt1XFuvFXVKMLEWMcHPMh+nIyDGABbUw0FY4rvXqj +D1FtI2o/7V8Fapf4BwS5LkXdAwg4F2luakqH8pMjrVPIYwHbjcnA3+EG+27/D2p/ +dY/cfFIATkZNHwaoZtaQ9mw6lV3Sr2RezY+tKH3lN5lr+sYPRSC1Ct3ORQ920FYU +xC21IiQuGsuIwzCLsPuQ/Nn+tLPEVJnzpUk7U9S2awnyXTRp5O0DT3n2W8DI5djM +J6GP/NCIFV73N4YNW5PaoItLNs2mL2aJohOJr6OhW30RBZLs7aq9I7TQUXqd04pb +Kts0ZfRNEoNRgb6/SnoGmvIPCD6WeaKq9GKjodcV/1gDzwIDAQABoAAwDQYJKoZI +hvcNAQELBQADggEBAI9SP5NUWWOXxEwZ4zz4wr62F2AAZsJuCwi9hYcWncF0i6qb +8RktS5FcF3BToMOiJzDPpteOllVbDCZOOW3X9XsnPmf4A/t2dm00SFhdkIPpzqSo +6yFzAEa0VwZ7dUx0bvw/3RKBXRi9QraZn1gHJk7grlRvqKeD93gdoorQ9XJPkmGj +zc+dCiEP6E08sg1JUc/7nVtxYtealc8nBVvs7N6zDXspJh8wYzTWpdIDVUicdD3f +l1h8ieIFuxpYJ91j4+ojVGIsNSqPMHQBPTLyVOIDEeErLPyOJzxbNnfwC0gUZeGz +C7vQhXstV8Wa9gyYV/0L7Wmjd2K0eY0w00dx8eA= +-----END CERTIFICATE REQUEST----- diff --git a/tests/src/test/resources/mtls/server.key b/tests/src/test/resources/mtls/server.key new file mode 100644 index 000000000..3be39ba07 --- /dev/null +++ b/tests/src/test/resources/mtls/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC3VcW68VdUowsR +Yxwc8yH6cjIMYAFtTDQVjiu9eqMPUW0jaj/tXwVql/gHBLkuRd0DCDgXaW5qSofy +kyOtU8hjAduNycDf4Qb7bv8Pan91j9x8UgBORk0fBqhm1pD2bDqVXdKvZF7Nj60o +feU3mWv6xg9FILUK3c5FD3bQVhTELbUiJC4ay4jDMIuw+5D82f60s8RUmfOlSTtT +1LZrCfJdNGnk7QNPefZbwMjl2MwnoY/80IgVXvc3hg1bk9qgi0s2zaYvZomiE4mv +o6FbfREFkuztqr0jtNBRep3Tilsq2zRl9E0Sg1GBvr9Kegaa8g8IPpZ5oqr0YqOh +1xX/WAPPAgMBAAECggEACeVZ1nTne1yPoOEiJ9fh2iRm2i8mdJFb8FvrtX8UpSOG +ihZWnAf4gV/xleNl4X8I5nx/lpfsy1T5kJjroJP4qYt0n+sne44oc9LydpEPjzd0 +NcuxU4hM6mNQHLjxOzPtV5moYSpAScU7Ggftovonj3I4aclRrGP7mdOzXJyA43Pi +nIdCsDw2j65ExI6wU5eQVC1TzEFXdEoZQsOPYIQO6XZbccJTpcIdhFYzkoOpYLe6 +G56JLjiNJSTDpPg8KEFpNq0Csjmh29tTbZEKfJdUpMDTnX9WXrB3w/el/R343Jn7 +fAmhw3M5ugw2IE3uQHWwj2EpPiKgPgepTQQav+Hg3QKBgQDyvdc30IhEXweSqKDA +3uFx9wdHHpw+BJUBuuuYAwqU2fwPX19vR6VlSjjqDGbpLa8SBh0Tv0VnHMHx/F19 +DjyVOpORzJ7DBnEKJn83USvATdP3hpjkSA0DO8eCKHI+r2HHwyuI43ZNqrDxLzM1 +mfFwW6Ppc6EaBF+Py+FSpIi+1QKBgQDBWUYbj0W0ySAAwJsC5hMvzbpirqdcIsfe +fx/kCU8xHRcSQRwmImgIHdFB+iyaQXmUHodlqc/wTZMX4aCXgJvSF//xDbBJVzKr +eHa6d5sTtLVqZbv+IBc20X/gBLAe5rv1xVTP1Dr94tqzeWLtV/4MobJnT+cf7Kdm +bjEfFNtyEwKBgGtCxbntFHmZwD/m8XmoQthX/shHV2T0I1+rV/VIysExfXbRftsu +PoB+hp2tM0AwJp8BQpH6P9GrXGvwRuM+ijiqtJCFaVXmH8cLccVgwcNs4JAM0rx0 +tgNKxALYmnrmhn9911vanuj81skMQUWbK5upcslyhap4aj2hKoSZHa+tAoGAAQSQ +SurZKhd49KgO6Nf/N9w0Y/qZZPHF7ZTrvQ6TfSWzDmSLWmQJ+ij2BgvkGjfIBRCY +E9/t+UzfPlvwtXt21odL0KAK0ogD+0UaEuc4SMVFwzaf47mVhbNaofpEVxVN3gBY +7vMmEFoWXqV/8NHqw3RCdSrFg7SCORbRaWF5ukMCgYBaNpCKI7nhwlGfetL8Nx7/ +BqhAO9TBGNwnMv1SmTEtPcUyi2GFGduIttZtuxYr5UHM/K2fNk64YeAVU59+elvj +/5k0tr9X+UwkCn3f1zJ8qon3+4Hl+FXRIz++Oo4B6Td+U3cwOxJGm1zvj0A59KJQ +r1vqYIL4qChsjV72sXkHfQ== +-----END PRIVATE KEY----- diff --git a/tests/src/test/resources/mtls/server.p12 b/tests/src/test/resources/mtls/server.p12 new file mode 100644 index 0000000000000000000000000000000000000000..21560276b3bb9f269647699199ffcc7a56da8edc GIT binary patch literal 2531 zcmai$X*3jy8^+BT%h>mQnIW!0{bvGzd;JhB-0;hA#81fuKLg@Zy?1QK zCN1JL8xBt@k5I1y0@<11T&(Q>y9xxeFu|o+!PsO=fFCmmpaSBv!CMBwHSmv;fsDpw zhv&KRL}n~B%=}5f+yD`}YtPJb2Gnrq7LyX z<8kd>)t(}zooaNQxzhFBU>mv48~k{mgXZ_@O1@&BV2H(^5{kmh=hDc;9y zR<-+&b%)Gr)@ze`hGNoku?dHH zz9jgdW4vgbVUT9^-nHBe~wFj5fZ95r^?S5M4_ zM_dBOZi8HitRDJ(AwO>Ld@hIt{L1kcKBU3dqKVY+RIEnNP&lJD9L^1&q(3=!Z$77( zy=pL7A}tTPa{oX;SZ$y@fP-TtYpONF^*!P>_vTjHuZgs0_6MY@XXih!H5-K{%XG~r zK2*CMx>m37lmx|zZJ+hpZl7@^_x<8*V}Xt*EVtlnHkWQ-S({U`2~NwUKC%rO1($oi z%TvUghBBr2tTms~!ZHaY(UeR$X=jYCIQ{iuT;^)d#k{FV8>d3aEwEdED!IUR<0RrBW1JHb@;$zyglNFnN$+ z?^s9t{!Y&ad7rx-Nl5cAP}#F3(JuvB1V$sFyhN-<(^2W;w-w!)sjGF8igFBE3MG_+ zNq`*aV^YyGd2a!c+bkKZ1eMX+f^@fLO;#87xpfv1i00k_(pJDDYV-h zmE2`TN>NxKL4(&v0@wKfS6+)guv}^9{i|MQn1MBPiCphhI(+D{)KzQ4Pj)Uf+qbs7 zTEF_IsO>|C-ooECe#>s1zc!qb#eF5$ySHn6bTzO1vineyAsJ3&$@tORe?h=<3q)jz zKDF_u6UNHjz5{L+*5B71caQVtrHje~DMq=jsp=(o`UCx-fJ2$6fN5Gti0nw4SOz>&G_fHmI zx>8GKqPpYPAnsnVwfF`;OO8NL<}h8nC>6g4OF4 zZEQDqmuY@CvC=nDKoIaMY|-CI#4R535yjed*n9DB?|TRC64aABnNk}@D_Jko?&heb zGIq0W+4BQ7;zK8!%|Td)KwO?5xIw7urSh8Av@D%eU^M+yz3Y$aX-Jfmw>Lg9>{5q$&i@d2|=q$OZrU*f=imlL|?EGyW!g0-{{PD#K!vM z%0o<%g528;74p4_^=NS(&`Y14#nnd!8b0D3{pkX8A4rXBhQ3!&bw7Zd0Yo?v>n#F zO(aoX6H*bslJ*GgL){IiDS?fJ^VofTBgLHAdNtC(Pz;yB#=uR+C`2ED#J-2iv) z*rzn@(HN1Rj&iExwD<6-dN<|xV3%}Kd6>Ar(KMqFgO4z5-=bFr;&#w0WHZN-b6z!~ z^leuNtQ}zd?U>$?mQT~wL)LE=;GE?PrDgnhoFJU>$xkf$hHq3;&>Nps3%)@3?~4%u z9OM?a6W9Z?9ySse@wSd)%~gnY^`wel+B!Ij={j2Q*Dvj_xa@0`1=D+R%sL`RdbgzpY9Id@RUHf5~g#@woOvZJzdqXoBA8j?I{Kl$E26X05ZDtu%7c28o^A}xZ)8^T zkL#3ay0e?qrvS0uuNz^Dh-Sdk?H!ed-exqVRbq(7d28odcYV?`O`|7%MoLSz8FCe^&ur_mMqcnG52sFGxNZ&Z4FvJ^Ar#>9KR^o>Mu>of z__S&Y4&|s{a5pxy)qV^xj-;X2! literal 0 HcmV?d00001 From c0b1442b0eef4c6572e3134ce2d70f480c6087b1 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Wed, 21 Aug 2024 11:04:25 +0800 Subject: [PATCH 05/23] add xxx --- .../MQTTBrokerProtocolMethodProcessor.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java index df7e5b4b7..4e13e58b9 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java @@ -25,6 +25,7 @@ import io.netty.handler.codec.mqtt.MqttSubscribeMessage; import io.netty.handler.codec.mqtt.MqttTopicSubscription; import io.netty.handler.codec.mqtt.MqttUnsubscribeMessage; +import io.netty.handler.ssl.SslHandler; import io.streamnative.pulsar.handlers.mqtt.Connection; import io.streamnative.pulsar.handlers.mqtt.MQTTConnectionManager; import io.streamnative.pulsar.handlers.mqtt.MQTTServerConfiguration; @@ -86,6 +87,9 @@ import org.apache.pulsar.common.util.Codec; import org.apache.pulsar.common.util.FutureUtil; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; + /** * Default implementation of protocol method processor. */ @@ -182,6 +186,21 @@ public void processPublish(MqttAdapterMessage adapter) { if (log.isDebugEnabled()) { log.debug("[Publish] [{}] msg: {}", connection.getClientId(), adapter); } + try { + SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); + if (sslHandler != null) { + SSLSession session = sslHandler.engine().getSession(); + java.security.cert.Certificate[] clientCerts = session.getPeerCertificates(); + if (clientCerts.length > 0) { + if (clientCerts[0] instanceof java.security.cert.X509Certificate) { + java.security.cert.X509Certificate clientCert = (java.security.cert.X509Certificate) clientCerts[0]; + log.info("Client cert info: " + clientCert.getSubjectDN()); + } + } + } + } catch (SSLPeerUnverifiedException ex) { + log.warn("get client clientCerts error", ex); + } MqttPublishMessage msg = (MqttPublishMessage) adapter.getMqttMessage(); CompletableFuture result; if (!configuration.isMqttAuthorizationEnabled()) { From 551896221efa0b8cf784571e6110d3eb66a571ea Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Wed, 21 Aug 2024 11:04:59 +0800 Subject: [PATCH 06/23] add xxx --- .../mqtt3/fusesource/proxy/ProxyMtlsTest.java | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java index b9babbd40..e4ba373e0 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java @@ -21,6 +21,7 @@ import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.util.Random; +import java.util.concurrent.CountDownLatch; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; @@ -36,26 +37,36 @@ public class ProxyMtlsTest extends MQTTTestBase { String path = "./src/test/resources/mtls/"; - private final Random random = new Random(); - @Override protected MQTTCommonConfiguration initConfig() throws Exception { + System.setProperty("javax.net.debug","ssl"); enableTls = true; MQTTCommonConfiguration mqtt = super.initConfig(); - mqtt.setMqttProxyEnabled(true); - mqtt.setMqttProxyTlsEnabled(true); +// mqtt.setMqttProxyEnabled(true); +// mqtt.setMqttProxyTlsEnabled(true); mqtt.setMqttTlsCertificateFilePath(path + "server.crt"); + mqtt.setMqttTlsTrustCertsFilePath(path + "client.crt"); mqtt.setMqttTlsKeyFilePath(path + "server.key"); return mqtt; } public SSLContext createSSLContext() throws Exception { - KeyStore keyStore = KeyStore.getInstance("PKCS12"); - try (FileInputStream fis = new FileInputStream(path + "client.p12")) { - keyStore.load(fis, "".toCharArray()); - } +// KeyStore keyStore = KeyStore.getInstance("PKCS12"); +// try (FileInputStream fis = new FileInputStream(path + "client.p12")) { +// keyStore.load(fis, "".toCharArray()); +// +// } + + + + File clientCrt = new File(path + "client.crt"); + Certificate clientCert = CertificateFactory + .getInstance("X.509").generateCertificate(new FileInputStream(clientCrt)); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, null); + keyStore.setCertificateEntry("client", clientCert); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, "".toCharArray()); @@ -79,7 +90,7 @@ public SSLContext createSSLContext() throws Exception { @Test public void testProduceAndConsume() throws Exception { SSLContext sslContext = createSSLContext(); - MQTT mqtt = createMQTTProxyTlsClient(); + MQTT mqtt = createMQTTTlsClient(); mqtt.setSslContext(sslContext); String topicName = "testProduceAndConsume"; @@ -94,5 +105,8 @@ public void testProduceAndConsume() throws Exception { Assert.assertEquals(new String(received.getPayload()), message); received.ack(); connection.disconnect(); + + CountDownLatch latch = new CountDownLatch(1); + latch.await(); } } From 4f412880217e071862ad76fc3af3f66688e59995 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Wed, 21 Aug 2024 11:30:27 +0800 Subject: [PATCH 07/23] add xxx --- .../mqtt3/fusesource/proxy/ProxyMtlsTest.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java index e4ba373e0..6ae7d64be 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java @@ -18,6 +18,7 @@ import java.io.File; import java.io.FileInputStream; import java.security.KeyStore; +import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.util.Random; @@ -25,6 +26,8 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; + +import org.apache.pulsar.common.util.SecurityUtility; import org.fusesource.mqtt.client.BlockingConnection; import org.fusesource.mqtt.client.MQTT; import org.fusesource.mqtt.client.Message; @@ -46,7 +49,7 @@ protected MQTTCommonConfiguration initConfig() throws Exception { // mqtt.setMqttProxyEnabled(true); // mqtt.setMqttProxyTlsEnabled(true); mqtt.setMqttTlsCertificateFilePath(path + "server.crt"); - mqtt.setMqttTlsTrustCertsFilePath(path + "client.crt"); + mqtt.setMqttTlsTrustCertsFilePath(path + "client_combined.pem"); mqtt.setMqttTlsKeyFilePath(path + "server.key"); return mqtt; @@ -87,9 +90,28 @@ public SSLContext createSSLContext() throws Exception { return sslContext; } + public SSLContext createSSLContext2() throws Exception { + File clientCrt1 = new File(path + "ca.cer"); + Certificate clientCert1 = CertificateFactory + .getInstance("X.509").generateCertificate(new FileInputStream(clientCrt1)); + + + File key = new File(path + "client.crt"); + Certificate clientKey1 = CertificateFactory + .getInstance("X.509").generateCertificate(new FileInputStream(key)); + + PrivateKey privateKey = SecurityUtility.loadPrivateKeyFromPemFile(path + "client.crt.pem"); + + + final SSLContext sslContext = SecurityUtility.createSslContext(true, new Certificate[]{clientCert1}, new Certificate[]{clientKey1}, privateKey); + + return sslContext; + } + + @Test public void testProduceAndConsume() throws Exception { - SSLContext sslContext = createSSLContext(); + SSLContext sslContext = createSSLContext2(); MQTT mqtt = createMQTTTlsClient(); mqtt.setSslContext(sslContext); From 6f1d589d87ab91fa95c07cd6d6b1cbbb752c3633 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Wed, 21 Aug 2024 13:27:27 +0800 Subject: [PATCH 08/23] update --- .../mqtt3/fusesource/proxy/ProxyMtlsTest.java | 60 +++---------------- 1 file changed, 7 insertions(+), 53 deletions(-) diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java index 6ae7d64be..cb5312d39 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java @@ -17,16 +17,10 @@ import io.streamnative.pulsar.handlers.mqtt.base.MQTTTestBase; import java.io.File; import java.io.FileInputStream; -import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; - import org.apache.pulsar.common.util.SecurityUtility; import org.fusesource.mqtt.client.BlockingConnection; import org.fusesource.mqtt.client.MQTT; @@ -42,68 +36,30 @@ public class ProxyMtlsTest extends MQTTTestBase { @Override protected MQTTCommonConfiguration initConfig() throws Exception { - System.setProperty("javax.net.debug","ssl"); enableTls = true; MQTTCommonConfiguration mqtt = super.initConfig(); -// mqtt.setMqttProxyEnabled(true); -// mqtt.setMqttProxyTlsEnabled(true); + mqtt.setMqttProxyEnabled(true); + mqtt.setMqttProxyTlsEnabled(true); mqtt.setMqttTlsCertificateFilePath(path + "server.crt"); - mqtt.setMqttTlsTrustCertsFilePath(path + "client_combined.pem"); mqtt.setMqttTlsKeyFilePath(path + "server.key"); return mqtt; } public SSLContext createSSLContext() throws Exception { -// KeyStore keyStore = KeyStore.getInstance("PKCS12"); -// try (FileInputStream fis = new FileInputStream(path + "client.p12")) { -// keyStore.load(fis, "".toCharArray()); -// -// } - - - - File clientCrt = new File(path + "client.crt"); - Certificate clientCert = CertificateFactory - .getInstance("X.509").generateCertificate(new FileInputStream(clientCrt)); - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(null, null); - keyStore.setCertificateEntry("client", clientCert); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(keyStore, "".toCharArray()); - - File crtFile = new File(path + "server.crt"); - Certificate certificate = CertificateFactory - .getInstance("X.509").generateCertificate(new FileInputStream(crtFile)); - KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - trustStore.load(null, null); - trustStore.setCertificateEntry("server", certificate); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - tmf.init(trustStore); - - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new java.security.SecureRandom()); - - return sslContext; - } - - public SSLContext createSSLContext2() throws Exception { File clientCrt1 = new File(path + "ca.cer"); Certificate clientCert1 = CertificateFactory .getInstance("X.509").generateCertificate(new FileInputStream(clientCrt1)); - File key = new File(path + "client.crt"); Certificate clientKey1 = CertificateFactory .getInstance("X.509").generateCertificate(new FileInputStream(key)); - PrivateKey privateKey = SecurityUtility.loadPrivateKeyFromPemFile(path + "client.crt.pem"); - + PrivateKey privateKey = SecurityUtility.loadPrivateKeyFromPemFile(path + "client.key"); - final SSLContext sslContext = SecurityUtility.createSslContext(true, new Certificate[]{clientCert1}, new Certificate[]{clientKey1}, privateKey); + final SSLContext sslContext = SecurityUtility.createSslContext(true, + new Certificate[]{clientCert1}, new Certificate[]{clientKey1}, privateKey); return sslContext; } @@ -111,8 +67,8 @@ public SSLContext createSSLContext2() throws Exception { @Test public void testProduceAndConsume() throws Exception { - SSLContext sslContext = createSSLContext2(); - MQTT mqtt = createMQTTTlsClient(); + SSLContext sslContext = createSSLContext(); + MQTT mqtt = createMQTTProxyTlsClient(); mqtt.setSslContext(sslContext); String topicName = "testProduceAndConsume"; @@ -128,7 +84,5 @@ public void testProduceAndConsume() throws Exception { received.ack(); connection.disconnect(); - CountDownLatch latch = new CountDownLatch(1); - latch.await(); } } From 953a15b0c78bba4ddf9cad1ba922b2803de224b2 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Fri, 23 Aug 2024 22:11:38 +0800 Subject: [PATCH 09/23] update --- .../pulsar/handlers/mqtt/Connection.java | 4 +- .../pulsar/handlers/mqtt/Constants.java | 2 + .../mqtt/MQTTAuthenticationService.java | 42 ++++ .../mqtt/MQTTCommonConfiguration.java | 14 ++ .../pulsar/handlers/mqtt/MQTTService.java | 14 ++ .../mqtt/exception/MQTTAuthException.java | 35 +++ .../mqtt/oidc/ExpressionCompiler.java | 98 ++++++++ .../handlers/mqtt/oidc/OIDCPoolResources.java | 87 +++++++ .../handlers/mqtt/oidc/OIDCService.java | 179 ++++++++++++++ .../pulsar/handlers/mqtt/oidc/Pool.java | 32 +++ .../handlers/mqtt/oidc/PoolCompiler.java | 32 +++ .../mqtt/proxy/MQTTProxyConfiguration.java | 2 +- .../MQTTProxyProtocolMethodProcessor.java | 38 ++- .../handlers/mqtt/proxy/MQTTProxyService.java | 14 +- ...AbstractCommonProtocolMethodProcessor.java | 25 +- .../MQTTBrokerProtocolMethodProcessor.java | 36 +-- .../handlers/mqtt/utils/MqttMessageUtils.java | 20 ++ .../pulsar/handlers/mqtt/utils/Paths.java | 23 ++ pom.xml | 6 + .../mqtt3/fusesource/proxy/ProxyMtlsTest.java | 88 ------- .../mqtt5/hivemq/base/MQTT5ClientUtils.java | 8 + .../mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java | 225 ++++++++++++++++++ tests/src/test/resources/mtls/ca.cer | 18 -- tests/src/test/resources/mtls/ca.csr | 15 -- tests/src/test/resources/mtls/ca.key | 28 --- tests/src/test/resources/mtls/ca.p12 | Bin 2483 -> 0 bytes tests/src/test/resources/mtls/ca.srl | 1 - tests/src/test/resources/mtls/client.cer | 18 -- tests/src/test/resources/mtls/client.csr | 15 -- tests/src/test/resources/mtls/client.key | 28 --- tests/src/test/resources/mtls/client.p12 | Bin 2531 -> 0 bytes tests/src/test/resources/mtls/server.cer | 18 -- tests/src/test/resources/mtls/server.crt | 18 -- tests/src/test/resources/mtls/server.csr | 15 -- tests/src/test/resources/mtls/server.key | 28 --- tests/src/test/resources/mtls/server.p12 | Bin 2531 -> 0 bytes 36 files changed, 907 insertions(+), 319 deletions(-) create mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/exception/MQTTAuthException.java create mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java create mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java create mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java create mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java create mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java create mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java delete mode 100644 tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java create mode 100644 tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java delete mode 100644 tests/src/test/resources/mtls/ca.cer delete mode 100644 tests/src/test/resources/mtls/ca.csr delete mode 100644 tests/src/test/resources/mtls/ca.key delete mode 100644 tests/src/test/resources/mtls/ca.p12 delete mode 100644 tests/src/test/resources/mtls/ca.srl delete mode 100644 tests/src/test/resources/mtls/client.cer delete mode 100644 tests/src/test/resources/mtls/client.csr delete mode 100644 tests/src/test/resources/mtls/client.key delete mode 100644 tests/src/test/resources/mtls/client.p12 delete mode 100644 tests/src/test/resources/mtls/server.cer delete mode 100644 tests/src/test/resources/mtls/server.crt delete mode 100644 tests/src/test/resources/mtls/server.csr delete mode 100644 tests/src/test/resources/mtls/server.key delete mode 100644 tests/src/test/resources/mtls/server.p12 diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Connection.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Connection.java index a2eda7925..4c30d1062 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Connection.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Connection.java @@ -44,6 +44,7 @@ import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.pulsar.broker.authentication.AuthenticationDataSource; @@ -69,7 +70,8 @@ public class Connection { @Getter private final TopicSubscriptionManager topicSubscriptionManager; @Getter - private final MqttConnectMessage connectMessage; + @Setter + private MqttConnectMessage connectMessage; @Getter private final ClientRestrictions clientRestrictions; @Getter diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Constants.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Constants.java index a0c663936..714ffe9bd 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Constants.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Constants.java @@ -45,6 +45,8 @@ public final class Constants { public static final String MQTT_SUB_PROTOCOL_CSV_LIST = "mqtt, mqttv3.1, mqttv3.1.1, mqttv5.0"; + public static final String MTLS = "mTls"; + private Constants() { } } diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java index c474d2103..3fe4cf141 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java @@ -15,13 +15,19 @@ import static io.streamnative.pulsar.handlers.mqtt.Constants.AUTH_BASIC; import static io.streamnative.pulsar.handlers.mqtt.Constants.AUTH_TOKEN; +import static io.streamnative.pulsar.handlers.mqtt.Constants.MTLS; import io.netty.handler.codec.mqtt.MqttConnectMessage; import io.netty.handler.codec.mqtt.MqttConnectPayload; +import io.netty.handler.ssl.SslHandler; +import io.streamnative.pulsar.handlers.mqtt.exception.MQTTAuthException; +import io.streamnative.pulsar.handlers.mqtt.oidc.OIDCService; import io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.naming.AuthenticationException; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -64,6 +70,39 @@ private Map getAuthenticationProviders(List 0) { + if (clientCerts[0] instanceof java.security.cert.X509Certificate) { + java.security.cert.X509Certificate clientCert = + (java.security.cert.X509Certificate) clientCerts[0]; + log.info("[proxy]-Client cert info: " + clientCert.getSubjectDN()); + String[] parts = clientCert.getSubjectDN().toString().split("="); + Map datas = new HashMap<>(); + datas.put(parts[0], parts[1]); + final String principal = oidcService.getPrincipal(datas); + log.info("[proxy]-mTls principal : {}", principal); + return new AuthenticationResult(true, principal, + new AuthenticationDataCommand(clientCert.getSubjectDN().toString())); + } + } + } else { + String msg = "mTlsEnabled, but not find SslHandler, disconnect the connection"; + log.error("mTlsEnabled, but not find SslHandler, disconnect the connection"); + throw new MQTTAuthException(msg); + } + } catch (SSLPeerUnverifiedException ex) { + log.warn("[proxy]- get client clientCerts error", ex); + throw new MQTTAuthException(ex); + } + String msg = "mTlsEnabled, but not find matched principal"; + throw new MQTTAuthException(msg); + } + public AuthenticationResult authenticate(MqttConnectMessage connectMessage) { String authMethod = MqttMessageUtils.getAuthMethod(connectMessage); if (authMethod != null) { @@ -100,6 +139,9 @@ public AuthenticationResult authenticate(MqttConnectPayload payload) { public AuthenticationResult authenticate(String clientIdentifier, String authMethod, AuthenticationDataCommand command) { + if (MTLS.equalsIgnoreCase(authMethod)) { + return new AuthenticationResult(true, command.getCommandData(), command); + } AuthenticationProvider authenticationProvider = authenticationProviders.get(authMethod); if (authenticationProvider == null) { log.warn("Authentication failed, no authMethod : {} for CId={}", clientIdentifier, authMethod); diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java index 676dc5a0e..e4a72f5a4 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java @@ -145,6 +145,13 @@ public class MQTTCommonConfiguration extends ServiceConfiguration { ) private boolean mqttProxyTlsEnabled = false; + @FieldContext( + category = CATEGORY_MQTT_PROXY, + required = false, + doc = "Whether start mqtt protocol handler with proxy mtls" + ) + private boolean mqttProxyMtlsEnabled = false; + @FieldContext( category = CATEGORY_MQTT_PROXY, required = false, @@ -173,6 +180,13 @@ public class MQTTCommonConfiguration extends ServiceConfiguration { ) private boolean mqttTlsPskEnabled = false; + @FieldContext( + category = CATEGORY_TLS, + required = false, + doc = "Whether start mqtt protocol handler with mtls" + ) + private boolean mqttMtlsEnabled = false; + @Deprecated @FieldContext( category = CATEGORY_TLS, diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java index 26db52fa4..8e4c34d4f 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java @@ -13,6 +13,9 @@ */ package io.streamnative.pulsar.handlers.mqtt; +import io.streamnative.pulsar.handlers.mqtt.exception.MQTTServerException; +import io.streamnative.pulsar.handlers.mqtt.oidc.OIDCService; +import io.streamnative.pulsar.handlers.mqtt.proxy.MQTTProxyException; import io.streamnative.pulsar.handlers.mqtt.support.MQTTMetricsCollector; import io.streamnative.pulsar.handlers.mqtt.support.MQTTMetricsProvider; import io.streamnative.pulsar.handlers.mqtt.support.QosPublishHandlersImpl; @@ -29,6 +32,7 @@ import org.apache.pulsar.broker.PulsarService; import org.apache.pulsar.broker.authorization.AuthorizationService; import org.apache.pulsar.broker.service.BrokerService; +import org.apache.pulsar.metadata.api.MetadataStoreException; /** * Main class for mqtt service. @@ -85,6 +89,9 @@ public class MQTTService { @Setter private SystemEventService eventService; + @Getter + private OIDCService oidcService; + public MQTTService(BrokerService brokerService, MQTTServerConfiguration serverConfiguration) { this.brokerService = brokerService; this.pulsarService = brokerService.pulsar(); @@ -109,6 +116,13 @@ public MQTTService(BrokerService brokerService, MQTTServerConfiguration serverCo this.retainedMessageHandler = new RetainedMessageHandler(this); this.qosPublishHandlers = new QosPublishHandlersImpl(this); this.willMessageHandler = new WillMessageHandler(this); + if (serverConfiguration.isMqttMtlsEnabled()) { + try { + this.oidcService = new OIDCService(pulsarService); + } catch (MetadataStoreException ex) { + throw new MQTTServerException(ex); + } + } } public boolean isSystemTopicEnabled() { diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/exception/MQTTAuthException.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/exception/MQTTAuthException.java new file mode 100644 index 000000000..267536539 --- /dev/null +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/exception/MQTTAuthException.java @@ -0,0 +1,35 @@ +/** + * 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. + */ +package io.streamnative.pulsar.handlers.mqtt.exception; + +/** + * Internal server exception. + */ +public class MQTTAuthException extends Exception { + + public MQTTAuthException() { + } + + public MQTTAuthException(String message) { + super(message); + } + + public MQTTAuthException(String message, Throwable cause) { + super(message, cause); + } + + public MQTTAuthException(Throwable cause) { + super(cause); + } +} diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java new file mode 100644 index 000000000..1eb2a5b44 --- /dev/null +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2020 StreamNative, Inc.. All Rights Reserved. + */ +package io.streamnative.pulsar.handlers.mqtt.oidc; + +import com.google.common.annotations.VisibleForTesting; +import dev.cel.common.CelAbstractSyntaxTree; +import dev.cel.common.CelValidationException; +import dev.cel.common.CelVarDecl; +import dev.cel.common.types.MapType; +import dev.cel.common.types.SimpleType; +import dev.cel.compiler.CelCompiler; +import dev.cel.compiler.CelCompilerFactory; +import dev.cel.parser.CelStandardMacro; +import dev.cel.runtime.CelEvaluationException; +import dev.cel.runtime.CelRuntime; +import dev.cel.runtime.CelRuntimeFactory; +import lombok.Getter; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ExpressionCompiler { + + @Getter + private CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() + .setStandardMacros(CelStandardMacro.STANDARD_MACROS) + .addVarDeclarations(CelVarDecl.newVarDeclaration("claims", + MapType.create(SimpleType.STRING, SimpleType.STRING))) + .build(); + + final CelRuntime runtime = CelRuntimeFactory.standardCelRuntimeBuilder().build(); + + static final String REGEX = "claims[\\w.]*"; + + static final Pattern PATTERN = Pattern.compile(REGEX); + + @Getter + private String expression; + + @Getter + private List variables; + + private CelAbstractSyntaxTree ast; + + private CelRuntime.Program program; + + public ExpressionCompiler(String expression) { + this.expression = expression; + this.variables = parse(expression); + try { + this.compile(); + } catch (CelValidationException | CelEvaluationException ex) { + throw new IllegalArgumentException(ex); + } + } + + @VisibleForTesting + ExpressionCompiler() { + } + + @VisibleForTesting + List parse(String expression) { + if (StringUtils.isEmpty(expression)) { + throw new IllegalArgumentException("Expression should not be empty"); + } + Matcher matcher = PATTERN.matcher(expression); + List matches = new ArrayList<>(); + while (matcher.find()) { + String find = matcher.group(0); + String[] parts = find.split("\\."); + matches.add(parts[1]); + } + if (CollectionUtils.isEmpty(matches)) { + throw new IllegalArgumentException("Not valid expression, " + + "expression definitions must be prefixed with claims."); + } + return matches; + } + + private void compile() throws CelValidationException, CelEvaluationException { + this.ast = compiler.compile(expression).getAst(); + this.program = runtime.createProgram(ast); + } + + public Boolean eval(Map mapValue) throws Exception { + final Object eval = program.eval(mapValue); + if (eval instanceof Boolean) { + return (Boolean) eval; + } + return false; + } +} diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java new file mode 100644 index 000000000..1b95d55c2 --- /dev/null +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2020 StreamNative, Inc.. All Rights Reserved. + */ +package io.streamnative.pulsar.handlers.mqtt.oidc; + +import com.fasterxml.jackson.core.type.TypeReference; +import io.streamnative.pulsar.handlers.mqtt.utils.Paths; +import org.apache.pulsar.broker.resources.BaseResources; +import org.apache.pulsar.common.util.FutureUtil; +import org.apache.pulsar.metadata.api.MetadataStore; +import org.apache.pulsar.metadata.api.MetadataStoreException; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +@SuppressWarnings("UnstableApiUsage") +public final class OIDCPoolResources extends BaseResources { + + public static final int RESOURCE_SYNC_OPERATION_TIMEOUT_SEC = 30; + private static final String BASE_PATH = "/sn-oidc/pools"; + + public OIDCPoolResources(@NotNull MetadataStore metadataStore) { + super(metadataStore, new TypeReference<>() { }, RESOURCE_SYNC_OPERATION_TIMEOUT_SEC); + } + + public @NotNull Optional getPool(@NotNull String poolName) throws MetadataStoreException { + return get(joinPath(BASE_PATH, Paths.getUrlEncodedPath(poolName))); + } + + public @NotNull CompletableFuture> getPoolAsync(@NotNull String poolName) { + return getAsync(joinPath(BASE_PATH, Paths.getUrlEncodedPath(poolName))); + } + + public void createPool(@NotNull Pool pool) throws MetadataStoreException { + create(joinPath(BASE_PATH, Paths.getUrlEncodedPath(pool.name())), pool); + } + + public @NotNull CompletableFuture createPoolAsync(@NotNull Pool pool) { + return createAsync(joinPath(BASE_PATH, Paths.getUrlEncodedPath(pool.name())), pool); + } + + public @NotNull CompletableFuture existsAsync(@NotNull String poolName) { + return super.existsAsync(joinPath(BASE_PATH, Paths.getUrlEncodedPath(poolName))); + } + + public void deletePool(@NotNull String poolName) throws MetadataStoreException { + super.delete(joinPath(BASE_PATH, Paths.getUrlEncodedPath(poolName))); + } + + public @NotNull CompletableFuture deletePoolAsync(@NotNull String poolName) { + return super.deleteIfExistsAsync(joinPath(BASE_PATH, Paths.getUrlEncodedPath(poolName))); + } + + public @NotNull CompletableFuture updatePoolAsync(@NotNull Pool pool) { + return super.setAsync(joinPath(BASE_PATH, Paths.getUrlEncodedPath(pool.name())), __ -> pool); + } + + public @NotNull CompletableFuture> listPoolNamesAsync() { + return super.getChildrenAsync(joinPath(BASE_PATH)); + } + + public @NotNull CompletableFuture> listPoolsAsync() { + return super.getChildrenAsync(joinPath(BASE_PATH)) + .thenCompose(poolNames -> { + List>> pools = new ArrayList<>(); + for (String name : poolNames) { + pools.add(getAsync(joinPath(BASE_PATH, name))); + } + return FutureUtil.waitForAll(pools) + .thenApply(__ -> pools.stream().map(f -> f.join()) + .filter(f -> f.isPresent()) + .map(f -> f.get()) + .collect(Collectors.toList())); + }); + } + + public static boolean pathIsFromPool(String path) { + return path.startsWith(BASE_PATH + "/"); + } + + public static String poolFromPath(String path) { + return path.substring(BASE_PATH.length() + 1); + } +} diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java new file mode 100644 index 000000000..469f9406d --- /dev/null +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java @@ -0,0 +1,179 @@ +package io.streamnative.pulsar.handlers.mqtt.oidc; + +import com.beust.jcommander.internal.Lists; +import com.google.common.base.Joiner; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.pulsar.broker.PulsarService; +import org.apache.pulsar.broker.ServiceConfiguration; +import org.apache.pulsar.metadata.api.MetadataStore; +import org.apache.pulsar.metadata.api.MetadataStoreConfig; +import org.apache.pulsar.metadata.api.MetadataStoreException; +import org.apache.pulsar.metadata.api.Notification; +import org.apache.pulsar.metadata.api.NotificationType; +import org.apache.pulsar.metadata.api.extended.MetadataStoreExtended; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +@Slf4j +public class OIDCService { + + static final char PRINCIPAL_JOINER = (char) 27; + + private final PulsarService pulsarService; + + private final MetadataStore metadataStore; + + private final OIDCPoolResources poolResources; + + private final ConcurrentHashMap> poolsMap = new ConcurrentHashMap<>(); + + private final List pools = new ArrayList<>(); + + public OIDCService(PulsarService pulsarService) throws MetadataStoreException { + this.pulsarService = pulsarService; +// this.metadataStore = createLocalMetadataStore(pulsarService.getConfig()); + this.metadataStore = pulsarService.getConfigurationMetadataStore(); + this.metadataStore.registerListener(this::handleMetadataChanges); + this.poolResources = new OIDCPoolResources(this.metadataStore); + this.createData(); + } + + public MetadataStoreExtended createLocalMetadataStore(ServiceConfiguration config) throws MetadataStoreException { + return MetadataStoreExtended.create(config.getMetadataStoreUrl(), + MetadataStoreConfig.builder() + .sessionTimeoutMillis((int) config.getMetadataStoreSessionTimeoutMillis()) + .allowReadOnlyOperations(config.isMetadataStoreAllowReadOnlyOperations()) + .configFilePath(config.getMetadataStoreConfigPath()) + .batchingEnabled(config.isMetadataStoreBatchingEnabled()) + .batchingMaxDelayMillis(config.getMetadataStoreBatchingMaxDelayMillis()) + .batchingMaxOperations(config.getMetadataStoreBatchingMaxOperations()) + .batchingMaxSizeKb(config.getMetadataStoreBatchingMaxSizeKb()) + .metadataStoreName(MetadataStoreConfig.METADATA_STORE) + .build()); + } + + private CompletableFuture createData() { + Pool pool = new Pool("test-pool", "d", "provider-1", "claims.CN=='CLIENT'"); + return doLoadPools(CompletableFuture.completedFuture(Lists.newArrayList(pool))); + + } + + private CompletableFuture createDemoData() { + Pool pool = new Pool("test-pool", "d", "provider-1", "claims.CN=='CLIENT'"); + return poolResources.createPoolAsync(pool); + } + + private CompletableFuture loadPoolsAsync() { + return doLoadPools(poolResources.listPoolsAsync()); + } + + private CompletableFuture loadPoolAsync(String pool) { + final CompletableFuture> pools = poolResources.getPoolAsync(pool).thenCompose(opt -> { + if (opt.isEmpty()) { + return CompletableFuture.completedFuture(new ArrayList<>()); + } + return CompletableFuture.completedFuture(List.of(opt.get())); + }); + return doLoadPools(pools); + } + + private CompletableFuture doLoadPools(CompletableFuture> future) { + return future.thenApply(localPools -> { + localPools.stream().forEach(p -> { + final List poolCompilers = poolsMap.computeIfAbsent(p.providerName(), + k -> Collections.synchronizedList(new ArrayList<>())); + poolCompilers.removeIf(pc -> pc.getName().equalsIgnoreCase(p.name())); + PoolCompiler compiler = new PoolCompiler(p); + poolCompilers.add(compiler); + // + pools.removeIf(pc -> pc.getName().equalsIgnoreCase(p.name())); + pools.add(compiler); + }); + + List poolsNames = new ArrayList<>(); + for (List value : poolsMap.values()) { + Optional poolCompiler = value.stream().findFirst(); + poolCompiler.ifPresent(compiler -> poolsNames.add(compiler.getName())); + } + return poolsNames; + }).thenAccept(poolsNames -> log.info("refreshed OIDC pools, pools: {}, {}", poolsNames, pools)) + .exceptionally(ex -> { + log.error("load pool error", ex); + return null; + }); + } + + public String getPrincipal(Map datas) { + List principals = new ArrayList<>(); + for (PoolCompiler pool : pools) { + ExpressionCompiler compiler = pool.getCompiler(); + Map variables = new HashMap<>(); + Map claims = new HashMap<>(); + for (String var : compiler.getVariables()) { + Object jwtValue = datas.get(var); + if (jwtValue != null) { + variables.put(var, jwtValue); + } + } + claims.put("claims", variables); + Boolean matched = false; + try { + matched = compiler.eval(claims); + } catch (Exception e) { + log.warn("eval : {} value : {}", pool.getExpression(), claims, e); + } + if (matched) { + principals.add(pool.getName()); + } + } + return Joiner.on(PRINCIPAL_JOINER).join(principals); + } + + private void handleMetadataChanges(Notification n) { + if (OIDCPoolResources.pathIsFromPool(n.getPath())) { + log.info("pool-handleMetadataChanges : {}", n); + handlePoolAsync(n); + } + } + + private void handlePoolAsync(Notification n) { + String pool = OIDCPoolResources.poolFromPath(n.getPath()); + if (NotificationType.Created == n.getType() || NotificationType.Modified == n.getType()) { + loadPoolAsync(pool); + } else if (NotificationType.Deleted == n.getType()) { + deletePool(pool); + } + } + + private void deletePool(String pool) { + String providerName = ""; + for (List pools : poolsMap.values()) { + Iterator iterator = pools.iterator(); + while (iterator.hasNext()) { + final PoolCompiler item = iterator.next(); + if (item.getName().equalsIgnoreCase(pool)) { + iterator.remove(); + providerName = item.getProviderName(); + } + } + } + if (StringUtils.isNotEmpty(providerName)) { + final List poolCompilers = poolsMap.get(providerName); + if (CollectionUtils.isEmpty(poolCompilers)) { + poolsMap.remove(providerName); + } + } + } +} diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java new file mode 100644 index 000000000..8b6c520f2 --- /dev/null +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2020 StreamNative, Inc.. All Rights Reserved. + */ +package io.streamnative.pulsar.handlers.mqtt.oidc; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import javax.validation.constraints.NotNull; +import java.util.Objects; + +public record Pool(@JsonProperty(value = "name", required = true) String name, + @JsonProperty(value = "description", required = true) @NotNull String description, + @JsonProperty(value = "provider_name", required = true) @NotNull String providerName, + @JsonProperty(value = "expression", required = true) @NotNull String expression) { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pool pool = (Pool) o; + return Objects.equals(name, pool.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java new file mode 100644 index 000000000..2bf82900c --- /dev/null +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2020 StreamNative, Inc.. All Rights Reserved. + */ +package io.streamnative.pulsar.handlers.mqtt.oidc; + +import lombok.Getter; + +public class PoolCompiler { + + private final Pool pool; + + @Getter + private final ExpressionCompiler compiler; + + public PoolCompiler(Pool pool) { + this.pool = pool; + this.compiler = new ExpressionCompiler(pool.expression()); + } + + public String getExpression() { + return pool.expression(); + } + + public String getName() { + return pool.name(); + } + + public String getProviderName() { + return pool.providerName(); + } + +} diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyConfiguration.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyConfiguration.java index 251eac432..708ef5124 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyConfiguration.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyConfiguration.java @@ -60,7 +60,7 @@ public class MQTTProxyConfiguration extends MQTTCommonConfiguration { category = CATEGORY_MQTT_PROXY, doc = "Enable system event service." ) - private boolean systemEventEnabled = true; + private boolean systemEventEnabled = false; @FieldContext( category = CATEGORY_MQTT, diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java index a64df78fa..f40e24609 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java @@ -13,6 +13,8 @@ */ package io.streamnative.pulsar.handlers.mqtt.proxy; +import static io.streamnative.pulsar.handlers.mqtt.Constants.MTLS; +import static io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils.createMqttConnectMessage; import com.google.common.collect.Lists; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.mqtt.MqttConnectMessage; @@ -23,17 +25,21 @@ import io.netty.handler.codec.mqtt.MqttSubscribeMessage; import io.netty.handler.codec.mqtt.MqttTopicSubscription; import io.netty.handler.codec.mqtt.MqttUnsubscribeMessage; +import io.netty.handler.ssl.SslHandler; import io.streamnative.pulsar.handlers.mqtt.Connection; +import io.streamnative.pulsar.handlers.mqtt.MQTTAuthenticationService; import io.streamnative.pulsar.handlers.mqtt.MQTTConnectionManager; import io.streamnative.pulsar.handlers.mqtt.TopicFilter; import io.streamnative.pulsar.handlers.mqtt.adapter.AdapterChannel; import io.streamnative.pulsar.handlers.mqtt.adapter.MQTTProxyAdapter; import io.streamnative.pulsar.handlers.mqtt.adapter.MqttAdapterMessage; +import io.streamnative.pulsar.handlers.mqtt.exception.MQTTAuthException; import io.streamnative.pulsar.handlers.mqtt.messages.ack.MqttAck; import io.streamnative.pulsar.handlers.mqtt.messages.ack.MqttPubAck; import io.streamnative.pulsar.handlers.mqtt.messages.ack.MqttSubAck; import io.streamnative.pulsar.handlers.mqtt.messages.codes.mqtt5.Mqtt5PubReasonCode; import io.streamnative.pulsar.handlers.mqtt.messages.properties.PulsarProperties; +import io.streamnative.pulsar.handlers.mqtt.oidc.OIDCService; import io.streamnative.pulsar.handlers.mqtt.restrictions.ClientRestrictions; import io.streamnative.pulsar.handlers.mqtt.restrictions.ServerRestrictions; import io.streamnative.pulsar.handlers.mqtt.support.AbstractCommonProtocolMethodProcessor; @@ -64,17 +70,19 @@ import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.common.util.Codec; import org.apache.pulsar.common.util.FutureUtil; + /** * Proxy inbound handler is the bridge between proxy and MoP. */ @Slf4j public class MQTTProxyProtocolMethodProcessor extends AbstractCommonProtocolMethodProcessor { + private final PulsarService pulsarService; + @Getter private Connection connection; private final LookupHandler lookupHandler; private final MQTTProxyConfiguration proxyConfig; - private final PulsarService pulsarService; private final Map> topicBrokers; private final Map adapterChannels; @Getter @@ -86,6 +94,8 @@ public class MQTTProxyProtocolMethodProcessor extends AbstractCommonProtocolMeth private final MQTTConnectionManager connectionManager; private final SystemEventService eventService; private final MQTTProxyAdapter proxyAdapter; + + private final OIDCService oidcService; private final AtomicBoolean isDisconnected = new AtomicBoolean(false); private final AutoSubscribeHandler autoSubscribeHandler; @@ -95,8 +105,9 @@ public class MQTTProxyProtocolMethodProcessor extends AbstractCommonProtocolMeth public MQTTProxyProtocolMethodProcessor(MQTTProxyService proxyService, ChannelHandlerContext ctx) { super(proxyService.getAuthenticationService(), - proxyService.getProxyConfig().isMqttAuthenticationEnabled(), ctx); - this.pulsarService = proxyService.getPulsarService(); + proxyService.getProxyConfig().isMqttAuthenticationEnabled(), + ctx); + pulsarService = proxyService.getPulsarService(); this.lookupHandler = proxyService.getLookupHandler(); this.proxyConfig = proxyService.getProxyConfig(); this.connectionManager = proxyService.getConnectionManager(); @@ -107,6 +118,7 @@ public MQTTProxyProtocolMethodProcessor(MQTTProxyService proxyService, ChannelHa this.unsubscribeAckTracker = new MessageAckTracker(); this.packetIdTopic = new ConcurrentHashMap<>(); this.proxyAdapter = proxyService.getProxyAdapter(); + this.oidcService = proxyService.getOidcService(); this.maxPendingSendRequest = proxyConfig.getMaxPendingSendRequest(); this.resumeReadThreshold = maxPendingSendRequest / 2; this.autoSubscribeHandler = new AutoSubscribeHandler(proxyService.getEventCenter()); @@ -115,7 +127,7 @@ public MQTTProxyProtocolMethodProcessor(MQTTProxyService proxyService, ChannelHa @Override public void doProcessConnect(MqttAdapterMessage adapter, String userRole, AuthenticationDataSource authData, ClientRestrictions clientRestrictions) { - final MqttConnectMessage msg = (MqttConnectMessage) adapter.getMqttMessage(); + MqttConnectMessage msg = (MqttConnectMessage) adapter.getMqttMessage(); final ServerRestrictions serverRestrictions = ServerRestrictions.builder() .receiveMaximum(proxyConfig.getReceiveMaximum()) .maximumPacketSize(proxyConfig.getMqttMessageMaxLength()) @@ -133,6 +145,12 @@ public void doProcessConnect(MqttAdapterMessage adapter, String userRole, .processor(this) .build(); connection.sendConnAck(); + if (proxyConfig.isMqttProxyMtlsEnabled()) { + MqttConnectMessage connectMessage = createMqttConnectMessage(msg, MTLS, userRole); + msg = connectMessage; + connection.setConnectMessage(msg); + } + ConnectEvent connectEvent = ConnectEvent.builder() .clientId(connection.getClientId()) .address(pulsarService.getAdvertisedAddress()) @@ -140,6 +158,14 @@ public void doProcessConnect(MqttAdapterMessage adapter, String userRole, eventService.sendConnectEvent(connectEvent); } + protected MQTTAuthenticationService.AuthenticationResult mtlsAuth(boolean fromProxy) throws MQTTAuthException { + if (proxyConfig.isMqttProxyMtlsEnabled()) { + SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); + return authenticationService.mTlsAuthenticate(sslHandler, oidcService); + } + return super.mtlsAuth(fromProxy); + } + @Override public void processPublish(MqttAdapterMessage adapter) { final MqttPublishMessage msg = (MqttPublishMessage) adapter.getMqttMessage(); @@ -447,8 +473,10 @@ private CompletableFuture connectToBroker(final String topic) { key -> lookupHandler.findBroker(TopicName.get(topic)).thenApply(mqttBroker -> adapterChannels.computeIfAbsent(mqttBroker, key1 -> { AdapterChannel adapterChannel = proxyAdapter.getAdapterChannel(mqttBroker); + final MqttConnectMessage connectMessage = connection.getConnectMessage(); + adapterChannel.writeAndFlush(new MqttAdapterMessage(connection.getClientId(), - connection.getConnectMessage())); + connectMessage)); return adapterChannel; }) ) diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java index bc17954ab..31934a20d 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java @@ -23,6 +23,7 @@ import io.streamnative.pulsar.handlers.mqtt.MQTTConnectionManager; import io.streamnative.pulsar.handlers.mqtt.MQTTService; import io.streamnative.pulsar.handlers.mqtt.adapter.MQTTProxyAdapter; +import io.streamnative.pulsar.handlers.mqtt.oidc.OIDCService; import io.streamnative.pulsar.handlers.mqtt.support.event.PulsarEventCenter; import io.streamnative.pulsar.handlers.mqtt.support.event.PulsarEventCenterImpl; import io.streamnative.pulsar.handlers.mqtt.support.psk.PSKConfiguration; @@ -36,6 +37,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.pulsar.broker.PulsarService; import org.apache.pulsar.common.util.netty.EventLoopUtil; +import org.apache.pulsar.metadata.api.MetadataStoreException; /** * This service is used for redirecting MQTT client request to proper MQTT protocol handler Broker. @@ -62,6 +64,9 @@ public class MQTTProxyService implements Closeable { @Getter private final MQTTProxyAdapter proxyAdapter; + @Getter + private OIDCService oidcService; + private Channel listenChannel; private Channel listenChannelTls; private Channel listenChannelTlsPsk; @@ -117,7 +122,7 @@ public void start() throws MQTTProxyException { throw new MQTTProxyException(e); } - if (proxyConfig.isMqttProxyTlsEnabled()) { + if (proxyConfig.isMqttProxyTlsEnabled() || proxyConfig.isMqttProxyMtlsEnabled()) { ServerBootstrap tlsBootstrap = serverBootstrap.clone(); tlsBootstrap.childHandler(new MQTTProxyChannelInitializer( this, proxyConfig, true, sslContextRefresher)); @@ -148,6 +153,13 @@ public void start() throws MQTTProxyException { throw new MQTTProxyException(e); } } + if (proxyConfig.isMqttProxyMtlsEnabled()) { + try { + this.oidcService = new OIDCService(pulsarService); + } catch (MetadataStoreException ex) { + throw new MQTTProxyException(ex); + } + } this.lookupHandler = new PulsarServiceLookupHandler(pulsarService, proxyConfig); this.eventService.start(); diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/AbstractCommonProtocolMethodProcessor.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/AbstractCommonProtocolMethodProcessor.java index 678e4c1e3..e94c63df1 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/AbstractCommonProtocolMethodProcessor.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/AbstractCommonProtocolMethodProcessor.java @@ -25,6 +25,7 @@ import io.streamnative.pulsar.handlers.mqtt.MQTTAuthenticationService; import io.streamnative.pulsar.handlers.mqtt.ProtocolMethodProcessor; import io.streamnative.pulsar.handlers.mqtt.adapter.MqttAdapterMessage; +import io.streamnative.pulsar.handlers.mqtt.exception.MQTTAuthException; import io.streamnative.pulsar.handlers.mqtt.exception.restrictions.InvalidReceiveMaximumException; import io.streamnative.pulsar.handlers.mqtt.messages.MqttPropertyUtils; import io.streamnative.pulsar.handlers.mqtt.messages.ack.MqttConnectAck; @@ -123,9 +124,10 @@ public void processConnect(MqttAdapterMessage adapter) { clientId, username); } } else { - MQTTAuthenticationService.AuthenticationResult authResult = authenticationService - .authenticate(connectMessage); - if (authResult.isFailed()) { + MQTTAuthenticationService.AuthenticationResult authResult; + try { + authResult = mtlsAuth(adapter.fromProxy()); + } catch (MQTTAuthException e) { MqttMessage mqttMessage = MqttConnectAck.errorBuilder().authFail(protocolVersion); log.error("[CONNECT] Invalid or incorrect authentication. CId={}, username={}", clientId, username); adapter.setMqttMessage(mqttMessage); @@ -135,6 +137,19 @@ public void processConnect(MqttAdapterMessage adapter) { } return; } + if (authResult.isFailed()) { + authResult = authenticationService.authenticate(connectMessage); + if (authResult.isFailed()) { + MqttMessage mqttMessage = MqttConnectAck.errorBuilder().authFail(protocolVersion); + log.error("[CONNECT] Invalid or incorrect authentication. CId={}, username={}", clientId, username); + adapter.setMqttMessage(mqttMessage); + channel.writeAndFlush(adapter); + if (!adapter.fromProxy()) { + channel.close(); + } + return; + } + } userRole = authResult.getUserRole(); authData = authResult.getAuthData(); } @@ -157,6 +172,10 @@ public void processConnect(MqttAdapterMessage adapter) { } } + protected MQTTAuthenticationService.AuthenticationResult mtlsAuth(boolean fromProxy) throws MQTTAuthException { + return MQTTAuthenticationService.AuthenticationResult.FAILED; + } + @Override public void processPubAck(MqttAdapterMessage msg) { if (log.isDebugEnabled()) { diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java index 4e13e58b9..18d335915 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java @@ -27,6 +27,7 @@ import io.netty.handler.codec.mqtt.MqttUnsubscribeMessage; import io.netty.handler.ssl.SslHandler; import io.streamnative.pulsar.handlers.mqtt.Connection; +import io.streamnative.pulsar.handlers.mqtt.MQTTAuthenticationService; import io.streamnative.pulsar.handlers.mqtt.MQTTConnectionManager; import io.streamnative.pulsar.handlers.mqtt.MQTTServerConfiguration; import io.streamnative.pulsar.handlers.mqtt.MQTTService; @@ -37,6 +38,7 @@ import io.streamnative.pulsar.handlers.mqtt.QosPublishHandlers; import io.streamnative.pulsar.handlers.mqtt.TopicFilter; import io.streamnative.pulsar.handlers.mqtt.adapter.MqttAdapterMessage; +import io.streamnative.pulsar.handlers.mqtt.exception.MQTTAuthException; import io.streamnative.pulsar.handlers.mqtt.exception.MQTTNoSubscriptionExistedException; import io.streamnative.pulsar.handlers.mqtt.exception.MQTTTopicNotExistedException; import io.streamnative.pulsar.handlers.mqtt.exception.restrictions.InvalidSessionExpireIntervalException; @@ -50,6 +52,7 @@ import io.streamnative.pulsar.handlers.mqtt.messages.codes.mqtt5.Mqtt5PubReasonCode; import io.streamnative.pulsar.handlers.mqtt.messages.codes.mqtt5.Mqtt5UnsubReasonCode; import io.streamnative.pulsar.handlers.mqtt.messages.properties.PulsarProperties; +import io.streamnative.pulsar.handlers.mqtt.oidc.OIDCService; import io.streamnative.pulsar.handlers.mqtt.restrictions.ClientRestrictions; import io.streamnative.pulsar.handlers.mqtt.restrictions.ServerRestrictions; import io.streamnative.pulsar.handlers.mqtt.support.event.AutoSubscribeHandler; @@ -87,14 +90,12 @@ import org.apache.pulsar.common.util.Codec; import org.apache.pulsar.common.util.FutureUtil; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; - /** * Default implementation of protocol method processor. */ @Slf4j public class MQTTBrokerProtocolMethodProcessor extends AbstractCommonProtocolMethodProcessor { + private final PulsarService pulsarService; private final QosPublishHandlers qosPublishHandlers; private final MQTTServerConfiguration configuration; @@ -108,6 +109,8 @@ public class MQTTBrokerProtocolMethodProcessor extends AbstractCommonProtocolMet private final WillMessageHandler willMessageHandler; private final RetainedMessageHandler retainedMessageHandler; private final AutoSubscribeHandler autoSubscribeHandler; + + private final OIDCService oidcService; @Getter private final CompletableFuture inactiveFuture = new CompletableFuture<>(); @@ -127,6 +130,7 @@ public MQTTBrokerProtocolMethodProcessor(MQTTService mqttService, ChannelHandler this.retainedMessageHandler = mqttService.getRetainedMessageHandler(); this.serverCnx = new MQTTServerCnx(pulsarService, ctx); this.autoSubscribeHandler = new AutoSubscribeHandler(mqttService.getEventCenter()); + this.oidcService = mqttService.getOidcService(); } @Override @@ -155,6 +159,17 @@ public void doProcessConnect(MqttAdapterMessage adapterMsg, String userRole, connection.sendConnAck(); } + protected MQTTAuthenticationService.AuthenticationResult mtlsAuth(boolean fromProxy) throws MQTTAuthException { + if (fromProxy) { + return super.mtlsAuth(fromProxy); + } + if (configuration.isMqttMtlsEnabled()) { + SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); + return authenticationService.mTlsAuthenticate(sslHandler, oidcService); + } + return super.mtlsAuth(fromProxy); + } + @Override public void processPubAck(MqttAdapterMessage adapter) { if (log.isDebugEnabled()) { @@ -186,21 +201,6 @@ public void processPublish(MqttAdapterMessage adapter) { if (log.isDebugEnabled()) { log.debug("[Publish] [{}] msg: {}", connection.getClientId(), adapter); } - try { - SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); - if (sslHandler != null) { - SSLSession session = sslHandler.engine().getSession(); - java.security.cert.Certificate[] clientCerts = session.getPeerCertificates(); - if (clientCerts.length > 0) { - if (clientCerts[0] instanceof java.security.cert.X509Certificate) { - java.security.cert.X509Certificate clientCert = (java.security.cert.X509Certificate) clientCerts[0]; - log.info("Client cert info: " + clientCert.getSubjectDN()); - } - } - } - } catch (SSLPeerUnverifiedException ex) { - log.warn("get client clientCerts error", ex); - } MqttPublishMessage msg = (MqttPublishMessage) adapter.getMqttMessage(); CompletableFuture result; if (!configuration.isMqttAuthorizationEnabled()) { diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java index 706e1964c..fa9e32364 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java @@ -19,6 +19,7 @@ import io.netty.channel.Channel; import io.netty.handler.codec.mqtt.MqttConnectMessage; import io.netty.handler.codec.mqtt.MqttConnectPayload; +import io.netty.handler.codec.mqtt.MqttConnectVariableHeader; import io.netty.handler.codec.mqtt.MqttFixedHeader; import io.netty.handler.codec.mqtt.MqttMessage; import io.netty.handler.codec.mqtt.MqttMessageType; @@ -182,6 +183,25 @@ public static MqttPublishMessage createMqttWillMessage(WillMessage willMessage) return builder.build(); } + public static MqttConnectMessage createMqttConnectMessage(MqttConnectMessage connectMessage, + String authMethod, + String authData) { + final MqttConnectVariableHeader header = connectMessage.variableHeader(); + MqttProperties properties = new MqttProperties(); + properties.add(new MqttProperties.StringProperty(MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value() + , authMethod)); + properties.add(new MqttProperties.BinaryProperty(MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value() + , authData.getBytes())); + MqttConnectVariableHeader variableHeader = new MqttConnectVariableHeader( + header.name(), header.version(), header.hasUserName(), header.hasPassword(), header.isWillRetain(), + header.willQos(), header.isWillFlag(), header.isCleanSession(), header.keepAliveTimeSeconds(), + properties + ); + MqttConnectMessage newConnectMessage = new MqttConnectMessage(connectMessage.fixedHeader(), variableHeader, + connectMessage.payload()); + return newConnectMessage; + } + public static MqttMessage createMqttDisconnectMessage() { return MessageBuilder.disconnect().build(); } diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java new file mode 100644 index 000000000..962dc49ec --- /dev/null +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2020 StreamNative, Inc.. All Rights Reserved. + */ +package io.streamnative.pulsar.handlers.mqtt.utils; + +import lombok.experimental.UtilityClass; + +import javax.validation.constraints.NotNull; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +@UtilityClass +public final class Paths { + + public String getUrlEncodedPath(@NotNull String name) { + return URLEncoder.encode(name, StandardCharsets.UTF_8); + } + + public String getUrlDecodedPath(@NotNull String name) { + return URLDecoder.decode(name, StandardCharsets.UTF_8); + } +} diff --git a/pom.xml b/pom.xml index d5041e5b5..e12255ec9 100644 --- a/pom.xml +++ b/pom.xml @@ -95,6 +95,12 @@ + + + dev.cel + cel + 0.5.2 + io.grpc grpc-all diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java deleted file mode 100644 index cb5312d39..000000000 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt3/fusesource/proxy/ProxyMtlsTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/** - * 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. - */ -package io.streamnative.pulsar.handlers.mqtt.mqtt3.fusesource.proxy; - -import io.streamnative.pulsar.handlers.mqtt.MQTTCommonConfiguration; -import io.streamnative.pulsar.handlers.mqtt.base.MQTTTestBase; -import java.io.File; -import java.io.FileInputStream; -import java.security.PrivateKey; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; -import javax.net.ssl.SSLContext; -import org.apache.pulsar.common.util.SecurityUtility; -import org.fusesource.mqtt.client.BlockingConnection; -import org.fusesource.mqtt.client.MQTT; -import org.fusesource.mqtt.client.Message; -import org.fusesource.mqtt.client.QoS; -import org.fusesource.mqtt.client.Topic; -import org.testng.Assert; -import org.testng.annotations.Test; - -public class ProxyMtlsTest extends MQTTTestBase { - - String path = "./src/test/resources/mtls/"; - - @Override - protected MQTTCommonConfiguration initConfig() throws Exception { - enableTls = true; - MQTTCommonConfiguration mqtt = super.initConfig(); - - mqtt.setMqttProxyEnabled(true); - mqtt.setMqttProxyTlsEnabled(true); - mqtt.setMqttTlsCertificateFilePath(path + "server.crt"); - mqtt.setMqttTlsKeyFilePath(path + "server.key"); - - return mqtt; - } - - public SSLContext createSSLContext() throws Exception { - File clientCrt1 = new File(path + "ca.cer"); - Certificate clientCert1 = CertificateFactory - .getInstance("X.509").generateCertificate(new FileInputStream(clientCrt1)); - - File key = new File(path + "client.crt"); - Certificate clientKey1 = CertificateFactory - .getInstance("X.509").generateCertificate(new FileInputStream(key)); - - PrivateKey privateKey = SecurityUtility.loadPrivateKeyFromPemFile(path + "client.key"); - - final SSLContext sslContext = SecurityUtility.createSslContext(true, - new Certificate[]{clientCert1}, new Certificate[]{clientKey1}, privateKey); - - return sslContext; - } - - - @Test - public void testProduceAndConsume() throws Exception { - SSLContext sslContext = createSSLContext(); - MQTT mqtt = createMQTTProxyTlsClient(); - mqtt.setSslContext(sslContext); - - String topicName = "testProduceAndConsume"; - BlockingConnection connection = mqtt.blockingConnection(); - connection.connect(); - Topic[] topics = { new Topic(topicName, QoS.AT_MOST_ONCE) }; - connection.subscribe(topics); - String message = "Hello MQTT"; - connection.publish(topicName, message.getBytes(), QoS.AT_MOST_ONCE, false); - Message received = connection.receive(); - Assert.assertEquals(received.getTopic(), topicName); - Assert.assertEquals(new String(received.getPayload()), message); - received.ack(); - connection.disconnect(); - - } -} diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/MQTT5ClientUtils.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/MQTT5ClientUtils.java index 8183f4281..7307f152a 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/MQTT5ClientUtils.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/MQTT5ClientUtils.java @@ -36,6 +36,14 @@ public static Mqtt5BlockingClient createMqtt5ProxyClient(int proxyPort) { .buildBlocking(); } + public static Mqtt5BlockingClient createMqtt5ProxyClient(int proxyPort, String x) { + return Mqtt5Client.builder() + .identifier(UUID.randomUUID().toString()) + .serverHost("127.0.0.1") + .serverPort(proxyPort) + .buildBlocking(); + } + public static void publishQos1ARandomMsg(Mqtt5BlockingClient client, String topic) { client.publishWith() .topic(topic) diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java new file mode 100644 index 000000000..3a4dbec05 --- /dev/null +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java @@ -0,0 +1,225 @@ +/** + * 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. + */ +package io.streamnative.pulsar.handlers.mqtt.mqtt5.hivemq.base; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import com.hivemq.client.mqtt.MqttClientSslConfig; +import com.hivemq.client.mqtt.MqttGlobalPublishFilter; +import com.hivemq.client.mqtt.datatypes.MqttQos; +import com.hivemq.client.mqtt.datatypes.MqttTopic; +import com.hivemq.client.mqtt.mqtt5.Mqtt5BlockingClient; +import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; +import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish; +import io.jsonwebtoken.SignatureAlgorithm; +import io.streamnative.pulsar.handlers.mqtt.MQTTCommonConfiguration; +import io.streamnative.pulsar.handlers.mqtt.base.MQTTTestBase; +import java.io.File; +import java.io.FileInputStream; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.util.Optional; +import java.util.Properties; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import javax.crypto.SecretKey; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.security.KeyStore; +import org.apache.pulsar.broker.authentication.AuthenticationProviderToken; +import org.apache.pulsar.broker.authentication.utils.AuthTokenUtils; +import org.apache.pulsar.client.admin.PulsarAdmin; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.impl.auth.AuthenticationToken; +import org.apache.pulsar.common.util.SecurityUtility; +import org.fusesource.mqtt.client.BlockingConnection; +import org.fusesource.mqtt.client.MQTT; +import org.fusesource.mqtt.client.QoS; +import org.fusesource.mqtt.client.Topic; +import org.testng.Assert; +import org.testng.annotations.Test; + + +import static org.mockito.Mockito.spy; + +public class ProxyMtlsTest extends MQTTTestBase { + + + String path = "./src/test/resources/mtls/"; + + String token; + + @Override + protected MQTTCommonConfiguration initConfig() throws Exception { + System.setProperty("jdk.security.allowNonCaAnchor", "true"); + enableTls = true; + MQTTCommonConfiguration mqtt = super.initConfig(); + + mqtt.setSystemTopicEnabled(false); + mqtt.setMqttProxyEnabled(true); + mqtt.setMqttProxyMtlsEnabled(true); + mqtt.setMqttMtlsEnabled(true); + mqtt.setMqttProxyTlsEnabled(true); + + mqtt.setMqttTlsEnabledWithKeyStore(true); + mqtt.setMqttTlsKeyStoreType("JKS"); + mqtt.setMqttTlsKeyStore(path + "serverkeystore.jks"); + mqtt.setMqttTlsKeyStorePassword("123456"); + mqtt.setMqttTlsTrustStoreType("JKS"); + mqtt.setMqttTlsTrustStore(path + "truststore.jks"); + mqtt.setMqttTlsTrustStorePassword("123456"); + + SecretKey secretKey = AuthTokenUtils.createSecretKey(SignatureAlgorithm.HS256); + Properties properties = new Properties(); + properties.setProperty("tokenSecretKey", AuthTokenUtils.encodeKeyBase64(secretKey)); + token = AuthTokenUtils.createToken(secretKey, "superUser", Optional.empty()); + + mqtt.setAuthenticationEnabled(true); + mqtt.setMqttAuthenticationEnabled(true); + mqtt.setMqttAuthenticationMethods(ImmutableList.of("token")); + mqtt.setSuperUserRoles(ImmutableSet.of("superUser")); + mqtt.setAuthenticationProviders(Sets.newHashSet(AuthenticationProviderToken.class.getName())); + mqtt.setBrokerClientAuthenticationPlugin(AuthenticationToken.class.getName()); + mqtt.setBrokerClientAuthenticationParameters("token:" + token); + mqtt.setProperties(properties); + + return mqtt; + } + + @Override + public void afterSetup() throws Exception { + AuthenticationToken authToken = new AuthenticationToken(); + authToken.configure("token:" + token); + + pulsarClient = PulsarClient.builder() + .serviceUrl(brokerUrl.toString()) + .authentication(authToken) + .statsInterval(0, TimeUnit.SECONDS) + .build(); + admin = spy(PulsarAdmin.builder() + .serviceHttpUrl(brokerUrl.toString()) + .authentication(authToken) + .build()); + } + + public SSLContext createSSLContext() throws Exception { + File caCertFile = new File(path + "ca.cer"); + Certificate caCert = CertificateFactory + .getInstance("X.509").generateCertificate(new FileInputStream(caCertFile)); + + File clientCertFile = new File(path + "client.crt"); + Certificate clientCert = CertificateFactory + .getInstance("X.509").generateCertificate(new FileInputStream(clientCertFile)); + + PrivateKey privateKey = SecurityUtility.loadPrivateKeyFromPemFile(path + "client.key"); + + final SSLContext sslContext = SecurityUtility.createSslContext(true, + new Certificate[]{caCert}, new Certificate[]{clientCert}, privateKey); + + return sslContext; + } + + public SSLContext createSSLContext2() throws Exception { + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + keyStore.load(new FileInputStream(path + "client.p12"), "".toCharArray()); + + KeyStore trustStore = KeyStore.getInstance("PKCS12"); + trustStore.load(new FileInputStream(path + "ca.p12"), "".toCharArray()); + + // 初始化密钥管理器 + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, "".toCharArray()); + + // 初始化信任管理器 + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(trustStore); + + final SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); + + return sslContext; + } + + + @Test + public void testMqtt3() throws Exception { + + + SSLContext sslContext = createSSLContext2(); + MQTT mqtt = createMQTTProxyTlsClient(); + mqtt.setSslContext(sslContext); + + String topicName = "testProduceAndConsume"; + BlockingConnection connection = mqtt.blockingConnection(); + connection.connect(); + Topic[] topics = { new Topic(topicName, QoS.AT_MOST_ONCE) }; +// connection.subscribe(topics); + String message = "Hello MQTT"; + connection.publish(topicName, message.getBytes(), QoS.AT_MOST_ONCE, false); +// Message received = connection.receive(); +// Assert.assertEquals(received.getTopic(), topicName); +// Assert.assertEquals(new String(received.getPayload()), message); +// received.ack(); + connection.disconnect(); + + } + + @Test + public void testMqtt5() throws Exception { + + KeyStore keyStore = KeyStore.getInstance("JKS"); + keyStore.load(new FileInputStream(path + "clientkeystore.jks"), "123456".toCharArray()); + + KeyStore trustStore = KeyStore.getInstance("JKS"); + trustStore.load(new FileInputStream(path + "truststore.jks"), "123456".toCharArray()); + + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, "123456".toCharArray()); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManagerFactory.init(trustStore); + + final MqttClientSslConfig sslConfig = MqttClientSslConfig.builder().keyManagerFactory(keyManagerFactory).trustManagerFactory(trustManagerFactory) + .build(); + + Random random = new Random(); + final Mqtt5BlockingClient client = Mqtt5Client.builder() + .identifier(UUID.randomUUID().toString()) + .serverHost("localhost") + .sslConfig(sslConfig) + .serverPort(getMqttProxyPortTlsList().get(random.nextInt(getMqttProxyPortTlsList().size()))) + .buildBlocking(); + + String topic = "testMqtt5"; + client.connect(); + client.subscribeWith().topicFilter(topic).qos(MqttQos.AT_LEAST_ONCE).send(); + byte[] msg = "payload".getBytes(); + client.publishWith() + .topic(topic) + .qos(MqttQos.AT_LEAST_ONCE) + .payload(msg) + .send(); + try (Mqtt5BlockingClient.Mqtt5Publishes publishes = client.publishes(MqttGlobalPublishFilter.ALL)) { + Mqtt5Publish publish = publishes.receive(); + Assert.assertEquals(publish.getTopic(), MqttTopic.of(topic)); + Assert.assertEquals(publish.getPayloadAsBytes(), msg); + } + client.unsubscribeWith().topicFilter(topic).send(); + client.disconnect(); + } +} diff --git a/tests/src/test/resources/mtls/ca.cer b/tests/src/test/resources/mtls/ca.cer deleted file mode 100644 index 7a6113eed..000000000 --- a/tests/src/test/resources/mtls/ca.cer +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC0zCCAbugAwIBAgIUOmhPX7hCH5pdeph+Wi4iitxLPswwDQYJKoZIhvcNAQEL -BQAwETEPMA0GA1UEAwwGUk9PVENBMCAXDTI0MDgyMDExMzgyMloYDzIxMjQwNzI3 -MTEzODIyWjARMQ8wDQYDVQQDDAZST09UQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDRl9g6I8aXzi77QY7ARHRl/ArCj38sQFjdQa848afsNqRD1P55 -jaiM9YXwJokkWSmr2xbkNI55Lz4zq1jx6ydRFeEuwYXocLagUWGdudKjhv6eghpY -Yfl9xumV9+SgG78nwLfeGvzDJ6KIFdfP4uiTFcfJjNlsoISkXQaQuVpPso+Le+FA -TjymshjXRx04sKYnJS/XT3ppukXTcGiGRjlTSe4cAJDcUJs7HCRTzEgSffOiFQ0m -2DUpQ9XKsURsNaKaaJBxiiX/d+5u6a+EWMPUIe70lXFrj/vbWf7pdLlKVzaqmo6D -JSF6P5ucjqb0ype7dgYl7zWjHM+Zfxvgtmu3AgMBAAGjITAfMB0GA1UdDgQWBBS/ -tRdSUQkupbbdv9y5/ala7bN1lTANBgkqhkiG9w0BAQsFAAOCAQEAVEVXzWFwZWpJ -ubpKuBYe9VFAT/dOj08rUaI82ea9wqFq8YIenKhmvlEkL6Xyj5MntE539iIzsL2w -hTDbMAxZ82SkRG1sOmRoGH9v0h58urmWlDLBK/wlIATJoKgbdzuRxsbEK97WPZZ1 -A+GuWwXGpcMoH9wxEDxUnWD+wg+5ftqfrOggxuw1BQpo0tYbTUsAVpr9z9YU9rdd -0GYL3RB8tlC4ja+zh/sZ4jz2S1ZEB6ykTZ+mq2/kTWZ/k7Zcss7+r7O3UZP5UQ1C -43g50rkrFsMkiJKNYOdeHsYtFeiVaSYjE2huGcky96nhgQ1ExTdTGOo48Skqt/qA -xIPGX242jw== ------END CERTIFICATE----- diff --git a/tests/src/test/resources/mtls/ca.csr b/tests/src/test/resources/mtls/ca.csr deleted file mode 100644 index 815f163d6..000000000 --- a/tests/src/test/resources/mtls/ca.csr +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICVjCCAT4CAQAwETEPMA0GA1UEAwwGUk9PVENBMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEA0ZfYOiPGl84u+0GOwER0ZfwKwo9/LEBY3UGvOPGn7Dak -Q9T+eY2ojPWF8CaJJFkpq9sW5DSOeS8+M6tY8esnURXhLsGF6HC2oFFhnbnSo4b+ -noIaWGH5fcbplffkoBu/J8C33hr8wyeiiBXXz+LokxXHyYzZbKCEpF0GkLlaT7KP -i3vhQE48prIY10cdOLCmJyUv1096abpF03BohkY5U0nuHACQ3FCbOxwkU8xIEn3z -ohUNJtg1KUPVyrFEbDWimmiQcYol/3fubumvhFjD1CHu9JVxa4/721n+6XS5Slc2 -qpqOgyUhej+bnI6m9MqXu3YGJe81oxzPmX8b4LZrtwIDAQABoAAwDQYJKoZIhvcN -AQELBQADggEBAAm0yuYvm9muZ09eMTPwOd+PGuqkRlOsXuua8llPAhQQUriz/Mft -ayzQ4KwVueviQDxPxFJPjIJ7C4sMTqkgVJbO36iT4ugzqDn59gVKrUcglDk/VScR -SJBk1cKbvbjyJZ/orxYZ15vzn7rVqxpmEjhgR4zWMxdALkpHd5H/ebqc184GIH9F -L5tY/G1JSxq4Ez5y4gX1HNsBo9+4i3bYOsxkE3Am8gMhFcJOzhmT5UgfXs61fZeJ -Y3NR9oPaYfHQPXGwFgonWs/eiL5q6IWyfCclqjbWUIa6ROc5efX5rROEtdJkcFup -3k6OcAX8WCbR8Yq64MMuf0PnSLStQh+AORA= ------END CERTIFICATE REQUEST----- diff --git a/tests/src/test/resources/mtls/ca.key b/tests/src/test/resources/mtls/ca.key deleted file mode 100644 index 55ccbf439..000000000 --- a/tests/src/test/resources/mtls/ca.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDRl9g6I8aXzi77 -QY7ARHRl/ArCj38sQFjdQa848afsNqRD1P55jaiM9YXwJokkWSmr2xbkNI55Lz4z -q1jx6ydRFeEuwYXocLagUWGdudKjhv6eghpYYfl9xumV9+SgG78nwLfeGvzDJ6KI -FdfP4uiTFcfJjNlsoISkXQaQuVpPso+Le+FATjymshjXRx04sKYnJS/XT3ppukXT -cGiGRjlTSe4cAJDcUJs7HCRTzEgSffOiFQ0m2DUpQ9XKsURsNaKaaJBxiiX/d+5u -6a+EWMPUIe70lXFrj/vbWf7pdLlKVzaqmo6DJSF6P5ucjqb0ype7dgYl7zWjHM+Z -fxvgtmu3AgMBAAECggEAIMdgJDubH/u5gkcO9cfe8mI4JpR9naSUoUnYBw5YJkun -ZgpmIAmFDkKJx3SnZx1gtIVnr5n+nDpEvpzyJKeTtw02cfMHJ8KU9T61Bw9cP4Hp -yU1spFzyQXb96hviUB32x9dOijhrRnQo6aKM5XDF0dcKr11NVb1G8VOxJqouUx8/ -9mf9W1Umf2JQ4SetQ/vktYMCke3BVgdnKPsNZbPTruWPXl28miVl/zWs++DEkwTL -4ZJrl3J+4D+2HGlxIJ9QVroA1D4RskXVdDqe0aE8wBME3wS/JYQSacG/pisvpAUz -ivXSWZGzv7OCzupB7ewRSNzZcsDTio3wXy3rZzHUKQKBgQDsrBHfteg0094iFuZ/ -Sp9nNLbryc9Ag+CNIqiAhiJbkgaGWtUaRhU3AaAYg2CJoJMAVY6fb1jYdAb4tgh7 -xq8+o7JS+ERVLcW1BgUOR4W8xjctKvNVqZ2x2AVNYcNwlJIb0nQyF4BLV+YzrHIV -NdDCkJzpB5+MjlJGNeOfc7W1yQKBgQDitaduEcKi6pK3wrlMk49S9+H4DL5TDg6k -gx4xFsBC8WZqipSN1KlcZEDIpm20rzOfet/kOQAME5989EzuNcrnJBlFmPiJ9rxv -IiHCab5mUhjXMRv6jo0Y5n21MPO9WL9ol9mzCvhDfDJnikeIiZztHAIuLM2pRYJL -BNzsW0nVfwKBgE4hQ8lJYP3Hj4ZLbw5IkTTd5yERvzR6FLAi5+N95Gu8WiESbVU+ -G5TMGZDeFgl5E+5BUFL7zCWwr/h9B3HtFj8khSL0yIIiGSl4ckTTgafe+6oSisAV -vXRPbvirtHw+37kFkcxTi8vTmbAnVoX//Qmt+c7H8HjTJv/8nEcwSKVZAoGAIP2w -VLsu6Mhb+3PRxUv/4mICNzebhriX9ubBwQD/j35TmhN6lL0qvDA2oTxe4JlSWNXn -uO12jUtZvTRL8apQUZyWNOOS33jRaRa9dO4wb/FofgA+gxK1g7ce+fwarCY7DHx0 -iLKC+EcdiqW7zSnBdVvLEW8hqo1b7ZDSmW6bav8CgYEAkT6msKVPZzADJlAAfc6N -cN8nXc5WH86V3qKwQUR4p2EP0ti67UE4t1tenuS61IeeQux22g9mO7KLc4os+35D -QmGtbaDa1oPBI5qgTM9SoLTSRQAnZRUWcSZN2RbmJym0EKswKjQzL2B3CyGOg0Mv -nSw7JE+3k6fSrJEb9rIuMZc= ------END PRIVATE KEY----- diff --git a/tests/src/test/resources/mtls/ca.p12 b/tests/src/test/resources/mtls/ca.p12 deleted file mode 100644 index bffb33375b2df0f6552228a62b247dbf72318e84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2483 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 diff --git a/tests/src/test/resources/mtls/server.cer b/tests/src/test/resources/mtls/server.cer deleted file mode 100644 index 713cbc6fb..000000000 --- a/tests/src/test/resources/mtls/server.cer +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC9zCCAd+gAwIBAgIUIv6phwXlPa0CN34gK4Z2YAOafs0wDQYJKoZIhvcNAQEL -BQAwETEPMA0GA1UEAwwGUk9PVENBMCAXDTI0MDgyMDExMzg1NloYDzIxMjQwNzI3 -MTEzODU2WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQC3VcW68VdUowsRYxwc8yH6cjIMYAFtTDQVjiu9eqMPUW0j -aj/tXwVql/gHBLkuRd0DCDgXaW5qSofykyOtU8hjAduNycDf4Qb7bv8Pan91j9x8 -UgBORk0fBqhm1pD2bDqVXdKvZF7Nj60ofeU3mWv6xg9FILUK3c5FD3bQVhTELbUi -JC4ay4jDMIuw+5D82f60s8RUmfOlSTtT1LZrCfJdNGnk7QNPefZbwMjl2MwnoY/8 -0IgVXvc3hg1bk9qgi0s2zaYvZomiE4mvo6FbfREFkuztqr0jtNBRep3Tilsq2zRl -9E0Sg1GBvr9Kegaa8g8IPpZ5oqr0YqOh1xX/WAPPAgMBAAGjQjBAMB0GA1UdDgQW -BBR9qjLZLqBi4ssG9re0LvL9gy6zFDAfBgNVHSMEGDAWgBS/tRdSUQkupbbdv9y5 -/ala7bN1lTANBgkqhkiG9w0BAQsFAAOCAQEAFQ++gIJmZXhSuKXPi3QlA1Wk6un7 -/0coZDWJg8EpVjw6stBHedNbf8RiKc8L+OVFkWqKna7/oFbcq+kAN/KZ8Zh/+3bH -jCJD8olPUCMKQUVefawuzEyv0q9t5f41XPoe9Gs2vieh6hIWtSpjobZAVxp4MPwG -k6SVqYxq305OBSfrNl7QMakv/GRvs37/2VRo3/v5e9/W/UbS4IQHmfIiEfPtuRyd -iCmuxppW1BgFcwLWt2buX2k8xkNGy5709wRIq+f6K6qdYRSfoPMZLJzHlW7r/pWb -OzBCSFlz7eFZxzqoSd3l2/qHk2tg+cY3pl+GkvubsXJTlsVn3mpxjiUCYw== ------END CERTIFICATE----- diff --git a/tests/src/test/resources/mtls/server.crt b/tests/src/test/resources/mtls/server.crt deleted file mode 100644 index 030c99786..000000000 --- a/tests/src/test/resources/mtls/server.crt +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC1zCCAb+gAwIBAgIUbAr8zoEcK7TWWvvVQcEY7FkeZ2MwDQYJKoZIhvcNAQEL -BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MDgyMDExNTMyN1oXDTM0MDgx -ODExNTMyN1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAt1XFuvFXVKMLEWMcHPMh+nIyDGABbUw0FY4rvXqjD1Ft -I2o/7V8Fapf4BwS5LkXdAwg4F2luakqH8pMjrVPIYwHbjcnA3+EG+27/D2p/dY/c -fFIATkZNHwaoZtaQ9mw6lV3Sr2RezY+tKH3lN5lr+sYPRSC1Ct3ORQ920FYUxC21 -IiQuGsuIwzCLsPuQ/Nn+tLPEVJnzpUk7U9S2awnyXTRp5O0DT3n2W8DI5djMJ6GP -/NCIFV73N4YNW5PaoItLNs2mL2aJohOJr6OhW30RBZLs7aq9I7TQUXqd04pbKts0 -ZfRNEoNRgb6/SnoGmvIPCD6WeaKq9GKjodcV/1gDzwIDAQABoyEwHzAdBgNVHQ4E -FgQUfaoy2S6gYuLLBva3tC7y/YMusxQwDQYJKoZIhvcNAQELBQADggEBADOtJsIo -KICWLZNNqzbjQnmq4muHkkECEU+QPk3VSGmb6BtbgsNI+ZjNkYZhYkhVWiDWLYRM -6IuKbkm4qG29CJInBkMjsbjMqWa9o2C00GnK2E/WXIZOTNcTMqjPOTJt3LkfBoNt -J0MelOd+imHB+0NA7HyfnrQnH4veknhhLXImL0brgrdED8kieylenzm9DHIJ8pPY -FQEzDwjVAWjaErWgfd/j+ip2adD90Gf6lkC+uBDA84sQvdboChLbTGlH4FE0PBe+ -ILAu3rlvbULJUqDYnk4z6m7rn+T2SxWd/0VgFWFqcxol5A6zpcSVZm1EyakAh7hc -zfIyqHCXDHg7fec= ------END CERTIFICATE----- diff --git a/tests/src/test/resources/mtls/server.csr b/tests/src/test/resources/mtls/server.csr deleted file mode 100644 index 83800fd4c..000000000 --- a/tests/src/test/resources/mtls/server.csr +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEAt1XFuvFXVKMLEWMcHPMh+nIyDGABbUw0FY4rvXqj -D1FtI2o/7V8Fapf4BwS5LkXdAwg4F2luakqH8pMjrVPIYwHbjcnA3+EG+27/D2p/ -dY/cfFIATkZNHwaoZtaQ9mw6lV3Sr2RezY+tKH3lN5lr+sYPRSC1Ct3ORQ920FYU -xC21IiQuGsuIwzCLsPuQ/Nn+tLPEVJnzpUk7U9S2awnyXTRp5O0DT3n2W8DI5djM -J6GP/NCIFV73N4YNW5PaoItLNs2mL2aJohOJr6OhW30RBZLs7aq9I7TQUXqd04pb -Kts0ZfRNEoNRgb6/SnoGmvIPCD6WeaKq9GKjodcV/1gDzwIDAQABoAAwDQYJKoZI -hvcNAQELBQADggEBAI9SP5NUWWOXxEwZ4zz4wr62F2AAZsJuCwi9hYcWncF0i6qb -8RktS5FcF3BToMOiJzDPpteOllVbDCZOOW3X9XsnPmf4A/t2dm00SFhdkIPpzqSo -6yFzAEa0VwZ7dUx0bvw/3RKBXRi9QraZn1gHJk7grlRvqKeD93gdoorQ9XJPkmGj -zc+dCiEP6E08sg1JUc/7nVtxYtealc8nBVvs7N6zDXspJh8wYzTWpdIDVUicdD3f -l1h8ieIFuxpYJ91j4+ojVGIsNSqPMHQBPTLyVOIDEeErLPyOJzxbNnfwC0gUZeGz -C7vQhXstV8Wa9gyYV/0L7Wmjd2K0eY0w00dx8eA= ------END CERTIFICATE REQUEST----- diff --git a/tests/src/test/resources/mtls/server.key b/tests/src/test/resources/mtls/server.key deleted file mode 100644 index 3be39ba07..000000000 --- a/tests/src/test/resources/mtls/server.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC3VcW68VdUowsR -Yxwc8yH6cjIMYAFtTDQVjiu9eqMPUW0jaj/tXwVql/gHBLkuRd0DCDgXaW5qSofy -kyOtU8hjAduNycDf4Qb7bv8Pan91j9x8UgBORk0fBqhm1pD2bDqVXdKvZF7Nj60o -feU3mWv6xg9FILUK3c5FD3bQVhTELbUiJC4ay4jDMIuw+5D82f60s8RUmfOlSTtT -1LZrCfJdNGnk7QNPefZbwMjl2MwnoY/80IgVXvc3hg1bk9qgi0s2zaYvZomiE4mv -o6FbfREFkuztqr0jtNBRep3Tilsq2zRl9E0Sg1GBvr9Kegaa8g8IPpZ5oqr0YqOh -1xX/WAPPAgMBAAECggEACeVZ1nTne1yPoOEiJ9fh2iRm2i8mdJFb8FvrtX8UpSOG -ihZWnAf4gV/xleNl4X8I5nx/lpfsy1T5kJjroJP4qYt0n+sne44oc9LydpEPjzd0 -NcuxU4hM6mNQHLjxOzPtV5moYSpAScU7Ggftovonj3I4aclRrGP7mdOzXJyA43Pi -nIdCsDw2j65ExI6wU5eQVC1TzEFXdEoZQsOPYIQO6XZbccJTpcIdhFYzkoOpYLe6 -G56JLjiNJSTDpPg8KEFpNq0Csjmh29tTbZEKfJdUpMDTnX9WXrB3w/el/R343Jn7 -fAmhw3M5ugw2IE3uQHWwj2EpPiKgPgepTQQav+Hg3QKBgQDyvdc30IhEXweSqKDA -3uFx9wdHHpw+BJUBuuuYAwqU2fwPX19vR6VlSjjqDGbpLa8SBh0Tv0VnHMHx/F19 -DjyVOpORzJ7DBnEKJn83USvATdP3hpjkSA0DO8eCKHI+r2HHwyuI43ZNqrDxLzM1 -mfFwW6Ppc6EaBF+Py+FSpIi+1QKBgQDBWUYbj0W0ySAAwJsC5hMvzbpirqdcIsfe -fx/kCU8xHRcSQRwmImgIHdFB+iyaQXmUHodlqc/wTZMX4aCXgJvSF//xDbBJVzKr -eHa6d5sTtLVqZbv+IBc20X/gBLAe5rv1xVTP1Dr94tqzeWLtV/4MobJnT+cf7Kdm -bjEfFNtyEwKBgGtCxbntFHmZwD/m8XmoQthX/shHV2T0I1+rV/VIysExfXbRftsu -PoB+hp2tM0AwJp8BQpH6P9GrXGvwRuM+ijiqtJCFaVXmH8cLccVgwcNs4JAM0rx0 -tgNKxALYmnrmhn9911vanuj81skMQUWbK5upcslyhap4aj2hKoSZHa+tAoGAAQSQ -SurZKhd49KgO6Nf/N9w0Y/qZZPHF7ZTrvQ6TfSWzDmSLWmQJ+ij2BgvkGjfIBRCY -E9/t+UzfPlvwtXt21odL0KAK0ogD+0UaEuc4SMVFwzaf47mVhbNaofpEVxVN3gBY -7vMmEFoWXqV/8NHqw3RCdSrFg7SCORbRaWF5ukMCgYBaNpCKI7nhwlGfetL8Nx7/ -BqhAO9TBGNwnMv1SmTEtPcUyi2GFGduIttZtuxYr5UHM/K2fNk64YeAVU59+elvj -/5k0tr9X+UwkCn3f1zJ8qon3+4Hl+FXRIz++Oo4B6Td+U3cwOxJGm1zvj0A59KJQ -r1vqYIL4qChsjV72sXkHfQ== ------END PRIVATE KEY----- diff --git a/tests/src/test/resources/mtls/server.p12 b/tests/src/test/resources/mtls/server.p12 deleted file mode 100644 index 21560276b3bb9f269647699199ffcc7a56da8edc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2531 zcmai$X*3jy8^+BT%h>mQnIW!0{bvGzd;JhB-0;hA#81fuKLg@Zy?1QK zCN1JL8xBt@k5I1y0@<11T&(Q>y9xxeFu|o+!PsO=fFCmmpaSBv!CMBwHSmv;fsDpw zhv&KRL}n~B%=}5f+yD`}YtPJb2Gnrq7LyX z<8kd>)t(}zooaNQxzhFBU>mv48~k{mgXZ_@O1@&BV2H(^5{kmh=hDc;9y zR<-+&b%)Gr)@ze`hGNoku?dHH zz9jgdW4vgbVUT9^-nHBe~wFj5fZ95r^?S5M4_ zM_dBOZi8HitRDJ(AwO>Ld@hIt{L1kcKBU3dqKVY+RIEnNP&lJD9L^1&q(3=!Z$77( zy=pL7A}tTPa{oX;SZ$y@fP-TtYpONF^*!P>_vTjHuZgs0_6MY@XXih!H5-K{%XG~r zK2*CMx>m37lmx|zZJ+hpZl7@^_x<8*V}Xt*EVtlnHkWQ-S({U`2~NwUKC%rO1($oi z%TvUghBBr2tTms~!ZHaY(UeR$X=jYCIQ{iuT;^)d#k{FV8>d3aEwEdED!IUR<0RrBW1JHb@;$zyglNFnN$+ z?^s9t{!Y&ad7rx-Nl5cAP}#F3(JuvB1V$sFyhN-<(^2W;w-w!)sjGF8igFBE3MG_+ zNq`*aV^YyGd2a!c+bkKZ1eMX+f^@fLO;#87xpfv1i00k_(pJDDYV-h zmE2`TN>NxKL4(&v0@wKfS6+)guv}^9{i|MQn1MBPiCphhI(+D{)KzQ4Pj)Uf+qbs7 zTEF_IsO>|C-ooECe#>s1zc!qb#eF5$ySHn6bTzO1vineyAsJ3&$@tORe?h=<3q)jz zKDF_u6UNHjz5{L+*5B71caQVtrHje~DMq=jsp=(o`UCx-fJ2$6fN5Gti0nw4SOz>&G_fHmI zx>8GKqPpYPAnsnVwfF`;OO8NL<}h8nC>6g4OF4 zZEQDqmuY@CvC=nDKoIaMY|-CI#4R535yjed*n9DB?|TRC64aABnNk}@D_Jko?&heb zGIq0W+4BQ7;zK8!%|Td)KwO?5xIw7urSh8Av@D%eU^M+yz3Y$aX-Jfmw>Lg9>{5q$&i@d2|=q$OZrU*f=imlL|?EGyW!g0-{{PD#K!vM z%0o<%g528;74p4_^=NS(&`Y14#nnd!8b0D3{pkX8A4rXBhQ3!&bw7Zd0Yo?v>n#F zO(aoX6H*bslJ*GgL){IiDS?fJ^VofTBgLHAdNtC(Pz;yB#=uR+C`2ED#J-2iv) z*rzn@(HN1Rj&iExwD<6-dN<|xV3%}Kd6>Ar(KMqFgO4z5-=bFr;&#w0WHZN-b6z!~ z^leuNtQ}zd?U>$?mQT~wL)LE=;GE?PrDgnhoFJU>$xkf$hHq3;&>Nps3%)@3?~4%u z9OM?a6W9Z?9ySse@wSd)%~gnY^`wel+B!Ij={j2Q*Dvj_xa@0`1=D+R%sL`RdbgzpY9Id@RUHf5~g#@woOvZJzdqXoBA8j?I{Kl$E26X05ZDtu%7c28o^A}xZ)8^T zkL#3ay0e?qrvS0uuNz^Dh-Sdk?H!ed-exqVRbq(7d28odcYV?`O`|7%MoLSz8FCe^&ur_mMqcnG52sFGxNZ&Z4FvJ^Ar#>9KR^o>Mu>of z__S&Y4&|s{a5pxy)qV^xj-;X2! From 8b2e0f2a616be65bfec8cf5981353ced48994287 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Fri, 23 Aug 2024 22:14:19 +0800 Subject: [PATCH 10/23] fix license header --- .../handlers/mqtt/oidc/ExpressionCompiler.java | 12 +++++++++++- .../handlers/mqtt/oidc/OIDCPoolResources.java | 12 +++++++++++- .../pulsar/handlers/mqtt/oidc/OIDCService.java | 13 +++++++++++++ .../pulsar/handlers/mqtt/oidc/Pool.java | 12 +++++++++++- .../pulsar/handlers/mqtt/oidc/PoolCompiler.java | 12 +++++++++++- .../pulsar/handlers/mqtt/utils/Paths.java | 12 +++++++++++- 6 files changed, 68 insertions(+), 5 deletions(-) diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java index 1eb2a5b44..ea7fa103f 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java @@ -1,5 +1,15 @@ /** - * Copyright (c) 2020 StreamNative, Inc.. All Rights Reserved. + * 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. */ package io.streamnative.pulsar.handlers.mqtt.oidc; diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java index 1b95d55c2..c403389db 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java @@ -1,5 +1,15 @@ /** - * Copyright (c) 2020 StreamNative, Inc.. All Rights Reserved. + * 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. */ package io.streamnative.pulsar.handlers.mqtt.oidc; diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java index 469f9406d..44891e377 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java @@ -1,3 +1,16 @@ +/** + * 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. + */ package io.streamnative.pulsar.handlers.mqtt.oidc; import com.beust.jcommander.internal.Lists; diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java index 8b6c520f2..73ab73566 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java @@ -1,5 +1,15 @@ /** - * Copyright (c) 2020 StreamNative, Inc.. All Rights Reserved. + * 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. */ package io.streamnative.pulsar.handlers.mqtt.oidc; diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java index 2bf82900c..32c6a3bd5 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java @@ -1,5 +1,15 @@ /** - * Copyright (c) 2020 StreamNative, Inc.. All Rights Reserved. + * 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. */ package io.streamnative.pulsar.handlers.mqtt.oidc; diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java index 962dc49ec..eb76937c5 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java @@ -1,5 +1,15 @@ /** - * Copyright (c) 2020 StreamNative, Inc.. All Rights Reserved. + * 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. */ package io.streamnative.pulsar.handlers.mqtt.utils; From 97cf9efb540b8eb52a0a918b15b9d9d1d31c8b5a Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Fri, 23 Aug 2024 22:24:52 +0800 Subject: [PATCH 11/23] fix checkstyle --- .../pulsar/handlers/mqtt/MQTTService.java | 1 - .../mqtt/oidc/ExpressionCompiler.java | 7 ++--- .../handlers/mqtt/oidc/OIDCPoolResources.java | 10 +++---- .../handlers/mqtt/oidc/OIDCService.java | 21 ++++++------- .../pulsar/handlers/mqtt/oidc/Pool.java | 3 +- .../handlers/mqtt/oidc/package-info.java | 18 +++++++++++ .../pulsar/handlers/mqtt/utils/Paths.java | 5 ++-- .../mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java | 14 +++++---- tests/src/test/resources/mtls/ca.cer | 19 ++++++++++++ tests/src/test/resources/mtls/ca.crt | 19 ++++++++++++ tests/src/test/resources/mtls/ca.key | 28 ++++++++++++++++++ tests/src/test/resources/mtls/ca.srl | 1 + tests/src/test/resources/mtls/ca_config.cnf | 15 ++++++++++ tests/src/test/resources/mtls/client.cer | 18 +++++++++++ tests/src/test/resources/mtls/client.csr | 15 ++++++++++ tests/src/test/resources/mtls/client.key | 28 ++++++++++++++++++ tests/src/test/resources/mtls/client.p12 | Bin 0 -> 2531 bytes .../test/resources/mtls/clientkeystore.jks | Bin 0 -> 2107 bytes tests/src/test/resources/mtls/server.cer | 18 +++++++++++ tests/src/test/resources/mtls/server.csr | 15 ++++++++++ tests/src/test/resources/mtls/server.key | 28 ++++++++++++++++++ tests/src/test/resources/mtls/server.p12 | Bin 0 -> 2531 bytes .../test/resources/mtls/serverkeystore.jks | Bin 0 -> 2110 bytes tests/src/test/resources/mtls/truststore.jks | Bin 0 -> 1158 bytes 24 files changed, 250 insertions(+), 33 deletions(-) create mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/package-info.java create mode 100644 tests/src/test/resources/mtls/ca.cer create mode 100644 tests/src/test/resources/mtls/ca.crt create mode 100644 tests/src/test/resources/mtls/ca.key create mode 100644 tests/src/test/resources/mtls/ca.srl create mode 100644 tests/src/test/resources/mtls/ca_config.cnf create mode 100644 tests/src/test/resources/mtls/client.cer create mode 100644 tests/src/test/resources/mtls/client.csr create mode 100644 tests/src/test/resources/mtls/client.key create mode 100644 tests/src/test/resources/mtls/client.p12 create mode 100644 tests/src/test/resources/mtls/clientkeystore.jks create mode 100644 tests/src/test/resources/mtls/server.cer create mode 100644 tests/src/test/resources/mtls/server.csr create mode 100644 tests/src/test/resources/mtls/server.key create mode 100644 tests/src/test/resources/mtls/server.p12 create mode 100644 tests/src/test/resources/mtls/serverkeystore.jks create mode 100644 tests/src/test/resources/mtls/truststore.jks diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java index 8e4c34d4f..7a9c1f807 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java @@ -15,7 +15,6 @@ import io.streamnative.pulsar.handlers.mqtt.exception.MQTTServerException; import io.streamnative.pulsar.handlers.mqtt.oidc.OIDCService; -import io.streamnative.pulsar.handlers.mqtt.proxy.MQTTProxyException; import io.streamnative.pulsar.handlers.mqtt.support.MQTTMetricsCollector; import io.streamnative.pulsar.handlers.mqtt.support.MQTTMetricsProvider; import io.streamnative.pulsar.handlers.mqtt.support.QosPublishHandlersImpl; diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java index ea7fa103f..b11c01550 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java @@ -25,15 +25,14 @@ import dev.cel.runtime.CelEvaluationException; import dev.cel.runtime.CelRuntime; import dev.cel.runtime.CelRuntimeFactory; -import lombok.Getter; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; - import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import lombok.Getter; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; public class ExpressionCompiler { diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java index c403389db..348210206 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java @@ -15,16 +15,16 @@ import com.fasterxml.jackson.core.type.TypeReference; import io.streamnative.pulsar.handlers.mqtt.utils.Paths; -import org.apache.pulsar.broker.resources.BaseResources; -import org.apache.pulsar.common.util.FutureUtil; -import org.apache.pulsar.metadata.api.MetadataStore; -import org.apache.pulsar.metadata.api.MetadataStoreException; -import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; +import javax.validation.constraints.NotNull; +import org.apache.pulsar.broker.resources.BaseResources; +import org.apache.pulsar.common.util.FutureUtil; +import org.apache.pulsar.metadata.api.MetadataStore; +import org.apache.pulsar.metadata.api.MetadataStoreException; @SuppressWarnings("UnstableApiUsage") public final class OIDCPoolResources extends BaseResources { diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java index 44891e377..778ec63af 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java @@ -15,6 +15,15 @@ import com.beust.jcommander.internal.Lists; import com.google.common.base.Joiner; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -26,18 +35,6 @@ import org.apache.pulsar.metadata.api.Notification; import org.apache.pulsar.metadata.api.NotificationType; import org.apache.pulsar.metadata.api.extended.MetadataStoreExtended; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; @Slf4j public class OIDCService { diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java index 73ab73566..6e116bb7a 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java @@ -14,9 +14,8 @@ package io.streamnative.pulsar.handlers.mqtt.oidc; import com.fasterxml.jackson.annotation.JsonProperty; - -import javax.validation.constraints.NotNull; import java.util.Objects; +import javax.validation.constraints.NotNull; public record Pool(@JsonProperty(value = "name", required = true) String name, @JsonProperty(value = "description", required = true) @NotNull String description, diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/package-info.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/package-info.java new file mode 100644 index 000000000..33a5d663e --- /dev/null +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/package-info.java @@ -0,0 +1,18 @@ +/** + * 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. + */ + +/** + * Package info. + */ +package io.streamnative.pulsar.handlers.mqtt.oidc; diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java index eb76937c5..14d76b29e 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/Paths.java @@ -13,12 +13,11 @@ */ package io.streamnative.pulsar.handlers.mqtt.utils; -import lombok.experimental.UtilityClass; - -import javax.validation.constraints.NotNull; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import javax.validation.constraints.NotNull; +import lombok.experimental.UtilityClass; @UtilityClass public final class Paths { diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java index 3a4dbec05..3553948bd 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java @@ -13,6 +13,7 @@ */ package io.streamnative.pulsar.handlers.mqtt.mqtt5.hivemq.base; +import static org.mockito.Mockito.spy; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; @@ -28,6 +29,7 @@ import io.streamnative.pulsar.handlers.mqtt.base.MQTTTestBase; import java.io.File; import java.io.FileInputStream; +import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; @@ -40,7 +42,6 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; -import java.security.KeyStore; import org.apache.pulsar.broker.authentication.AuthenticationProviderToken; import org.apache.pulsar.broker.authentication.utils.AuthTokenUtils; import org.apache.pulsar.client.admin.PulsarAdmin; @@ -55,8 +56,6 @@ import org.testng.annotations.Test; -import static org.mockito.Mockito.spy; - public class ProxyMtlsTest extends MQTTTestBase { @@ -146,7 +145,8 @@ public SSLContext createSSLContext2() throws Exception { keyManagerFactory.init(keyStore, "".toCharArray()); // 初始化信任管理器 - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(trustStore); final SSLContext sslContext = SSLContext.getInstance("TLS"); @@ -191,10 +191,12 @@ public void testMqtt5() throws Exception { KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, "123456".toCharArray()); - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( + TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(trustStore); - final MqttClientSslConfig sslConfig = MqttClientSslConfig.builder().keyManagerFactory(keyManagerFactory).trustManagerFactory(trustManagerFactory) + final MqttClientSslConfig sslConfig = MqttClientSslConfig.builder().keyManagerFactory(keyManagerFactory) + .trustManagerFactory(trustManagerFactory) .build(); Random random = new Random(); diff --git a/tests/src/test/resources/mtls/ca.cer b/tests/src/test/resources/mtls/ca.cer new file mode 100644 index 000000000..0fd518e1f --- /dev/null +++ b/tests/src/test/resources/mtls/ca.cer @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDEDCCAfigAwIBAgIUMsRb5hhnGL727b9Lbdj/kVI2H1cwDQYJKoZIhvcNAQEL +BQAwETEPMA0GA1UEAwwGUk9PVENBMB4XDTI0MDgyMzEwNTcxN1oXDTM0MDgyMTEw +NTcxN1owETEPMA0GA1UEAwwGUk9PVENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAoEpINahEpHzitKLvYJYuEGz1lDrdLqxbV39P2Lkxy9o+4nunNvwH +1dT3e0FBEzNBmA1ply0465MXGoTzljgnugeit2hfAfYTYLoDWZnKXfEz6qs1Oe4/ +K9LanD+W30nzoE5huq9jsoxHX6FDDu7driV/U+ffxGzYEteVAHj6EpwdOdLjW2uV +zDlL5V23NR3sSI23xIbIKng6/U6t8SSX70gCM7HG38KK8LzBDcaz10tixVQ0vtIm +g+xkNoDG1re21e6hI6Q62KNQqzygqEQ7AzbW0fe2M8RdviFGe2UW131FqD0DQ3J8 +C2F5aq6bjWPZc7vr/HQJf4n4od1P9cSg5QIDAQABo2AwXjAdBgNVHQ4EFgQUlwCH +1eZpUIPJWoAaFjn2GpUNiWcwHwYDVR0jBBgwFoAUlwCH1eZpUIPJWoAaFjn2GpUN +iWcwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAYYwDQYJKoZIhvcNAQELBQAD +ggEBAHcjg7XIVgjKwAq79FVDc+l53YDpw0PpGvL6mI29Wrp2cR2gx0A89hyXGfZD +SxxWmQyx2Z/S+bocaJdJrFIikA1XgHD2LQYjLx2D5ONM8uFcsM1KfPcCAc18D0Y4 +o1lAkC4rk/b/Mv9OKGjtvpwHxDpgoXVBR4yFE9h9dvpOvae8pOPWpeY/P2dEVOo/ +1N7bc8K/yhOjdT/umB1x3xdpTX6mO90tzDSjWerCJTUZgADjHui5N8CHc4RH9+1b +xQNPFBIXgHi/UOYD6ekxoAfbnoAjC3BBKwsICnBDz6qX07uSl/5zbXl06CFWnOQr +O9LMX4bSgPDmi437cnBB0np3NvA= +-----END CERTIFICATE----- diff --git a/tests/src/test/resources/mtls/ca.crt b/tests/src/test/resources/mtls/ca.crt new file mode 100644 index 000000000..e0203cd22 --- /dev/null +++ b/tests/src/test/resources/mtls/ca.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDEDCCAfigAwIBAgIUEJ+TKT+jKJrdq1wAsjhIukssB04wDQYJKoZIhvcNAQEL +BQAwETEPMA0GA1UEAwwGUk9PVENBMB4XDTI0MDgyMzEwNTA1OFoXDTM0MDgyMTEw +NTA1OFowETEPMA0GA1UEAwwGUk9PVENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAoEpINahEpHzitKLvYJYuEGz1lDrdLqxbV39P2Lkxy9o+4nunNvwH +1dT3e0FBEzNBmA1ply0465MXGoTzljgnugeit2hfAfYTYLoDWZnKXfEz6qs1Oe4/ +K9LanD+W30nzoE5huq9jsoxHX6FDDu7driV/U+ffxGzYEteVAHj6EpwdOdLjW2uV +zDlL5V23NR3sSI23xIbIKng6/U6t8SSX70gCM7HG38KK8LzBDcaz10tixVQ0vtIm +g+xkNoDG1re21e6hI6Q62KNQqzygqEQ7AzbW0fe2M8RdviFGe2UW131FqD0DQ3J8 +C2F5aq6bjWPZc7vr/HQJf4n4od1P9cSg5QIDAQABo2AwXjAdBgNVHQ4EFgQUlwCH +1eZpUIPJWoAaFjn2GpUNiWcwHwYDVR0jBBgwFoAUlwCH1eZpUIPJWoAaFjn2GpUN +iWcwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAYYwDQYJKoZIhvcNAQELBQAD +ggEBACh6PR76yNLMErrEqZcUhJngOQK0yZR9zjcDoAM4YDSx/qHP/rZA9j2HJdVz +oPAf1rU7QGmMojyQ7sj0jtViWtX9QJFtPcCR8vnwONDyC4hOwNAWLx9TeRp6ZZVL +Y8TN9ydo3jTj4ZjG9rPzQBH3+vErr+WtuIK5H5AvQCzRZPv1r78FBdhA6uQtm6EV +WZ81xJPLQirIDl7yWtCkE+325pOW8J48I6wa3EG/30quXjcaGzlPCAQMGsyjPBvC +m4c8dtEYbYEynMdRDhvgd3OI91L6eeGvEMQvOrLJWtB1zDHZ1xleHmNkBV625UTX +h+Ojtlo/0Nlw3mPABR/B++Rdeo8= +-----END CERTIFICATE----- diff --git a/tests/src/test/resources/mtls/ca.key b/tests/src/test/resources/mtls/ca.key new file mode 100644 index 000000000..f846ae7c3 --- /dev/null +++ b/tests/src/test/resources/mtls/ca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCgSkg1qESkfOK0 +ou9gli4QbPWUOt0urFtXf0/YuTHL2j7ie6c2/AfV1Pd7QUETM0GYDWmXLTjrkxca +hPOWOCe6B6K3aF8B9hNgugNZmcpd8TPqqzU57j8r0tqcP5bfSfOgTmG6r2OyjEdf +oUMO7t2uJX9T59/EbNgS15UAePoSnB050uNba5XMOUvlXbc1HexIjbfEhsgqeDr9 +Tq3xJJfvSAIzscbfworwvMENxrPXS2LFVDS+0iaD7GQ2gMbWt7bV7qEjpDrYo1Cr +PKCoRDsDNtbR97YzxF2+IUZ7ZRbXfUWoPQNDcnwLYXlqrpuNY9lzu+v8dAl/ifih +3U/1xKDlAgMBAAECggEAANcS1NEqdvA+ofK+rXNsD2L60ImUcjOuEOHWcczasXZV +4QsD39pnUhwZJfi8FhUtMVZUqNmwVC/DrbxnqHBn6OY0WKC/6rs288lVzijrsh1b +B85Y65JPm3Ox+KKusEHreHogsgFMVPm+QAaQ2umumMSSi8aJ2jY11bdyjPuVV/ae +YeFxs7C6Mk9uTb9KvESxjfxk0rOznXX5WGZLy1p4F2o1NX8I1ueVneeR7h5fDlzF +Tedl+BSU86JT1AFdbhsZJhzGShLPILACGQX6Rteim+C0sJyykuHQy+vh6/LKnYbW +j+JUkJWP3Hdk8gPyxwJ2foYh7Hw725RlPY5JlGtaYQKBgQDX4yf4UeuGgtNhGvVX +WshUrO37zlKsMu8FWBTyTfudDVcbcojeU8Kv0vW7PlCfyCvXnFE80/ipL/zedHYf +ZVCaZEPA+rOeCdBgVZ3FY59lw1h1DwQqYybwj/IuSzw3AqQ5f9tzxNG7noxdFX1T +BrY4VHbFYWPEMJJc5v2zGgALkQKBgQC+EprVUvZE6wbPdKFmg++fTKnwDybUrDKH +uB/garImkTqXOzPWVUdiw3XpWXvpCCwWxJ8yb9eaO4GfmCmhgKjgql1w2vxjDVNI +/3xZubeAR3WfAmIUgzB76L2Oz9xvzc1t/rnpvGQNihSGOnEogsXZBvRT+raVMPe+ +DHWu9qXOFQKBgAw2Gh2urI7YOZKljrkZNnmrqm5y1jRNUT3RJKYsCQ5yIbo4uUsy +G7IMUb/8n1zaWriAbAvvxYH0Z+5BUikmdu+0uixhQeWvkmzQivMOVobQDOHaLpcj +MqGq0r0Rnl9SM+3YsJYUzPQ63J+rRoJ6v7Xh+THi91yyjqTYoAMQdm4xAoGBAIYb +WmNpRZkaupNlFvvd2xPqY3ydNCiZ1o0rvFH69feAQHazrr9rLBLjFi6ulF63BWSL +Fkff4Z9QnQSdt8HbpUve6E7YM3svy7OVj4c/IdnAkZy/cbRHW84RSK2au02nR2p0 +b3gbE/z5j8GlOnH60t1tqrYWDvz0r9fHssDgBdyBAoGBAKB8sZCKpyKL66weEz+H +LFAqw+Fm3MdXFLx9tRm/0H0jlZXWviViYvbT1A+gZFMDqlX6Ivqxcxy/W0a3BXMn +9QKYMJFvbOjCI4qh+M/eyEofOtEAh/c5x7g1MYPaE08YaxoFyutP8MJszvWjnsuq +NgdFFE0gyRsHGmJdCDQ5dmVi +-----END PRIVATE KEY----- diff --git a/tests/src/test/resources/mtls/ca.srl b/tests/src/test/resources/mtls/ca.srl new file mode 100644 index 000000000..e46db4553 --- /dev/null +++ b/tests/src/test/resources/mtls/ca.srl @@ -0,0 +1 @@ +1EA9E0336372A6164A1F22BFB7C56CD4EA142F9F diff --git a/tests/src/test/resources/mtls/ca_config.cnf b/tests/src/test/resources/mtls/ca_config.cnf new file mode 100644 index 000000000..6c1edb524 --- /dev/null +++ b/tests/src/test/resources/mtls/ca_config.cnf @@ -0,0 +1,15 @@ +[ req ] +default_bits = 2048 +prompt = no +default_md = sha256 +distinguished_name = dn +x509_extensions = v3_ca + +[ dn ] +CN = ROOTCA + +[ v3_ca ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical,CA:true +keyUsage = digitalSignature, cRLSign, keyCertSign diff --git a/tests/src/test/resources/mtls/client.cer b/tests/src/test/resources/mtls/client.cer new file mode 100644 index 000000000..36f70ea7d --- /dev/null +++ b/tests/src/test/resources/mtls/client.cer @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC9DCCAdygAwIBAgIUHqngM2NyphZKHyK/t8Vs1OoUL58wDQYJKoZIhvcNAQEL +BQAwETEPMA0GA1UEAwwGUk9PVENBMCAXDTI0MDgyMzEwNTgzNloYDzIxMjQwNzMw +MTA1ODM2WjARMQ8wDQYDVQQDDAZDTElFTlQwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC0S6AnsYUBJJP3ZiOqPdqvjW4nbslKvTYFo2tfLnobOakuSKyD +Iisx9FlUHLFMslL3QZ6mp/U8pmZU6YORWo/f6eElLuGtQPSVxqTEZH0v+GY8N8HA +XshvXmh7CSkGFzbKJ9vyAN2rZ/XrgEP3bBSQZxVSloLaNjV+lXzs3JaULxvQL+EJ +ef38RC//qI7qPflaNveIpnaCpG+Rx8QnFDYeyi8BDS2PdeKwLzj4aXaW5qjoBC3v +qk9/XLqxMXTAX8Ty32E7HrgxhG0mA48gYg2T/Ba8RPykNGvM/cncRgC+B0IJJ1jY +XAgdg/C5Xsz7DveWeezWibripMQN0UrkTjcLAgMBAAGjQjBAMB0GA1UdDgQWBBQY +djFGcYoRFXb7lyZkoFqQJnML1DAfBgNVHSMEGDAWgBSXAIfV5mlQg8lagBoWOfYa +lQ2JZzANBgkqhkiG9w0BAQsFAAOCAQEAiATbrV3/uIuIJQbXBssuVOlTcUWXPAHf +bFGz31NgPnb0za2ApoJ+912orSxSAvlG10g+2Z34iW8+bciH8e1DF+cPQKVg0lkm +jaMQO1cUVw6e2aRHagIMvgEwcz+PqVJoLvWWp5sjqnlafu/ZuXjzeyefuFbxD3kI +EAuSp4juklHrjLZbDulUgGuodKnJ/plzRLKUYoKArdmCAulZRmxcKBw6oYjQWo3A +6lLLHgqaV2g2RuAQFP6qCTMGEWXu4F8ZWJC6vV0zEDMh6QKJdNH1RShbsWlfIxsW +TU6Pswt9EyDIo2Wd72n/sAC8pFxvM8tfhFsAOihHB1XBb2YhtNCORQ== +-----END CERTIFICATE----- diff --git a/tests/src/test/resources/mtls/client.csr b/tests/src/test/resources/mtls/client.csr new file mode 100644 index 000000000..0be3c4a35 --- /dev/null +++ b/tests/src/test/resources/mtls/client.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICVjCCAT4CAQAwETEPMA0GA1UEAwwGQ0xJRU5UMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtEugJ7GFASST92Yjqj3ar41uJ27JSr02BaNrXy56Gzmp +LkisgyIrMfRZVByxTLJS90Gepqf1PKZmVOmDkVqP3+nhJS7hrUD0lcakxGR9L/hm +PDfBwF7Ib15oewkpBhc2yifb8gDdq2f164BD92wUkGcVUpaC2jY1fpV87NyWlC8b +0C/hCXn9/EQv/6iO6j35Wjb3iKZ2gqRvkcfEJxQ2HsovAQ0tj3XisC84+Gl2luao +6AQt76pPf1y6sTF0wF/E8t9hOx64MYRtJgOPIGINk/wWvET8pDRrzP3J3EYAvgdC +CSdY2FwIHYPwuV7M+w73lnns1om64qTEDdFK5E43CwIDAQABoAAwDQYJKoZIhvcN +AQELBQADggEBAIoQFcm5h17AMtuZ2hdERwptzzQ8HxOC6Eb3NpfItRHLDKKMSuD9 +WZPixwz/53uF4jlcN+Uc5AONSKognp70pR3Ku9G47cEBb/iYF20OU6nd6a9+X4wr +r9SwkS/FlNb3A1UM0HuO9pXX3Raq3WR04gSWdJ2S7gbGWJp5vJiHbEwbIqb05lYG +sRdkVlJdGRbPmpVJmPib3wMidbm8K8SzLIDyLyTiMl92z7dBZq83tYAKdZ7D0TEb +k4rKu19Wi+EkOVe9qSdzWlgXLoNxct4rxpqbrWUg8DROtWFyQLA4WvjDzRnxFJgU +fhYb2IQXM1GUhNLGAdJOu8iaV2Dpd7fPGSw= +-----END CERTIFICATE REQUEST----- diff --git a/tests/src/test/resources/mtls/client.key b/tests/src/test/resources/mtls/client.key new file mode 100644 index 000000000..7d95fe83d --- /dev/null +++ b/tests/src/test/resources/mtls/client.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC0S6AnsYUBJJP3 +ZiOqPdqvjW4nbslKvTYFo2tfLnobOakuSKyDIisx9FlUHLFMslL3QZ6mp/U8pmZU +6YORWo/f6eElLuGtQPSVxqTEZH0v+GY8N8HAXshvXmh7CSkGFzbKJ9vyAN2rZ/Xr +gEP3bBSQZxVSloLaNjV+lXzs3JaULxvQL+EJef38RC//qI7qPflaNveIpnaCpG+R +x8QnFDYeyi8BDS2PdeKwLzj4aXaW5qjoBC3vqk9/XLqxMXTAX8Ty32E7HrgxhG0m +A48gYg2T/Ba8RPykNGvM/cncRgC+B0IJJ1jYXAgdg/C5Xsz7DveWeezWibripMQN +0UrkTjcLAgMBAAECggEAQ8Q9IU5HGMPf3diFRULUhLGbGrU4caAmwv3GqNL2UG9e +2Ke2N9/K7o7SWJwkRBiuuILwl+F/etlskzPmIOcyNs5YsropVw6YIAe2/J5ss3Ah +NTcb2yuFGN8aVEyAH+rvzBIpSI/swbVkqKzgXwo/vHsSd6Vc75n6h2a2uuy6qF1f +C4Jr1XXD4TBFRxzfdxpJOZlEHlDQ7Qj9csrHNrrN3QUtFzIPV8XYqAxqd/aoRkXL +VnmTZSH2fJvQR1XWdEcvLF9okulczUdTw0wUrYJAEh+rzhiGY/At3A1UVtzwqprZ +hVv866sC6PYY8q/tOCkTphBK5efzZ04dhJTNtKWqyQKBgQDYy7IsDFtDOmTQCL2h +sRO7qd+QBRnaIWNy6dcfo1WWGdsfBF8CpEnENBDaUT1v7NHYxkZdDeVeufXX6PDv +m55Yaz3NXC0kHyhH0PpWIhtOjEzCiyocdohiZalTFG+1sbpp7/XIagU+Vgoynotm +Nd0FipskzQmNbno8QWwZz4FxzQKBgQDU5jEe4TsGYmz6pLiphsIqm/ovndqAJ74G +dV4Q3Lm+qzQ79EAa1StYd05eG9EZWdbwkxgToulO3ANTh5PxgXCwmGYSAzGO2RXO ++/kv6hhBFsxgd8Ve+9AfLx1Wd9e2IJoUkhBwr3BRFIv2MhiV8PSBs4i4kidxUIZP +HDJJNUXUNwKBgQCC9cGClFBI8yxU8wLCevqFoZ9YG4y7VPIDR7jY9szLqIDSYsyW +BvI8oIsRpoOrae51uYhly/Aj4cfdjmyFAYeMt/OUazsll+C4SUf/4giG0X/JAVIF +8aB/eBPqCO1WX69RMVBSqaDTQBxW6akhrCYAo/MGLwm3MuaKIacQjGYQfQKBgC9r +OgObvO7WG1nUOIEhz7t31EioyxMCRxPfLl1pHEH4lgDIjUKsuiPRJvZVEcSouvQI +fzNYdMiovmDrcKs43mWm/A0FAxPDDFV2z/C5Hj/ZGRpfcumOArP/ZXRt6vDY4Bi2 +08yVdtnITsg+LjWvXnZJC6m4e+qEOfYC3LxrjisPAoGAUH1jW7oGLXUY/4YJpbRe +RNuRjX7K8ynJ/ztwsTFPM8AIl0lEdwdi1U6/Fo6CT1ls7jBPASOt8KCmYg9g8us5 +SWhMKvRD6ryWFqpOJUDQq3b7N2illdNW/kACi8aI5Ghup56iZT7yq+J+h0jxlj9y +gbL73lKp6ZOHeGKBOqDJLhI= +-----END PRIVATE KEY----- diff --git a/tests/src/test/resources/mtls/client.p12 b/tests/src/test/resources/mtls/client.p12 new file mode 100644 index 0000000000000000000000000000000000000000..bffb931b535ede54286564914188716961e2d2a2 GIT binary patch literal 2531 zcmai$X*3&%8ipkzL=&}dwZvAHqRB{&t(GE`GPWYIlv)NgLKU?Y(IRLu6-%p%+Lzke z)Eac5+8SahDoPP95_|3Bnse{z{G1=(`Of>kKfYh@b3P;iG6e*%BMA@^7=lPJP1u0} zH~|F&NCJoeA)MHEkp%Xoe^Nhr{I7gZIGycBorwR;w{t& z;W1=|D;7s}4c?>6_X2@jY)B}W>wi~)5Dqq^BpBkBU<&YJ2LTWuUc-JX-=}L{%hn@d z0f3Aty;uUfo7*2vrCP$tFg$o+5_YF^cc?&(<97u%as#}yk2v6gwltLk)})xs6MKr} zZQ?{I6x-^Iki|b2iqdz__UI0duBVyrC_MGl7~F$K zWi$vGY$N6RJ}=?j#gskI937uNL#FmS7}?7{7prmAJ-wQ%^J97>j|IlmL@TyHjg?xwA&_cXiet@%MHCNPo5zfZ z&9ks7&IzO8;K}m`Gd*bVdrbRZA&FTUW@D5rL#Jc1whY1`68rK1%;$FK@TGp16N=nw z*yqWlTqlPCm7FA+RM$ie$<286#lw=c_4MUT2Rt&54Z~rq*!`e2T3jLNY0+_&7Ftc= zQ)%>@Aj_lsoR`x+=tRSH&9j%Qi3Joho>SLsaM^;C#zEhiJ(BTneYCGpyP__(lG8ki zHMx1+-<2r2EZe#&6`$E?wUm9AY0g*xb!$j#5F78tU%nn3Q1#IjIbEny++ zf%kjhoGP)5LULySHY3yf^LY^=fiMHPDQoq2NaWfMptjb1Fzob}41u;EC%8K$p87=cldgU_Q3N|@F=n=Rq!Jy2YjB8;ll)OO zF$vX}Q3aF<$n2NtsFuQixoN~i%t|*_O5Y4ooRwXS6tku&-3SN!lR(V%55~a_{%#Z>QBnB(Z@wB!MIKXK()o0Y@~5z!838 zhn!3h_|*Ry0p$h&PeRQT^Wwi1Uk<}vJZH~1Q=97TAw3Jr_}AhmnaE4?X=d>ki|7Yb zral?~5kLdlhw_)gHM>Cd%%q_vla^}P_Wav=(4ymq6U_p?IpN}R_eL1>cRP>HCo$S} zhCF3-Yn7jB`Sl40m~F>fhG*mRXnsMxZ2I|YgORCP3w+FbIUJ|sOmehbu5)T8yd*D6 z4u!sg&6a3{lflZEv$ICe*-E^^>ieL42Z6h# z`=-1c_)i4tUUK_wgLerbo!OG zMb-5tJ_x04@=#u9sy@HLE3lNf&wy8rb(bo{)mzU*IAhq< z>3I_4x6V=){MWjQ$da?3sYE%%Xff>0cbedeV90R{9h;e;73%arq*CB9^M<7I>AUK* z_F8-gYld5>7JO4hD)iJ9^X8tp4;XSCX!M0cnH<*@f zn`PmHS$E>6WvBkbM^uJ`Yc6}SL!0*y<<;IJo+!&tyJ%xAvaHU! zupvlkutgyN)CQ^XhGhD$XLP3n!#6Bfzr!G9mqZ_ovY)*rZ9P;_A=E4bQOQFZp{WXL z3x|8*PsRzyJ#Gvv5cP0|~6PQ1HaAc-c5vOkl)5-~jBEWrql=F6kv2qNJ(jJ9}nBBUXI7@7Uw?V8%;KS!Z<1^S&P`1RrGS+C30jB{ zN*E+q%RqOK+YU>0nwn8H0whse=J`sb0TP9T{d|jn01h?~yk!VN`?5wy6|+lBymp$L h>T~YS50VgzgX$&jZZ$CEL0r@Y*9@zR0>gi!_P% literal 0 HcmV?d00001 diff --git a/tests/src/test/resources/mtls/clientkeystore.jks b/tests/src/test/resources/mtls/clientkeystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..a5033dc9f1398d5f4688358f9fa468055382d371 GIT binary patch literal 2107 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 f^t{x#_@Vvi)6$|0jUX_)^ literal 0 HcmV?d00001 diff --git a/tests/src/test/resources/mtls/serverkeystore.jks b/tests/src/test/resources/mtls/serverkeystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..6f9e628d3b89b9a51570da16dbe72041747a2d45 GIT binary patch literal 2110 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 YVfGr#=%_Z{n_~4?*xk_CWy5XkBdssI20 literal 0 HcmV?d00001 From b8bf531b3c8080902f57c67e5dd49ca154a70005 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Mon, 26 Aug 2024 21:12:40 +0800 Subject: [PATCH 12/23] fix test --- .../MQTTProxyProtocolMethodProcessor.java | 19 ++++ .../MQTTBrokerProtocolMethodProcessor.java | 33 +++++- .../handlers/mqtt/utils/MqttMessageUtils.java | 85 +++++++++++++- .../pulsar/handlers/mqtt/utils/MqttUtils.java | 4 + .../mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java | 106 +++++++++--------- 5 files changed, 188 insertions(+), 59 deletions(-) diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java index f40e24609..38f4521fb 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java @@ -15,6 +15,8 @@ import static io.streamnative.pulsar.handlers.mqtt.Constants.MTLS; import static io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils.createMqttConnectMessage; +import static io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils.createMqttPublishMessage; +import static io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils.createMqttSubscribeMessage; import com.google.common.collect.Lists; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.mqtt.MqttConnectMessage; @@ -145,6 +147,15 @@ public void doProcessConnect(MqttAdapterMessage adapter, String userRole, .processor(this) .build(); connection.sendConnAck(); +// if (MqttUtils.isMqtt5(msg.variableHeader().version()) && getMtlsAuthMethodAndData(msg).isPresent()) { +// MqttConnectMessage connectMessage = createMqttConnectMessage(msg, MTLS, userRole); +// msg = connectMessage; +// connection.setConnectMessage(msg); +// } else if (MqttUtils.isMqtt3(msg.variableHeader().version()) && proxyConfig.isMqttProxyMtlsEnabled()) { +// MqttConnectMessage connectMessage = createMqttConnectMessage(msg, MTLS, userRole); +// msg = connectMessage; +// connection.setConnectMessage(msg); +// } if (proxyConfig.isMqttProxyMtlsEnabled()) { MqttConnectMessage connectMessage = createMqttConnectMessage(msg, MTLS, userRole); msg = connectMessage; @@ -178,6 +189,10 @@ public void processPublish(MqttAdapterMessage adapter) { proxyConfig.getDefaultTenant(), proxyConfig.getDefaultNamespace(), TopicDomain.getEnum(proxyConfig.getDefaultTopicDomain())); adapter.setClientId(connection.getClientId()); + if (proxyConfig.isMqttProxyMtlsEnabled()) { + MqttPublishMessage mqttMessage = createMqttPublishMessage(msg, MTLS, connection.getUserRole()); + adapter.setMqttMessage(mqttMessage); + } startPublish() .thenCompose(__ -> writeToBroker(pulsarTopicName, adapter)) .whenComplete((unused, ex) -> { @@ -308,6 +323,10 @@ public void processSubscribe(final MqttAdapterMessage adapter) { log.debug("[Proxy Subscribe] [{}] msg: {}", clientId, msg); } registerTopicListener(adapter); + if (proxyConfig.isMqttProxyMtlsEnabled()) { + MqttSubscribeMessage mqttMessage = createMqttSubscribeMessage(msg, MTLS, connection.getUserRole()); + adapter.setMqttMessage(mqttMessage); + } doSubscribe(adapter, false) .exceptionally(ex -> { Throwable realCause = FutureUtil.unwrapCompletionException(ex); diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java index 18d335915..ed7a51e7f 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java @@ -14,6 +14,7 @@ package io.streamnative.pulsar.handlers.mqtt.support; import static io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils.createWillMessage; +import static io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils.getMtlsAuthMethodAndData; import static io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils.pingResp; import static io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils.topicSubscriptions; import io.netty.channel.ChannelHandlerContext; @@ -78,7 +79,9 @@ import org.apache.bookkeeper.mledger.Position; import org.apache.bookkeeper.mledger.PositionFactory; import org.apache.bookkeeper.mledger.impl.AckSetStateUtil; +import org.apache.commons.lang3.tuple.Pair; import org.apache.pulsar.broker.PulsarService; +import org.apache.pulsar.broker.authentication.AuthenticationDataCommand; import org.apache.pulsar.broker.authentication.AuthenticationDataSource; import org.apache.pulsar.broker.authorization.AuthorizationService; import org.apache.pulsar.broker.service.BrokerServiceException; @@ -199,19 +202,28 @@ public void processPubAck(MqttAdapterMessage adapter) { @Override public void processPublish(MqttAdapterMessage adapter) { if (log.isDebugEnabled()) { - log.debug("[Publish] [{}] msg: {}", connection.getClientId(), adapter); + log.debug("[Publish] [{}] msg: {}", adapter.getClientId(), adapter); } MqttPublishMessage msg = (MqttPublishMessage) adapter.getMqttMessage(); CompletableFuture result; if (!configuration.isMqttAuthorizationEnabled()) { if (log.isDebugEnabled()) { log.debug("[Publish] authorization is disabled, allowing client. CId={}, userRole={}", - connection.getClientId(), connection.getUserRole()); + adapter.getClientId(), connection.getUserRole()); } result = doPublish(adapter); } else { + String userRole = connection.getUserRole(); + AuthenticationDataSource authData = connection.getAuthData(); + if (adapter.fromProxy()) { + final Optional> mtlsAuthMethodAndData = getMtlsAuthMethodAndData(msg); + if (mtlsAuthMethodAndData.isPresent()) { + userRole = mtlsAuthMethodAndData.get().getKey(); + authData = new AuthenticationDataCommand(new String(mtlsAuthMethodAndData.get().getValue())); + } + } result = this.authorizationService.canProduceAsync(TopicName.get(msg.variableHeader().topicName()), - connection.getUserRole(), connection.getAuthData()) + userRole, authData) .thenCompose(authorized -> authorized ? doPublish(adapter) : doUnauthorized(adapter)); } result.thenAccept(__ -> msg.release()) @@ -359,7 +371,7 @@ public boolean connectionEstablished() { public void processSubscribe(MqttAdapterMessage adapter) { MqttSubscribeMessage msg = (MqttSubscribeMessage) adapter.getMqttMessage(); final String clientId = connection.getClientId(); - final String userRole = connection.getUserRole(); + String userRole = connection.getUserRole(); final int packetId = msg.variableHeader().messageId(); if (log.isDebugEnabled()) { log.debug("[Subscribe] [{}] msg: {}", clientId, msg); @@ -370,15 +382,24 @@ public void processSubscribe(MqttAdapterMessage adapter) { } doSubscribe(msg); } else { + AuthenticationDataSource authData = connection.getAuthData(); + if (adapter.fromProxy()) { + final Optional> mtlsAuthMethodAndData = getMtlsAuthMethodAndData(msg); + if (mtlsAuthMethodAndData.isPresent()) { + userRole = mtlsAuthMethodAndData.get().getKey(); + authData = new AuthenticationDataCommand(new String(mtlsAuthMethodAndData.get().getValue())); + } + } List> authorizationFutures = new ArrayList<>(); AtomicBoolean authorizedFlag = new AtomicBoolean(true); for (MqttTopicSubscription topic: msg.payload().topicSubscriptions()) { + String finalUserRole = userRole; authorizationFutures.add(this.authorizationService.canConsumeAsync(TopicName.get(topic.topicName()), - userRole, connection.getAuthData(), userRole).thenAccept((authorized) -> { + userRole, authData, userRole).thenAccept((authorized) -> { if (!authorized) { authorizedFlag.set(false); log.warn("[Subscribe] no authorization to sub topic={}, userRole={}, CId= {}", - topic.topicName(), userRole, clientId); + topic.topicName(), finalUserRole, clientId); } })); } diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java index fa9e32364..ed6c23af6 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java @@ -15,6 +15,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE; +import static io.streamnative.pulsar.handlers.mqtt.Constants.MTLS; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.handler.codec.mqtt.MqttConnectMessage; @@ -22,20 +23,25 @@ import io.netty.handler.codec.mqtt.MqttConnectVariableHeader; import io.netty.handler.codec.mqtt.MqttFixedHeader; import io.netty.handler.codec.mqtt.MqttMessage; +import io.netty.handler.codec.mqtt.MqttMessageIdAndPropertiesVariableHeader; import io.netty.handler.codec.mqtt.MqttMessageType; import io.netty.handler.codec.mqtt.MqttProperties; import io.netty.handler.codec.mqtt.MqttPublishMessage; +import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; import io.netty.handler.codec.mqtt.MqttQoS; import io.netty.handler.codec.mqtt.MqttSubscribeMessage; import io.netty.handler.codec.mqtt.MqttTopicSubscription; +import io.netty.handler.codec.mqtt.MqttVersion; import io.streamnative.pulsar.handlers.mqtt.support.MessageBuilder; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang3.tuple.Pair; /** * Mqtt message utils. @@ -193,8 +199,9 @@ public static MqttConnectMessage createMqttConnectMessage(MqttConnectMessage con properties.add(new MqttProperties.BinaryProperty(MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value() , authData.getBytes())); MqttConnectVariableHeader variableHeader = new MqttConnectVariableHeader( - header.name(), header.version(), header.hasUserName(), header.hasPassword(), header.isWillRetain(), - header.willQos(), header.isWillFlag(), header.isCleanSession(), header.keepAliveTimeSeconds(), + header.name(), MqttVersion.MQTT_5.protocolLevel(), header.hasUserName(), header.hasPassword(), + header.isWillRetain(), header.willQos(), header.isWillFlag(), header.isCleanSession(), + header.keepAliveTimeSeconds(), properties ); MqttConnectMessage newConnectMessage = new MqttConnectMessage(connectMessage.fixedHeader(), variableHeader, @@ -202,6 +209,80 @@ public static MqttConnectMessage createMqttConnectMessage(MqttConnectMessage con return newConnectMessage; } + public static MqttPublishMessage createMqttPublishMessage(MqttPublishMessage publishMessage, + String authMethod, + String authData) { + final MqttPublishVariableHeader header = publishMessage.variableHeader(); + MqttProperties properties = new MqttProperties(); + properties.add(new MqttProperties.StringProperty(MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value() + , authMethod)); + properties.add(new MqttProperties.BinaryProperty(MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value() + , authData.getBytes())); + MqttPublishVariableHeader variableHeader = new MqttPublishVariableHeader( + header.topicName(), header.packetId(), properties); + MqttPublishMessage newPublishMessage = new MqttPublishMessage(publishMessage.fixedHeader(), variableHeader, + publishMessage.payload()); + return newPublishMessage; + } + + public static Optional> getMtlsAuthMethodAndData(MqttConnectMessage connectMessage) { + final MqttConnectVariableHeader header = connectMessage.variableHeader(); + MqttProperties properties = header.properties(); + final MqttProperties.MqttProperty property = properties.getProperty( + MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value()); + if (property != null && property.value() instanceof String + && ((String) property.value()).equalsIgnoreCase(MTLS)) { + final MqttProperties.MqttProperty data = properties.getProperty( + MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value()); + return Optional.of(Pair.of((String) property.value(), (byte[]) data.value())); + } + return Optional.empty(); + } + + public static Optional> getMtlsAuthMethodAndData(MqttPublishMessage publishMessage) { + final MqttPublishVariableHeader header = publishMessage.variableHeader(); + MqttProperties properties = header.properties(); + final MqttProperties.MqttProperty property = properties.getProperty( + MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value()); + if (property != null && property.value() instanceof String + && ((String) property.value()).equalsIgnoreCase(MTLS)) { + final MqttProperties.MqttProperty data = properties.getProperty( + MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value()); + return Optional.of(Pair.of((String) property.value(), (byte[]) data.value())); + } + return Optional.empty(); + } + + public static Optional> getMtlsAuthMethodAndData(MqttSubscribeMessage subscribeMessage) { + final MqttMessageIdAndPropertiesVariableHeader header = subscribeMessage.idAndPropertiesVariableHeader(); + MqttProperties properties = header.properties(); + final MqttProperties.MqttProperty property = properties.getProperty( + MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value()); + if (property != null && property.value() instanceof String + && ((String) property.value()).equalsIgnoreCase(MTLS)) { + final MqttProperties.MqttProperty data = properties.getProperty( + MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value()); + return Optional.of(Pair.of((String) property.value(), (byte[]) data.value())); + } + return Optional.empty(); + } + + public static MqttSubscribeMessage createMqttSubscribeMessage(MqttSubscribeMessage subscribeMessage, + String authMethod, + String authData) { + final MqttMessageIdAndPropertiesVariableHeader header = subscribeMessage.idAndPropertiesVariableHeader(); + MqttProperties properties = new MqttProperties(); + properties.add(new MqttProperties.StringProperty(MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value() + , authMethod)); + properties.add(new MqttProperties.BinaryProperty(MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value() + , authData.getBytes())); + MqttMessageIdAndPropertiesVariableHeader variableHeader = new MqttMessageIdAndPropertiesVariableHeader( + header.messageId(), properties); + MqttSubscribeMessage newSubscribeMessage = new MqttSubscribeMessage(subscribeMessage.fixedHeader(), + variableHeader, subscribeMessage.payload()); + return newSubscribeMessage; + } + public static MqttMessage createMqttDisconnectMessage() { return MessageBuilder.disconnect().build(); } diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttUtils.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttUtils.java index c33529516..b64b851e7 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttUtils.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttUtils.java @@ -42,6 +42,10 @@ public static boolean isMqtt3(int version) { public static boolean isNotMqtt3(int version) { return !isMqtt3(version); } + + public static boolean isMqtt5(int version) { + return version == MqttVersion.MQTT_5.protocolLevel(); + } public static boolean isQosSupported(MqttConnectMessage msg) { return isQosSupported(msg.fixedHeader().qosLevel()); } diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java index 3553948bd..f48783035 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java @@ -36,7 +36,6 @@ import java.util.Optional; import java.util.Properties; import java.util.Random; -import java.util.UUID; import java.util.concurrent.TimeUnit; import javax.crypto.SecretKey; import javax.net.ssl.KeyManagerFactory; @@ -50,12 +49,12 @@ import org.apache.pulsar.common.util.SecurityUtility; import org.fusesource.mqtt.client.BlockingConnection; import org.fusesource.mqtt.client.MQTT; +import org.fusesource.mqtt.client.Message; import org.fusesource.mqtt.client.QoS; import org.fusesource.mqtt.client.Topic; import org.testng.Assert; import org.testng.annotations.Test; - public class ProxyMtlsTest extends MQTTTestBase { @@ -121,7 +120,7 @@ public SSLContext createSSLContext() throws Exception { Certificate caCert = CertificateFactory .getInstance("X.509").generateCertificate(new FileInputStream(caCertFile)); - File clientCertFile = new File(path + "client.crt"); + File clientCertFile = new File(path + "client.cer"); Certificate clientCert = CertificateFactory .getInstance("X.509").generateCertificate(new FileInputStream(clientCertFile)); @@ -133,50 +132,24 @@ public SSLContext createSSLContext() throws Exception { return sslContext; } - public SSLContext createSSLContext2() throws Exception { - KeyStore keyStore = KeyStore.getInstance("PKCS12"); - keyStore.load(new FileInputStream(path + "client.p12"), "".toCharArray()); - - KeyStore trustStore = KeyStore.getInstance("PKCS12"); - trustStore.load(new FileInputStream(path + "ca.p12"), "".toCharArray()); - - // 初始化密钥管理器 - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(keyStore, "".toCharArray()); - - // 初始化信任管理器 - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init(trustStore); - - final SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); - - return sslContext; - } - - @Test public void testMqtt3() throws Exception { - - - SSLContext sslContext = createSSLContext2(); + SSLContext sslContext = createSSLContext(); MQTT mqtt = createMQTTProxyTlsClient(); mqtt.setSslContext(sslContext); - String topicName = "testProduceAndConsume"; + String topicName = "mqtt3"; BlockingConnection connection = mqtt.blockingConnection(); connection.connect(); Topic[] topics = { new Topic(topicName, QoS.AT_MOST_ONCE) }; -// connection.subscribe(topics); - String message = "Hello MQTT"; + connection.subscribe(topics); + String message = "Hello MQTT3"; connection.publish(topicName, message.getBytes(), QoS.AT_MOST_ONCE, false); -// Message received = connection.receive(); -// Assert.assertEquals(received.getTopic(), topicName); -// Assert.assertEquals(new String(received.getPayload()), message); -// received.ack(); + Message received = connection.receive(); + Assert.assertEquals(received.getTopic(), topicName); + Assert.assertEquals(new String(received.getPayload()), message); + received.ack(); connection.disconnect(); - } @Test @@ -200,28 +173,59 @@ public void testMqtt5() throws Exception { .build(); Random random = new Random(); - final Mqtt5BlockingClient client = Mqtt5Client.builder() - .identifier(UUID.randomUUID().toString()) + final Mqtt5BlockingClient client1 = Mqtt5Client.builder() + .identifier("client-1") + .serverHost("localhost") + .sslConfig(sslConfig) + .serverPort(getMqttProxyPortTlsList().get(random.nextInt(getMqttProxyPortTlsList().size()))) + .buildBlocking(); + final Mqtt5BlockingClient client2 = Mqtt5Client.builder() + .identifier("client-2") .serverHost("localhost") .sslConfig(sslConfig) .serverPort(getMqttProxyPortTlsList().get(random.nextInt(getMqttProxyPortTlsList().size()))) .buildBlocking(); - String topic = "testMqtt5"; - client.connect(); - client.subscribeWith().topicFilter(topic).qos(MqttQos.AT_LEAST_ONCE).send(); - byte[] msg = "payload".getBytes(); - client.publishWith() - .topic(topic) + String topic1 = "testMqtt5-client-1"; + String topic2 = "testMqtt5-client-2"; + +// final Mqtt5UserProperties userProperties = Mqtt5UserProperties.builder().add( +// MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value() + "", Constants.MTLS).build(); +// client1.connectWith().userProperties(userProperties).send(); + client1.connect(); + client2.connect(); + client1.subscribeWith().topicFilter(topic1).qos(MqttQos.AT_LEAST_ONCE).send(); + client2.subscribeWith().topicFilter(topic2).qos(MqttQos.AT_LEAST_ONCE).send(); + byte[] msg1 = "client-1-payload".getBytes(); + byte[] msg2 = "client-2-payload".getBytes(); + client1.publishWith() + .topic(topic1) .qos(MqttQos.AT_LEAST_ONCE) - .payload(msg) + .payload(msg1) .send(); - try (Mqtt5BlockingClient.Mqtt5Publishes publishes = client.publishes(MqttGlobalPublishFilter.ALL)) { + + try (Mqtt5BlockingClient.Mqtt5Publishes publishes = client1.publishes(MqttGlobalPublishFilter.ALL)) { + System.out.println("go client1 receive"); + Mqtt5Publish publish = publishes.receive(); + Assert.assertEquals(publish.getTopic(), MqttTopic.of(topic1)); + Assert.assertEquals(publish.getPayloadAsBytes(), msg1); + } + // + client2.publishWith() + .topic(topic2) + .qos(MqttQos.AT_LEAST_ONCE) + .payload(msg2) + .send(); + try (Mqtt5BlockingClient.Mqtt5Publishes publishes = client2.publishes(MqttGlobalPublishFilter.ALL)) { + System.out.println("go client2 receive"); Mqtt5Publish publish = publishes.receive(); - Assert.assertEquals(publish.getTopic(), MqttTopic.of(topic)); - Assert.assertEquals(publish.getPayloadAsBytes(), msg); + Assert.assertEquals(publish.getTopic(), MqttTopic.of(topic2)); + Assert.assertEquals(publish.getPayloadAsBytes(), msg2); } - client.unsubscribeWith().topicFilter(topic).send(); - client.disconnect(); + client1.unsubscribeWith().topicFilter(topic1).send(); + client1.disconnect(); + client2.unsubscribeWith().topicFilter(topic1).send(); + client2.disconnect(); + System.out.println("done"); } } From 8f99d412106e9daac85b5fbad295ce8e9b04801c Mon Sep 17 00:00:00 2001 From: ran Date: Sun, 25 Aug 2024 13:39:56 +0800 Subject: [PATCH 13/23] Fix TLS initialization (#1426) (cherry picked from commit 9817118e3b17808e856e5338ae088df3b6f6a731) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e12255ec9..6c0799ad9 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ 2.22.0 6.14.3 4.0.2 - 4.0.0-ursa-5-SNAPSHOT + 4.0.0-SNAPSHOT 4.1.94.Final 2.18.0 1.16 From deabeaa90620e91b476641e4452ac1456254a4bc Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Tue, 10 Sep 2024 00:26:41 +0800 Subject: [PATCH 14/23] refactor --- .../pulsar/handlers/mqtt/Constants.java | 4 +- .../mqtt/MQTTAuthenticationService.java | 78 +++----- .../pulsar/handlers/mqtt/MQTTService.java | 15 +- .../handlers/mqtt/adapter/AdapterChannel.java | 2 +- .../AuthenticationProviderMTls.java | 1 - .../mqtt/oidc/ExpressionCompiler.java | 107 ---------- .../handlers/mqtt/oidc/OIDCPoolResources.java | 97 --------- .../handlers/mqtt/oidc/OIDCService.java | 189 ------------------ .../pulsar/handlers/mqtt/oidc/Pool.java | 41 ---- .../handlers/mqtt/oidc/PoolCompiler.java | 42 ---- .../handlers/mqtt/oidc/package-info.java | 18 -- .../MQTTProxyProtocolMethodProcessor.java | 31 +-- .../handlers/mqtt/proxy/MQTTProxyService.java | 13 -- ...AbstractCommonProtocolMethodProcessor.java | 22 +- .../MQTTBrokerProtocolMethodProcessor.java | 17 -- .../handlers/mqtt/utils/MqttMessageUtils.java | 15 +- pom.xml | 2 +- .../mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java | 30 ++- 18 files changed, 74 insertions(+), 650 deletions(-) delete mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java delete mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java delete mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java delete mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java delete mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java delete mode 100644 mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/package-info.java diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Constants.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Constants.java index 714ffe9bd..c5da59cf8 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Constants.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/Constants.java @@ -24,6 +24,8 @@ public final class Constants { public static final String AUTH_BASIC = "basic"; public static final String AUTH_TOKEN = "token"; + public static final String AUTH_MTLS = "mTls"; + public static final String ATTR_TOPIC_SUBS = "topicSubs"; public static final String MQTT_PROPERTIES = "MQTT_PROPERTIES_%d_"; @@ -45,8 +47,6 @@ public final class Constants { public static final String MQTT_SUB_PROTOCOL_CSV_LIST = "mqtt, mqttv3.1, mqttv3.1.1, mqttv5.0"; - public static final String MTLS = "mTls"; - private Constants() { } } diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java index 3fe4cf141..84637873e 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java @@ -14,19 +14,16 @@ package io.streamnative.pulsar.handlers.mqtt; import static io.streamnative.pulsar.handlers.mqtt.Constants.AUTH_BASIC; +import static io.streamnative.pulsar.handlers.mqtt.Constants.AUTH_MTLS; import static io.streamnative.pulsar.handlers.mqtt.Constants.AUTH_TOKEN; -import static io.streamnative.pulsar.handlers.mqtt.Constants.MTLS; import io.netty.handler.codec.mqtt.MqttConnectMessage; import io.netty.handler.codec.mqtt.MqttConnectPayload; -import io.netty.handler.ssl.SslHandler; -import io.streamnative.pulsar.handlers.mqtt.exception.MQTTAuthException; -import io.streamnative.pulsar.handlers.mqtt.oidc.OIDCService; +import io.streamnative.pulsar.handlers.mqtt.identitypool.AuthenticationProviderMTls; import io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.naming.AuthenticationException; -import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -35,6 +32,7 @@ import org.apache.pulsar.broker.authentication.AuthenticationDataSource; import org.apache.pulsar.broker.authentication.AuthenticationProvider; import org.apache.pulsar.broker.authentication.AuthenticationService; +import org.apache.pulsar.broker.service.BrokerService; /** * MQTT authentication service. @@ -48,8 +46,11 @@ public class MQTTAuthenticationService { @Getter private final Map authenticationProviders; - public MQTTAuthenticationService(AuthenticationService authenticationService, List authenticationMethods) { - this.authenticationService = authenticationService; + private final BrokerService brokerService; + + public MQTTAuthenticationService(BrokerService brokerService, List authenticationMethods) { + this.brokerService = brokerService; + this.authenticationService = brokerService.getAuthenticationService(); this.authenticationProviders = getAuthenticationProviders(authenticationMethods); } @@ -59,6 +60,14 @@ private Map getAuthenticationProviders(List getAuthenticationProviders(List 0) { - if (clientCerts[0] instanceof java.security.cert.X509Certificate) { - java.security.cert.X509Certificate clientCert = - (java.security.cert.X509Certificate) clientCerts[0]; - log.info("[proxy]-Client cert info: " + clientCert.getSubjectDN()); - String[] parts = clientCert.getSubjectDN().toString().split("="); - Map datas = new HashMap<>(); - datas.put(parts[0], parts[1]); - final String principal = oidcService.getPrincipal(datas); - log.info("[proxy]-mTls principal : {}", principal); - return new AuthenticationResult(true, principal, - new AuthenticationDataCommand(clientCert.getSubjectDN().toString())); - } - } - } else { - String msg = "mTlsEnabled, but not find SslHandler, disconnect the connection"; - log.error("mTlsEnabled, but not find SslHandler, disconnect the connection"); - throw new MQTTAuthException(msg); - } - } catch (SSLPeerUnverifiedException ex) { - log.warn("[proxy]- get client clientCerts error", ex); - throw new MQTTAuthException(ex); - } - String msg = "mTlsEnabled, but not find matched principal"; - throw new MQTTAuthException(msg); - } - - public AuthenticationResult authenticate(MqttConnectMessage connectMessage) { + public AuthenticationResult authenticate(boolean fromProxy, + SSLSession session, MqttConnectMessage connectMessage) { String authMethod = MqttMessageUtils.getAuthMethod(connectMessage); if (authMethod != null) { byte[] authData = MqttMessageUtils.getAuthData(connectMessage); if (authData == null) { return AuthenticationResult.FAILED; } + if (fromProxy && AUTH_MTLS.equalsIgnoreCase(authMethod)) { + return new AuthenticationResult(true, new String(authData), + new AuthenticationDataCommand(new String(authData), null, session)); + } return authenticate(connectMessage.payload().clientIdentifier(), authMethod, - new AuthenticationDataCommand(new String(authData))); + new AuthenticationDataCommand(new String(authData), null, session)); } - return authenticate(connectMessage.payload()); + return authenticate(connectMessage.payload(), session); } - public AuthenticationResult authenticate(MqttConnectPayload payload) { + public AuthenticationResult authenticate(MqttConnectPayload payload, SSLSession session) { String userRole = null; boolean authenticated = false; AuthenticationDataSource authenticationDataSource = null; for (Map.Entry entry : authenticationProviders.entrySet()) { String authMethod = entry.getKey(); try { - AuthenticationDataSource authData = getAuthData(authMethod, payload); + AuthenticationDataSource authData = getAuthData(authMethod, payload, session); userRole = entry.getValue().authenticate(authData); authenticated = true; authenticationDataSource = authData; @@ -139,9 +120,6 @@ public AuthenticationResult authenticate(MqttConnectPayload payload) { public AuthenticationResult authenticate(String clientIdentifier, String authMethod, AuthenticationDataCommand command) { - if (MTLS.equalsIgnoreCase(authMethod)) { - return new AuthenticationResult(true, command.getCommandData(), command); - } AuthenticationProvider authenticationProvider = authenticationProviders.get(authMethod); if (authenticationProvider == null) { log.warn("Authentication failed, no authMethod : {} for CId={}", clientIdentifier, authMethod); @@ -158,12 +136,14 @@ public AuthenticationResult authenticate(String clientIdentifier, return new AuthenticationResult(authenticated, userRole, command); } - public AuthenticationDataSource getAuthData(String authMethod, MqttConnectPayload payload) { + public AuthenticationDataSource getAuthData(String authMethod, MqttConnectPayload payload, SSLSession session) { switch (authMethod) { case AUTH_BASIC: return new AuthenticationDataCommand(payload.userName() + ":" + payload.password()); case AUTH_TOKEN: return new AuthenticationDataCommand(payload.password()); + case AUTH_MTLS: + return new AuthenticationDataCommand(null, null, session); default: throw new IllegalArgumentException( String.format("Unsupported authentication method : %s!", authMethod)); diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java index 7a9c1f807..c7a0c1b54 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTService.java @@ -13,8 +13,6 @@ */ package io.streamnative.pulsar.handlers.mqtt; -import io.streamnative.pulsar.handlers.mqtt.exception.MQTTServerException; -import io.streamnative.pulsar.handlers.mqtt.oidc.OIDCService; import io.streamnative.pulsar.handlers.mqtt.support.MQTTMetricsCollector; import io.streamnative.pulsar.handlers.mqtt.support.MQTTMetricsProvider; import io.streamnative.pulsar.handlers.mqtt.support.QosPublishHandlersImpl; @@ -31,7 +29,6 @@ import org.apache.pulsar.broker.PulsarService; import org.apache.pulsar.broker.authorization.AuthorizationService; import org.apache.pulsar.broker.service.BrokerService; -import org.apache.pulsar.metadata.api.MetadataStoreException; /** * Main class for mqtt service. @@ -88,9 +85,6 @@ public class MQTTService { @Setter private SystemEventService eventService; - @Getter - private OIDCService oidcService; - public MQTTService(BrokerService brokerService, MQTTServerConfiguration serverConfiguration) { this.brokerService = brokerService; this.pulsarService = brokerService.pulsar(); @@ -102,7 +96,7 @@ public MQTTService(BrokerService brokerService, MQTTServerConfiguration serverCo this.metricsProvider = new MQTTMetricsProvider(metricsCollector); this.pulsarService.addPrometheusRawMetricsProvider(metricsProvider); this.authenticationService = serverConfiguration.isMqttAuthenticationEnabled() - ? new MQTTAuthenticationService(brokerService.getAuthenticationService(), + ? new MQTTAuthenticationService(brokerService, serverConfiguration.getMqttAuthenticationMethods()) : null; this.connectionManager = new MQTTConnectionManager(pulsarService.getAdvertisedAddress()); this.subscriptionManager = new MQTTSubscriptionManager(); @@ -115,13 +109,6 @@ public MQTTService(BrokerService brokerService, MQTTServerConfiguration serverCo this.retainedMessageHandler = new RetainedMessageHandler(this); this.qosPublishHandlers = new QosPublishHandlersImpl(this); this.willMessageHandler = new WillMessageHandler(this); - if (serverConfiguration.isMqttMtlsEnabled()) { - try { - this.oidcService = new OIDCService(pulsarService); - } catch (MetadataStoreException ex) { - throw new MQTTServerException(ex); - } - } } public boolean isSystemTopicEnabled() { diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/adapter/AdapterChannel.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/adapter/AdapterChannel.java index ccf483d4c..1e43b74af 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/adapter/AdapterChannel.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/adapter/AdapterChannel.java @@ -51,7 +51,7 @@ public CompletableFuture writeAndFlush(final MqttAdapterMessage adapterMsg }); future.exceptionally(ex -> { log.warn("[AdapterChannel][{}] Proxy write to broker {} failed." - + " error message: {}", clientId, broker, ex.getMessage()); + + " adapterMsg message: {}", clientId, broker, adapterMsg, ex); return null; }); return future; diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/identitypool/AuthenticationProviderMTls.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/identitypool/AuthenticationProviderMTls.java index 6cad681cf..2f043aeda 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/identitypool/AuthenticationProviderMTls.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/identitypool/AuthenticationProviderMTls.java @@ -13,7 +13,6 @@ */ package io.streamnative.pulsar.handlers.mqtt.identitypool; - import static io.streamnative.pulsar.handlers.mqtt.identitypool.ExpressionCompiler.DN; import static io.streamnative.pulsar.handlers.mqtt.identitypool.ExpressionCompiler.DN_KEYS; import static io.streamnative.pulsar.handlers.mqtt.identitypool.ExpressionCompiler.SAN; diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java deleted file mode 100644 index b11c01550..000000000 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/ExpressionCompiler.java +++ /dev/null @@ -1,107 +0,0 @@ -/** - * 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. - */ -package io.streamnative.pulsar.handlers.mqtt.oidc; - -import com.google.common.annotations.VisibleForTesting; -import dev.cel.common.CelAbstractSyntaxTree; -import dev.cel.common.CelValidationException; -import dev.cel.common.CelVarDecl; -import dev.cel.common.types.MapType; -import dev.cel.common.types.SimpleType; -import dev.cel.compiler.CelCompiler; -import dev.cel.compiler.CelCompilerFactory; -import dev.cel.parser.CelStandardMacro; -import dev.cel.runtime.CelEvaluationException; -import dev.cel.runtime.CelRuntime; -import dev.cel.runtime.CelRuntimeFactory; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import lombok.Getter; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; - -public class ExpressionCompiler { - - @Getter - private CelCompiler compiler = CelCompilerFactory.standardCelCompilerBuilder() - .setStandardMacros(CelStandardMacro.STANDARD_MACROS) - .addVarDeclarations(CelVarDecl.newVarDeclaration("claims", - MapType.create(SimpleType.STRING, SimpleType.STRING))) - .build(); - - final CelRuntime runtime = CelRuntimeFactory.standardCelRuntimeBuilder().build(); - - static final String REGEX = "claims[\\w.]*"; - - static final Pattern PATTERN = Pattern.compile(REGEX); - - @Getter - private String expression; - - @Getter - private List variables; - - private CelAbstractSyntaxTree ast; - - private CelRuntime.Program program; - - public ExpressionCompiler(String expression) { - this.expression = expression; - this.variables = parse(expression); - try { - this.compile(); - } catch (CelValidationException | CelEvaluationException ex) { - throw new IllegalArgumentException(ex); - } - } - - @VisibleForTesting - ExpressionCompiler() { - } - - @VisibleForTesting - List parse(String expression) { - if (StringUtils.isEmpty(expression)) { - throw new IllegalArgumentException("Expression should not be empty"); - } - Matcher matcher = PATTERN.matcher(expression); - List matches = new ArrayList<>(); - while (matcher.find()) { - String find = matcher.group(0); - String[] parts = find.split("\\."); - matches.add(parts[1]); - } - if (CollectionUtils.isEmpty(matches)) { - throw new IllegalArgumentException("Not valid expression, " - + "expression definitions must be prefixed with claims."); - } - return matches; - } - - private void compile() throws CelValidationException, CelEvaluationException { - this.ast = compiler.compile(expression).getAst(); - this.program = runtime.createProgram(ast); - } - - public Boolean eval(Map mapValue) throws Exception { - final Object eval = program.eval(mapValue); - if (eval instanceof Boolean) { - return (Boolean) eval; - } - return false; - } -} diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java deleted file mode 100644 index 348210206..000000000 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCPoolResources.java +++ /dev/null @@ -1,97 +0,0 @@ -/** - * 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. - */ -package io.streamnative.pulsar.handlers.mqtt.oidc; - -import com.fasterxml.jackson.core.type.TypeReference; -import io.streamnative.pulsar.handlers.mqtt.utils.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; -import javax.validation.constraints.NotNull; -import org.apache.pulsar.broker.resources.BaseResources; -import org.apache.pulsar.common.util.FutureUtil; -import org.apache.pulsar.metadata.api.MetadataStore; -import org.apache.pulsar.metadata.api.MetadataStoreException; - -@SuppressWarnings("UnstableApiUsage") -public final class OIDCPoolResources extends BaseResources { - - public static final int RESOURCE_SYNC_OPERATION_TIMEOUT_SEC = 30; - private static final String BASE_PATH = "/sn-oidc/pools"; - - public OIDCPoolResources(@NotNull MetadataStore metadataStore) { - super(metadataStore, new TypeReference<>() { }, RESOURCE_SYNC_OPERATION_TIMEOUT_SEC); - } - - public @NotNull Optional getPool(@NotNull String poolName) throws MetadataStoreException { - return get(joinPath(BASE_PATH, Paths.getUrlEncodedPath(poolName))); - } - - public @NotNull CompletableFuture> getPoolAsync(@NotNull String poolName) { - return getAsync(joinPath(BASE_PATH, Paths.getUrlEncodedPath(poolName))); - } - - public void createPool(@NotNull Pool pool) throws MetadataStoreException { - create(joinPath(BASE_PATH, Paths.getUrlEncodedPath(pool.name())), pool); - } - - public @NotNull CompletableFuture createPoolAsync(@NotNull Pool pool) { - return createAsync(joinPath(BASE_PATH, Paths.getUrlEncodedPath(pool.name())), pool); - } - - public @NotNull CompletableFuture existsAsync(@NotNull String poolName) { - return super.existsAsync(joinPath(BASE_PATH, Paths.getUrlEncodedPath(poolName))); - } - - public void deletePool(@NotNull String poolName) throws MetadataStoreException { - super.delete(joinPath(BASE_PATH, Paths.getUrlEncodedPath(poolName))); - } - - public @NotNull CompletableFuture deletePoolAsync(@NotNull String poolName) { - return super.deleteIfExistsAsync(joinPath(BASE_PATH, Paths.getUrlEncodedPath(poolName))); - } - - public @NotNull CompletableFuture updatePoolAsync(@NotNull Pool pool) { - return super.setAsync(joinPath(BASE_PATH, Paths.getUrlEncodedPath(pool.name())), __ -> pool); - } - - public @NotNull CompletableFuture> listPoolNamesAsync() { - return super.getChildrenAsync(joinPath(BASE_PATH)); - } - - public @NotNull CompletableFuture> listPoolsAsync() { - return super.getChildrenAsync(joinPath(BASE_PATH)) - .thenCompose(poolNames -> { - List>> pools = new ArrayList<>(); - for (String name : poolNames) { - pools.add(getAsync(joinPath(BASE_PATH, name))); - } - return FutureUtil.waitForAll(pools) - .thenApply(__ -> pools.stream().map(f -> f.join()) - .filter(f -> f.isPresent()) - .map(f -> f.get()) - .collect(Collectors.toList())); - }); - } - - public static boolean pathIsFromPool(String path) { - return path.startsWith(BASE_PATH + "/"); - } - - public static String poolFromPath(String path) { - return path.substring(BASE_PATH.length() + 1); - } -} diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java deleted file mode 100644 index 778ec63af..000000000 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/OIDCService.java +++ /dev/null @@ -1,189 +0,0 @@ -/** - * 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. - */ -package io.streamnative.pulsar.handlers.mqtt.oidc; - -import com.beust.jcommander.internal.Lists; -import com.google.common.base.Joiner; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.pulsar.broker.PulsarService; -import org.apache.pulsar.broker.ServiceConfiguration; -import org.apache.pulsar.metadata.api.MetadataStore; -import org.apache.pulsar.metadata.api.MetadataStoreConfig; -import org.apache.pulsar.metadata.api.MetadataStoreException; -import org.apache.pulsar.metadata.api.Notification; -import org.apache.pulsar.metadata.api.NotificationType; -import org.apache.pulsar.metadata.api.extended.MetadataStoreExtended; - -@Slf4j -public class OIDCService { - - static final char PRINCIPAL_JOINER = (char) 27; - - private final PulsarService pulsarService; - - private final MetadataStore metadataStore; - - private final OIDCPoolResources poolResources; - - private final ConcurrentHashMap> poolsMap = new ConcurrentHashMap<>(); - - private final List pools = new ArrayList<>(); - - public OIDCService(PulsarService pulsarService) throws MetadataStoreException { - this.pulsarService = pulsarService; -// this.metadataStore = createLocalMetadataStore(pulsarService.getConfig()); - this.metadataStore = pulsarService.getConfigurationMetadataStore(); - this.metadataStore.registerListener(this::handleMetadataChanges); - this.poolResources = new OIDCPoolResources(this.metadataStore); - this.createData(); - } - - public MetadataStoreExtended createLocalMetadataStore(ServiceConfiguration config) throws MetadataStoreException { - return MetadataStoreExtended.create(config.getMetadataStoreUrl(), - MetadataStoreConfig.builder() - .sessionTimeoutMillis((int) config.getMetadataStoreSessionTimeoutMillis()) - .allowReadOnlyOperations(config.isMetadataStoreAllowReadOnlyOperations()) - .configFilePath(config.getMetadataStoreConfigPath()) - .batchingEnabled(config.isMetadataStoreBatchingEnabled()) - .batchingMaxDelayMillis(config.getMetadataStoreBatchingMaxDelayMillis()) - .batchingMaxOperations(config.getMetadataStoreBatchingMaxOperations()) - .batchingMaxSizeKb(config.getMetadataStoreBatchingMaxSizeKb()) - .metadataStoreName(MetadataStoreConfig.METADATA_STORE) - .build()); - } - - private CompletableFuture createData() { - Pool pool = new Pool("test-pool", "d", "provider-1", "claims.CN=='CLIENT'"); - return doLoadPools(CompletableFuture.completedFuture(Lists.newArrayList(pool))); - - } - - private CompletableFuture createDemoData() { - Pool pool = new Pool("test-pool", "d", "provider-1", "claims.CN=='CLIENT'"); - return poolResources.createPoolAsync(pool); - } - - private CompletableFuture loadPoolsAsync() { - return doLoadPools(poolResources.listPoolsAsync()); - } - - private CompletableFuture loadPoolAsync(String pool) { - final CompletableFuture> pools = poolResources.getPoolAsync(pool).thenCompose(opt -> { - if (opt.isEmpty()) { - return CompletableFuture.completedFuture(new ArrayList<>()); - } - return CompletableFuture.completedFuture(List.of(opt.get())); - }); - return doLoadPools(pools); - } - - private CompletableFuture doLoadPools(CompletableFuture> future) { - return future.thenApply(localPools -> { - localPools.stream().forEach(p -> { - final List poolCompilers = poolsMap.computeIfAbsent(p.providerName(), - k -> Collections.synchronizedList(new ArrayList<>())); - poolCompilers.removeIf(pc -> pc.getName().equalsIgnoreCase(p.name())); - PoolCompiler compiler = new PoolCompiler(p); - poolCompilers.add(compiler); - // - pools.removeIf(pc -> pc.getName().equalsIgnoreCase(p.name())); - pools.add(compiler); - }); - - List poolsNames = new ArrayList<>(); - for (List value : poolsMap.values()) { - Optional poolCompiler = value.stream().findFirst(); - poolCompiler.ifPresent(compiler -> poolsNames.add(compiler.getName())); - } - return poolsNames; - }).thenAccept(poolsNames -> log.info("refreshed OIDC pools, pools: {}, {}", poolsNames, pools)) - .exceptionally(ex -> { - log.error("load pool error", ex); - return null; - }); - } - - public String getPrincipal(Map datas) { - List principals = new ArrayList<>(); - for (PoolCompiler pool : pools) { - ExpressionCompiler compiler = pool.getCompiler(); - Map variables = new HashMap<>(); - Map claims = new HashMap<>(); - for (String var : compiler.getVariables()) { - Object jwtValue = datas.get(var); - if (jwtValue != null) { - variables.put(var, jwtValue); - } - } - claims.put("claims", variables); - Boolean matched = false; - try { - matched = compiler.eval(claims); - } catch (Exception e) { - log.warn("eval : {} value : {}", pool.getExpression(), claims, e); - } - if (matched) { - principals.add(pool.getName()); - } - } - return Joiner.on(PRINCIPAL_JOINER).join(principals); - } - - private void handleMetadataChanges(Notification n) { - if (OIDCPoolResources.pathIsFromPool(n.getPath())) { - log.info("pool-handleMetadataChanges : {}", n); - handlePoolAsync(n); - } - } - - private void handlePoolAsync(Notification n) { - String pool = OIDCPoolResources.poolFromPath(n.getPath()); - if (NotificationType.Created == n.getType() || NotificationType.Modified == n.getType()) { - loadPoolAsync(pool); - } else if (NotificationType.Deleted == n.getType()) { - deletePool(pool); - } - } - - private void deletePool(String pool) { - String providerName = ""; - for (List pools : poolsMap.values()) { - Iterator iterator = pools.iterator(); - while (iterator.hasNext()) { - final PoolCompiler item = iterator.next(); - if (item.getName().equalsIgnoreCase(pool)) { - iterator.remove(); - providerName = item.getProviderName(); - } - } - } - if (StringUtils.isNotEmpty(providerName)) { - final List poolCompilers = poolsMap.get(providerName); - if (CollectionUtils.isEmpty(poolCompilers)) { - poolsMap.remove(providerName); - } - } - } -} diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java deleted file mode 100644 index 6e116bb7a..000000000 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/Pool.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * 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. - */ -package io.streamnative.pulsar.handlers.mqtt.oidc; - -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.Objects; -import javax.validation.constraints.NotNull; - -public record Pool(@JsonProperty(value = "name", required = true) String name, - @JsonProperty(value = "description", required = true) @NotNull String description, - @JsonProperty(value = "provider_name", required = true) @NotNull String providerName, - @JsonProperty(value = "expression", required = true) @NotNull String expression) { - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Pool pool = (Pool) o; - return Objects.equals(name, pool.name); - } - - @Override - public int hashCode() { - return Objects.hash(name); - } -} diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java deleted file mode 100644 index 32c6a3bd5..000000000 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/PoolCompiler.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * 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. - */ -package io.streamnative.pulsar.handlers.mqtt.oidc; - -import lombok.Getter; - -public class PoolCompiler { - - private final Pool pool; - - @Getter - private final ExpressionCompiler compiler; - - public PoolCompiler(Pool pool) { - this.pool = pool; - this.compiler = new ExpressionCompiler(pool.expression()); - } - - public String getExpression() { - return pool.expression(); - } - - public String getName() { - return pool.name(); - } - - public String getProviderName() { - return pool.providerName(); - } - -} diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/package-info.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/package-info.java deleted file mode 100644 index 33a5d663e..000000000 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/oidc/package-info.java +++ /dev/null @@ -1,18 +0,0 @@ -/** - * 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. - */ - -/** - * Package info. - */ -package io.streamnative.pulsar.handlers.mqtt.oidc; diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java index 38f4521fb..dfcca36dc 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java @@ -13,7 +13,7 @@ */ package io.streamnative.pulsar.handlers.mqtt.proxy; -import static io.streamnative.pulsar.handlers.mqtt.Constants.MTLS; +import static io.streamnative.pulsar.handlers.mqtt.Constants.AUTH_MTLS; import static io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils.createMqttConnectMessage; import static io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils.createMqttPublishMessage; import static io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils.createMqttSubscribeMessage; @@ -27,21 +27,17 @@ import io.netty.handler.codec.mqtt.MqttSubscribeMessage; import io.netty.handler.codec.mqtt.MqttTopicSubscription; import io.netty.handler.codec.mqtt.MqttUnsubscribeMessage; -import io.netty.handler.ssl.SslHandler; import io.streamnative.pulsar.handlers.mqtt.Connection; -import io.streamnative.pulsar.handlers.mqtt.MQTTAuthenticationService; import io.streamnative.pulsar.handlers.mqtt.MQTTConnectionManager; import io.streamnative.pulsar.handlers.mqtt.TopicFilter; import io.streamnative.pulsar.handlers.mqtt.adapter.AdapterChannel; import io.streamnative.pulsar.handlers.mqtt.adapter.MQTTProxyAdapter; import io.streamnative.pulsar.handlers.mqtt.adapter.MqttAdapterMessage; -import io.streamnative.pulsar.handlers.mqtt.exception.MQTTAuthException; import io.streamnative.pulsar.handlers.mqtt.messages.ack.MqttAck; import io.streamnative.pulsar.handlers.mqtt.messages.ack.MqttPubAck; import io.streamnative.pulsar.handlers.mqtt.messages.ack.MqttSubAck; import io.streamnative.pulsar.handlers.mqtt.messages.codes.mqtt5.Mqtt5PubReasonCode; import io.streamnative.pulsar.handlers.mqtt.messages.properties.PulsarProperties; -import io.streamnative.pulsar.handlers.mqtt.oidc.OIDCService; import io.streamnative.pulsar.handlers.mqtt.restrictions.ClientRestrictions; import io.streamnative.pulsar.handlers.mqtt.restrictions.ServerRestrictions; import io.streamnative.pulsar.handlers.mqtt.support.AbstractCommonProtocolMethodProcessor; @@ -97,7 +93,6 @@ public class MQTTProxyProtocolMethodProcessor extends AbstractCommonProtocolMeth private final SystemEventService eventService; private final MQTTProxyAdapter proxyAdapter; - private final OIDCService oidcService; private final AtomicBoolean isDisconnected = new AtomicBoolean(false); private final AutoSubscribeHandler autoSubscribeHandler; @@ -120,7 +115,6 @@ public MQTTProxyProtocolMethodProcessor(MQTTProxyService proxyService, ChannelHa this.unsubscribeAckTracker = new MessageAckTracker(); this.packetIdTopic = new ConcurrentHashMap<>(); this.proxyAdapter = proxyService.getProxyAdapter(); - this.oidcService = proxyService.getOidcService(); this.maxPendingSendRequest = proxyConfig.getMaxPendingSendRequest(); this.resumeReadThreshold = maxPendingSendRequest / 2; this.autoSubscribeHandler = new AutoSubscribeHandler(proxyService.getEventCenter()); @@ -147,17 +141,8 @@ public void doProcessConnect(MqttAdapterMessage adapter, String userRole, .processor(this) .build(); connection.sendConnAck(); -// if (MqttUtils.isMqtt5(msg.variableHeader().version()) && getMtlsAuthMethodAndData(msg).isPresent()) { -// MqttConnectMessage connectMessage = createMqttConnectMessage(msg, MTLS, userRole); -// msg = connectMessage; -// connection.setConnectMessage(msg); -// } else if (MqttUtils.isMqtt3(msg.variableHeader().version()) && proxyConfig.isMqttProxyMtlsEnabled()) { -// MqttConnectMessage connectMessage = createMqttConnectMessage(msg, MTLS, userRole); -// msg = connectMessage; -// connection.setConnectMessage(msg); -// } if (proxyConfig.isMqttProxyMtlsEnabled()) { - MqttConnectMessage connectMessage = createMqttConnectMessage(msg, MTLS, userRole); + MqttConnectMessage connectMessage = createMqttConnectMessage(msg, AUTH_MTLS, userRole); msg = connectMessage; connection.setConnectMessage(msg); } @@ -169,14 +154,6 @@ public void doProcessConnect(MqttAdapterMessage adapter, String userRole, eventService.sendConnectEvent(connectEvent); } - protected MQTTAuthenticationService.AuthenticationResult mtlsAuth(boolean fromProxy) throws MQTTAuthException { - if (proxyConfig.isMqttProxyMtlsEnabled()) { - SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); - return authenticationService.mTlsAuthenticate(sslHandler, oidcService); - } - return super.mtlsAuth(fromProxy); - } - @Override public void processPublish(MqttAdapterMessage adapter) { final MqttPublishMessage msg = (MqttPublishMessage) adapter.getMqttMessage(); @@ -190,7 +167,7 @@ public void processPublish(MqttAdapterMessage adapter) { TopicDomain.getEnum(proxyConfig.getDefaultTopicDomain())); adapter.setClientId(connection.getClientId()); if (proxyConfig.isMqttProxyMtlsEnabled()) { - MqttPublishMessage mqttMessage = createMqttPublishMessage(msg, MTLS, connection.getUserRole()); + MqttPublishMessage mqttMessage = createMqttPublishMessage(msg, AUTH_MTLS, connection.getUserRole()); adapter.setMqttMessage(mqttMessage); } startPublish() @@ -324,7 +301,7 @@ public void processSubscribe(final MqttAdapterMessage adapter) { } registerTopicListener(adapter); if (proxyConfig.isMqttProxyMtlsEnabled()) { - MqttSubscribeMessage mqttMessage = createMqttSubscribeMessage(msg, MTLS, connection.getUserRole()); + MqttSubscribeMessage mqttMessage = createMqttSubscribeMessage(msg, AUTH_MTLS, connection.getUserRole()); adapter.setMqttMessage(mqttMessage); } doSubscribe(adapter, false) diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java index 31934a20d..84b2356a7 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java @@ -23,7 +23,6 @@ import io.streamnative.pulsar.handlers.mqtt.MQTTConnectionManager; import io.streamnative.pulsar.handlers.mqtt.MQTTService; import io.streamnative.pulsar.handlers.mqtt.adapter.MQTTProxyAdapter; -import io.streamnative.pulsar.handlers.mqtt.oidc.OIDCService; import io.streamnative.pulsar.handlers.mqtt.support.event.PulsarEventCenter; import io.streamnative.pulsar.handlers.mqtt.support.event.PulsarEventCenterImpl; import io.streamnative.pulsar.handlers.mqtt.support.psk.PSKConfiguration; @@ -37,7 +36,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.pulsar.broker.PulsarService; import org.apache.pulsar.common.util.netty.EventLoopUtil; -import org.apache.pulsar.metadata.api.MetadataStoreException; /** * This service is used for redirecting MQTT client request to proper MQTT protocol handler Broker. @@ -64,9 +62,6 @@ public class MQTTProxyService implements Closeable { @Getter private final MQTTProxyAdapter proxyAdapter; - @Getter - private OIDCService oidcService; - private Channel listenChannel; private Channel listenChannelTls; private Channel listenChannelTlsPsk; @@ -153,14 +148,6 @@ public void start() throws MQTTProxyException { throw new MQTTProxyException(e); } } - if (proxyConfig.isMqttProxyMtlsEnabled()) { - try { - this.oidcService = new OIDCService(pulsarService); - } catch (MetadataStoreException ex) { - throw new MQTTProxyException(ex); - } - } - this.lookupHandler = new PulsarServiceLookupHandler(pulsarService, proxyConfig); this.eventService.start(); } diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/AbstractCommonProtocolMethodProcessor.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/AbstractCommonProtocolMethodProcessor.java index e94c63df1..57f25a99f 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/AbstractCommonProtocolMethodProcessor.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/AbstractCommonProtocolMethodProcessor.java @@ -21,6 +21,7 @@ import io.netty.handler.codec.mqtt.MqttMessageBuilders; import io.netty.handler.codec.mqtt.MqttProperties; import io.netty.handler.codec.mqtt.MqttReasonCodeAndPropertiesVariableHeader; +import io.netty.handler.ssl.SslHandler; import io.streamnative.pulsar.handlers.mqtt.Connection; import io.streamnative.pulsar.handlers.mqtt.MQTTAuthenticationService; import io.streamnative.pulsar.handlers.mqtt.ProtocolMethodProcessor; @@ -34,6 +35,7 @@ import io.streamnative.pulsar.handlers.mqtt.utils.MqttMessageUtils; import io.streamnative.pulsar.handlers.mqtt.utils.MqttUtils; import io.streamnative.pulsar.handlers.mqtt.utils.NettyUtils; +import javax.net.ssl.SSLSession; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -125,9 +127,10 @@ public void processConnect(MqttAdapterMessage adapter) { } } else { MQTTAuthenticationService.AuthenticationResult authResult; - try { - authResult = mtlsAuth(adapter.fromProxy()); - } catch (MQTTAuthException e) { + SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); + SSLSession session = (sslHandler != null) ? sslHandler.engine().getSession() : null; + authResult = authenticationService.authenticate(adapter.fromProxy(), session, connectMessage); + if (authResult.isFailed()) { MqttMessage mqttMessage = MqttConnectAck.errorBuilder().authFail(protocolVersion); log.error("[CONNECT] Invalid or incorrect authentication. CId={}, username={}", clientId, username); adapter.setMqttMessage(mqttMessage); @@ -137,19 +140,6 @@ public void processConnect(MqttAdapterMessage adapter) { } return; } - if (authResult.isFailed()) { - authResult = authenticationService.authenticate(connectMessage); - if (authResult.isFailed()) { - MqttMessage mqttMessage = MqttConnectAck.errorBuilder().authFail(protocolVersion); - log.error("[CONNECT] Invalid or incorrect authentication. CId={}, username={}", clientId, username); - adapter.setMqttMessage(mqttMessage); - channel.writeAndFlush(adapter); - if (!adapter.fromProxy()) { - channel.close(); - } - return; - } - } userRole = authResult.getUserRole(); authData = authResult.getAuthData(); } diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java index ed7a51e7f..3a4bed839 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/support/MQTTBrokerProtocolMethodProcessor.java @@ -26,9 +26,7 @@ import io.netty.handler.codec.mqtt.MqttSubscribeMessage; import io.netty.handler.codec.mqtt.MqttTopicSubscription; import io.netty.handler.codec.mqtt.MqttUnsubscribeMessage; -import io.netty.handler.ssl.SslHandler; import io.streamnative.pulsar.handlers.mqtt.Connection; -import io.streamnative.pulsar.handlers.mqtt.MQTTAuthenticationService; import io.streamnative.pulsar.handlers.mqtt.MQTTConnectionManager; import io.streamnative.pulsar.handlers.mqtt.MQTTServerConfiguration; import io.streamnative.pulsar.handlers.mqtt.MQTTService; @@ -39,7 +37,6 @@ import io.streamnative.pulsar.handlers.mqtt.QosPublishHandlers; import io.streamnative.pulsar.handlers.mqtt.TopicFilter; import io.streamnative.pulsar.handlers.mqtt.adapter.MqttAdapterMessage; -import io.streamnative.pulsar.handlers.mqtt.exception.MQTTAuthException; import io.streamnative.pulsar.handlers.mqtt.exception.MQTTNoSubscriptionExistedException; import io.streamnative.pulsar.handlers.mqtt.exception.MQTTTopicNotExistedException; import io.streamnative.pulsar.handlers.mqtt.exception.restrictions.InvalidSessionExpireIntervalException; @@ -53,7 +50,6 @@ import io.streamnative.pulsar.handlers.mqtt.messages.codes.mqtt5.Mqtt5PubReasonCode; import io.streamnative.pulsar.handlers.mqtt.messages.codes.mqtt5.Mqtt5UnsubReasonCode; import io.streamnative.pulsar.handlers.mqtt.messages.properties.PulsarProperties; -import io.streamnative.pulsar.handlers.mqtt.oidc.OIDCService; import io.streamnative.pulsar.handlers.mqtt.restrictions.ClientRestrictions; import io.streamnative.pulsar.handlers.mqtt.restrictions.ServerRestrictions; import io.streamnative.pulsar.handlers.mqtt.support.event.AutoSubscribeHandler; @@ -113,7 +109,6 @@ public class MQTTBrokerProtocolMethodProcessor extends AbstractCommonProtocolMet private final RetainedMessageHandler retainedMessageHandler; private final AutoSubscribeHandler autoSubscribeHandler; - private final OIDCService oidcService; @Getter private final CompletableFuture inactiveFuture = new CompletableFuture<>(); @@ -133,7 +128,6 @@ public MQTTBrokerProtocolMethodProcessor(MQTTService mqttService, ChannelHandler this.retainedMessageHandler = mqttService.getRetainedMessageHandler(); this.serverCnx = new MQTTServerCnx(pulsarService, ctx); this.autoSubscribeHandler = new AutoSubscribeHandler(mqttService.getEventCenter()); - this.oidcService = mqttService.getOidcService(); } @Override @@ -162,17 +156,6 @@ public void doProcessConnect(MqttAdapterMessage adapterMsg, String userRole, connection.sendConnAck(); } - protected MQTTAuthenticationService.AuthenticationResult mtlsAuth(boolean fromProxy) throws MQTTAuthException { - if (fromProxy) { - return super.mtlsAuth(fromProxy); - } - if (configuration.isMqttMtlsEnabled()) { - SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); - return authenticationService.mTlsAuthenticate(sslHandler, oidcService); - } - return super.mtlsAuth(fromProxy); - } - @Override public void processPubAck(MqttAdapterMessage adapter) { if (log.isDebugEnabled()) { diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java index ed6c23af6..dac7a9f24 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/utils/MqttMessageUtils.java @@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE; -import static io.streamnative.pulsar.handlers.mqtt.Constants.MTLS; +import static io.streamnative.pulsar.handlers.mqtt.Constants.AUTH_MTLS; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.handler.codec.mqtt.MqttConnectMessage; @@ -199,10 +199,9 @@ public static MqttConnectMessage createMqttConnectMessage(MqttConnectMessage con properties.add(new MqttProperties.BinaryProperty(MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value() , authData.getBytes())); MqttConnectVariableHeader variableHeader = new MqttConnectVariableHeader( - header.name(), MqttVersion.MQTT_5.protocolLevel(), header.hasUserName(), header.hasPassword(), - header.isWillRetain(), header.willQos(), header.isWillFlag(), header.isCleanSession(), - header.keepAliveTimeSeconds(), - properties + MqttVersion.MQTT_5.protocolName(), MqttVersion.MQTT_5.protocolLevel(), header.hasUserName(), + header.hasPassword(), header.isWillRetain(), header.willQos(), header.isWillFlag(), + header.isCleanSession(), header.keepAliveTimeSeconds(), properties ); MqttConnectMessage newConnectMessage = new MqttConnectMessage(connectMessage.fixedHeader(), variableHeader, connectMessage.payload()); @@ -231,7 +230,7 @@ public static Optional> getMtlsAuthMethodAndData(MqttConnec final MqttProperties.MqttProperty property = properties.getProperty( MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value()); if (property != null && property.value() instanceof String - && ((String) property.value()).equalsIgnoreCase(MTLS)) { + && ((String) property.value()).equalsIgnoreCase(AUTH_MTLS)) { final MqttProperties.MqttProperty data = properties.getProperty( MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value()); return Optional.of(Pair.of((String) property.value(), (byte[]) data.value())); @@ -245,7 +244,7 @@ public static Optional> getMtlsAuthMethodAndData(MqttPublis final MqttProperties.MqttProperty property = properties.getProperty( MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value()); if (property != null && property.value() instanceof String - && ((String) property.value()).equalsIgnoreCase(MTLS)) { + && ((String) property.value()).equalsIgnoreCase(AUTH_MTLS)) { final MqttProperties.MqttProperty data = properties.getProperty( MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value()); return Optional.of(Pair.of((String) property.value(), (byte[]) data.value())); @@ -259,7 +258,7 @@ public static Optional> getMtlsAuthMethodAndData(MqttSubscr final MqttProperties.MqttProperty property = properties.getProperty( MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value()); if (property != null && property.value() instanceof String - && ((String) property.value()).equalsIgnoreCase(MTLS)) { + && ((String) property.value()).equalsIgnoreCase(AUTH_MTLS)) { final MqttProperties.MqttProperty data = properties.getProperty( MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value()); return Optional.of(Pair.of((String) property.value(), (byte[]) data.value())); diff --git a/pom.xml b/pom.xml index 6c0799ad9..e12255ec9 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ 2.22.0 6.14.3 4.0.2 - 4.0.0-SNAPSHOT + 4.0.0-ursa-5-SNAPSHOT 4.1.94.Final 2.18.0 1.16 diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java index f48783035..cdff71b5f 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java @@ -13,6 +13,7 @@ */ package io.streamnative.pulsar.handlers.mqtt.mqtt5.hivemq.base; +import static io.streamnative.oidc.broker.common.pojo.Pool.AUTH_TYPE_MTLS; import static org.mockito.Mockito.spy; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -25,8 +26,12 @@ import com.hivemq.client.mqtt.mqtt5.Mqtt5Client; import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish; import io.jsonwebtoken.SignatureAlgorithm; +import io.streamnative.oidc.broker.common.OIDCPoolResources; +import io.streamnative.oidc.broker.common.pojo.Pool; +import io.streamnative.pulsar.handlers.mqtt.Constants; import io.streamnative.pulsar.handlers.mqtt.MQTTCommonConfiguration; import io.streamnative.pulsar.handlers.mqtt.base.MQTTTestBase; +import io.streamnative.pulsar.handlers.mqtt.identitypool.AuthenticationProviderMTls; import java.io.File; import java.io.FileInputStream; import java.security.KeyStore; @@ -41,12 +46,14 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; +import org.apache.pulsar.broker.PulsarService; import org.apache.pulsar.broker.authentication.AuthenticationProviderToken; import org.apache.pulsar.broker.authentication.utils.AuthTokenUtils; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.impl.auth.AuthenticationToken; import org.apache.pulsar.common.util.SecurityUtility; +import org.awaitility.Awaitility; import org.fusesource.mqtt.client.BlockingConnection; import org.fusesource.mqtt.client.MQTT; import org.fusesource.mqtt.client.Message; @@ -62,6 +69,8 @@ public class ProxyMtlsTest extends MQTTTestBase { String token; + MQTTCommonConfiguration localConfig; + @Override protected MQTTCommonConfiguration initConfig() throws Exception { System.setProperty("jdk.security.allowNonCaAnchor", "true"); @@ -89,13 +98,18 @@ protected MQTTCommonConfiguration initConfig() throws Exception { mqtt.setAuthenticationEnabled(true); mqtt.setMqttAuthenticationEnabled(true); - mqtt.setMqttAuthenticationMethods(ImmutableList.of("token")); + mqtt.setMqttAuthenticationMethods(ImmutableList.of("token", Constants.AUTH_MTLS)); mqtt.setSuperUserRoles(ImmutableSet.of("superUser")); + mqtt.setAuthenticationProviders(Sets.newHashSet(AuthenticationProviderToken.class.getName(), + AuthenticationProviderMTls.class.getName())); + mqtt.setAuthenticationProviders(Sets.newHashSet(AuthenticationProviderToken.class.getName())); mqtt.setBrokerClientAuthenticationPlugin(AuthenticationToken.class.getName()); mqtt.setBrokerClientAuthenticationParameters("token:" + token); mqtt.setProperties(properties); + localConfig = mqtt; + return mqtt; } @@ -113,6 +127,14 @@ public void afterSetup() throws Exception { .serviceHttpUrl(brokerUrl.toString()) .authentication(authToken) .build()); + + final PulsarService pulsarService = pulsarServiceList.get(0); + OIDCPoolResources oidcPoolResources = new OIDCPoolResources(pulsarService.getLocalMetadataStore()); + + Pool pool = new Pool("test-pool", AUTH_TYPE_MTLS, "d", "provider-1", "CN=='CLIENT'"); + oidcPoolResources.createPool(pool); + + Awaitility.await().until(() -> oidcPoolResources.getPool("test-pool") != null); } public SSLContext createSSLContext() throws Exception { @@ -189,9 +211,6 @@ public void testMqtt5() throws Exception { String topic1 = "testMqtt5-client-1"; String topic2 = "testMqtt5-client-2"; -// final Mqtt5UserProperties userProperties = Mqtt5UserProperties.builder().add( -// MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value() + "", Constants.MTLS).build(); -// client1.connectWith().userProperties(userProperties).send(); client1.connect(); client2.connect(); client1.subscribeWith().topicFilter(topic1).qos(MqttQos.AT_LEAST_ONCE).send(); @@ -205,7 +224,6 @@ public void testMqtt5() throws Exception { .send(); try (Mqtt5BlockingClient.Mqtt5Publishes publishes = client1.publishes(MqttGlobalPublishFilter.ALL)) { - System.out.println("go client1 receive"); Mqtt5Publish publish = publishes.receive(); Assert.assertEquals(publish.getTopic(), MqttTopic.of(topic1)); Assert.assertEquals(publish.getPayloadAsBytes(), msg1); @@ -217,7 +235,6 @@ public void testMqtt5() throws Exception { .payload(msg2) .send(); try (Mqtt5BlockingClient.Mqtt5Publishes publishes = client2.publishes(MqttGlobalPublishFilter.ALL)) { - System.out.println("go client2 receive"); Mqtt5Publish publish = publishes.receive(); Assert.assertEquals(publish.getTopic(), MqttTopic.of(topic2)); Assert.assertEquals(publish.getPayloadAsBytes(), msg2); @@ -226,6 +243,5 @@ public void testMqtt5() throws Exception { client1.disconnect(); client2.unsubscribeWith().topicFilter(topic1).send(); client2.disconnect(); - System.out.println("done"); } } From 3de14e2aea1158b4d618a4c48aa84df517dc8d61 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Tue, 10 Sep 2024 09:22:28 +0800 Subject: [PATCH 15/23] update --- .../mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java | 2 +- tests/src/test/resources/mtls/{ => proxy}/ca.cer | 0 tests/src/test/resources/mtls/{ => proxy}/ca.crt | 0 tests/src/test/resources/mtls/{ => proxy}/ca.key | 0 tests/src/test/resources/mtls/{ => proxy}/ca.srl | 0 .../test/resources/mtls/{ => proxy}/ca_config.cnf | 0 .../src/test/resources/mtls/{ => proxy}/client.cer | 0 .../src/test/resources/mtls/{ => proxy}/client.csr | 0 .../src/test/resources/mtls/{ => proxy}/client.key | 0 .../src/test/resources/mtls/{ => proxy}/client.p12 | Bin .../resources/mtls/{ => proxy}/clientkeystore.jks | Bin .../src/test/resources/mtls/{ => proxy}/server.cer | 0 .../src/test/resources/mtls/{ => proxy}/server.csr | 0 .../src/test/resources/mtls/{ => proxy}/server.key | 0 .../src/test/resources/mtls/{ => proxy}/server.p12 | Bin .../resources/mtls/{ => proxy}/serverkeystore.jks | Bin .../test/resources/mtls/{ => proxy}/truststore.jks | Bin 17 files changed, 1 insertion(+), 1 deletion(-) rename tests/src/test/resources/mtls/{ => proxy}/ca.cer (100%) rename tests/src/test/resources/mtls/{ => proxy}/ca.crt (100%) rename tests/src/test/resources/mtls/{ => proxy}/ca.key (100%) rename tests/src/test/resources/mtls/{ => proxy}/ca.srl (100%) rename tests/src/test/resources/mtls/{ => proxy}/ca_config.cnf (100%) rename tests/src/test/resources/mtls/{ => proxy}/client.cer (100%) rename tests/src/test/resources/mtls/{ => proxy}/client.csr (100%) rename tests/src/test/resources/mtls/{ => proxy}/client.key (100%) rename tests/src/test/resources/mtls/{ => proxy}/client.p12 (100%) rename tests/src/test/resources/mtls/{ => proxy}/clientkeystore.jks (100%) rename tests/src/test/resources/mtls/{ => proxy}/server.cer (100%) rename tests/src/test/resources/mtls/{ => proxy}/server.csr (100%) rename tests/src/test/resources/mtls/{ => proxy}/server.key (100%) rename tests/src/test/resources/mtls/{ => proxy}/server.p12 (100%) rename tests/src/test/resources/mtls/{ => proxy}/serverkeystore.jks (100%) rename tests/src/test/resources/mtls/{ => proxy}/truststore.jks (100%) diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java index cdff71b5f..c17c08eb4 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java @@ -65,7 +65,7 @@ public class ProxyMtlsTest extends MQTTTestBase { - String path = "./src/test/resources/mtls/"; + String path = "./src/test/resources/mtls/proxy/"; String token; diff --git a/tests/src/test/resources/mtls/ca.cer b/tests/src/test/resources/mtls/proxy/ca.cer similarity index 100% rename from tests/src/test/resources/mtls/ca.cer rename to tests/src/test/resources/mtls/proxy/ca.cer diff --git a/tests/src/test/resources/mtls/ca.crt b/tests/src/test/resources/mtls/proxy/ca.crt similarity index 100% rename from tests/src/test/resources/mtls/ca.crt rename to tests/src/test/resources/mtls/proxy/ca.crt diff --git a/tests/src/test/resources/mtls/ca.key b/tests/src/test/resources/mtls/proxy/ca.key similarity index 100% rename from tests/src/test/resources/mtls/ca.key rename to tests/src/test/resources/mtls/proxy/ca.key diff --git a/tests/src/test/resources/mtls/ca.srl b/tests/src/test/resources/mtls/proxy/ca.srl similarity index 100% rename from tests/src/test/resources/mtls/ca.srl rename to tests/src/test/resources/mtls/proxy/ca.srl diff --git a/tests/src/test/resources/mtls/ca_config.cnf b/tests/src/test/resources/mtls/proxy/ca_config.cnf similarity index 100% rename from tests/src/test/resources/mtls/ca_config.cnf rename to tests/src/test/resources/mtls/proxy/ca_config.cnf diff --git a/tests/src/test/resources/mtls/client.cer b/tests/src/test/resources/mtls/proxy/client.cer similarity index 100% rename from tests/src/test/resources/mtls/client.cer rename to tests/src/test/resources/mtls/proxy/client.cer diff --git a/tests/src/test/resources/mtls/client.csr b/tests/src/test/resources/mtls/proxy/client.csr similarity index 100% rename from tests/src/test/resources/mtls/client.csr rename to tests/src/test/resources/mtls/proxy/client.csr diff --git a/tests/src/test/resources/mtls/client.key b/tests/src/test/resources/mtls/proxy/client.key similarity index 100% rename from tests/src/test/resources/mtls/client.key rename to tests/src/test/resources/mtls/proxy/client.key diff --git a/tests/src/test/resources/mtls/client.p12 b/tests/src/test/resources/mtls/proxy/client.p12 similarity index 100% rename from tests/src/test/resources/mtls/client.p12 rename to tests/src/test/resources/mtls/proxy/client.p12 diff --git a/tests/src/test/resources/mtls/clientkeystore.jks b/tests/src/test/resources/mtls/proxy/clientkeystore.jks similarity index 100% rename from tests/src/test/resources/mtls/clientkeystore.jks rename to tests/src/test/resources/mtls/proxy/clientkeystore.jks diff --git a/tests/src/test/resources/mtls/server.cer b/tests/src/test/resources/mtls/proxy/server.cer similarity index 100% rename from tests/src/test/resources/mtls/server.cer rename to tests/src/test/resources/mtls/proxy/server.cer diff --git a/tests/src/test/resources/mtls/server.csr b/tests/src/test/resources/mtls/proxy/server.csr similarity index 100% rename from tests/src/test/resources/mtls/server.csr rename to tests/src/test/resources/mtls/proxy/server.csr diff --git a/tests/src/test/resources/mtls/server.key b/tests/src/test/resources/mtls/proxy/server.key similarity index 100% rename from tests/src/test/resources/mtls/server.key rename to tests/src/test/resources/mtls/proxy/server.key diff --git a/tests/src/test/resources/mtls/server.p12 b/tests/src/test/resources/mtls/proxy/server.p12 similarity index 100% rename from tests/src/test/resources/mtls/server.p12 rename to tests/src/test/resources/mtls/proxy/server.p12 diff --git a/tests/src/test/resources/mtls/serverkeystore.jks b/tests/src/test/resources/mtls/proxy/serverkeystore.jks similarity index 100% rename from tests/src/test/resources/mtls/serverkeystore.jks rename to tests/src/test/resources/mtls/proxy/serverkeystore.jks diff --git a/tests/src/test/resources/mtls/truststore.jks b/tests/src/test/resources/mtls/proxy/truststore.jks similarity index 100% rename from tests/src/test/resources/mtls/truststore.jks rename to tests/src/test/resources/mtls/proxy/truststore.jks From 6570220bea3e4ed53b58172423d29289af30c57d Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Tue, 10 Sep 2024 09:40:25 +0800 Subject: [PATCH 16/23] v2 -> v3 --- .github/workflows/pr_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr_test.yml b/.github/workflows/pr_test.yml index af2eaf6ad..9ce8e86b5 100644 --- a/.github/workflows/pr_test.yml +++ b/.github/workflows/pr_test.yml @@ -100,7 +100,7 @@ jobs: run: ./scripts/retry.sh mvn -B -ntp test -Dtest=${{ matrix.test }} -DfailIfNoTests=false - name: Upload jacoco artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: ${{ matrix.test }}-jacoco-artifact path: '**/*.exec' From 61c1b811d5d4d71a5881a1e5d0727ab7789579e7 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Tue, 10 Sep 2024 10:22:21 +0800 Subject: [PATCH 17/23] v2 -> v3 --- .../pulsar/handlers/mqtt/MQTTCommonConfiguration.java | 9 +-------- .../handlers/mqtt/proxy/MQTTProxyConfiguration.java | 2 +- .../mqtt/proxy/MQTTProxyProtocolMethodProcessor.java | 6 +++--- .../pulsar/handlers/mqtt/proxy/MQTTProxyService.java | 2 +- .../handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java | 7 ++----- 5 files changed, 8 insertions(+), 18 deletions(-) diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java index e4a72f5a4..0b8db658e 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java @@ -150,7 +150,7 @@ public class MQTTCommonConfiguration extends ServiceConfiguration { required = false, doc = "Whether start mqtt protocol handler with proxy mtls" ) - private boolean mqttProxyMtlsEnabled = false; + private boolean mqttProxyMTlsAuthenticationEnabled = false; @FieldContext( category = CATEGORY_MQTT_PROXY, @@ -180,13 +180,6 @@ public class MQTTCommonConfiguration extends ServiceConfiguration { ) private boolean mqttTlsPskEnabled = false; - @FieldContext( - category = CATEGORY_TLS, - required = false, - doc = "Whether start mqtt protocol handler with mtls" - ) - private boolean mqttMtlsEnabled = false; - @Deprecated @FieldContext( category = CATEGORY_TLS, diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyConfiguration.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyConfiguration.java index 708ef5124..251eac432 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyConfiguration.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyConfiguration.java @@ -60,7 +60,7 @@ public class MQTTProxyConfiguration extends MQTTCommonConfiguration { category = CATEGORY_MQTT_PROXY, doc = "Enable system event service." ) - private boolean systemEventEnabled = false; + private boolean systemEventEnabled = true; @FieldContext( category = CATEGORY_MQTT, diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java index dfcca36dc..6dafd3db5 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyProtocolMethodProcessor.java @@ -141,7 +141,7 @@ public void doProcessConnect(MqttAdapterMessage adapter, String userRole, .processor(this) .build(); connection.sendConnAck(); - if (proxyConfig.isMqttProxyMtlsEnabled()) { + if (proxyConfig.isMqttProxyMTlsAuthenticationEnabled()) { MqttConnectMessage connectMessage = createMqttConnectMessage(msg, AUTH_MTLS, userRole); msg = connectMessage; connection.setConnectMessage(msg); @@ -166,7 +166,7 @@ public void processPublish(MqttAdapterMessage adapter) { proxyConfig.getDefaultTenant(), proxyConfig.getDefaultNamespace(), TopicDomain.getEnum(proxyConfig.getDefaultTopicDomain())); adapter.setClientId(connection.getClientId()); - if (proxyConfig.isMqttProxyMtlsEnabled()) { + if (proxyConfig.isMqttProxyMTlsAuthenticationEnabled()) { MqttPublishMessage mqttMessage = createMqttPublishMessage(msg, AUTH_MTLS, connection.getUserRole()); adapter.setMqttMessage(mqttMessage); } @@ -300,7 +300,7 @@ public void processSubscribe(final MqttAdapterMessage adapter) { log.debug("[Proxy Subscribe] [{}] msg: {}", clientId, msg); } registerTopicListener(adapter); - if (proxyConfig.isMqttProxyMtlsEnabled()) { + if (proxyConfig.isMqttProxyMTlsAuthenticationEnabled()) { MqttSubscribeMessage mqttMessage = createMqttSubscribeMessage(msg, AUTH_MTLS, connection.getUserRole()); adapter.setMqttMessage(mqttMessage); } diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java index 84b2356a7..968f2a40b 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java @@ -117,7 +117,7 @@ public void start() throws MQTTProxyException { throw new MQTTProxyException(e); } - if (proxyConfig.isMqttProxyTlsEnabled() || proxyConfig.isMqttProxyMtlsEnabled()) { + if (proxyConfig.isMqttProxyTlsEnabled() || proxyConfig.isMqttProxyMTlsAuthenticationEnabled()) { ServerBootstrap tlsBootstrap = serverBootstrap.clone(); tlsBootstrap.childHandler(new MQTTProxyChannelInitializer( this, proxyConfig, true, sslContextRefresher)); diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java index c17c08eb4..3e533a13b 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java @@ -79,8 +79,7 @@ protected MQTTCommonConfiguration initConfig() throws Exception { mqtt.setSystemTopicEnabled(false); mqtt.setMqttProxyEnabled(true); - mqtt.setMqttProxyMtlsEnabled(true); - mqtt.setMqttMtlsEnabled(true); + mqtt.setMqttProxyMTlsAuthenticationEnabled(true); mqtt.setMqttProxyTlsEnabled(true); mqtt.setMqttTlsEnabledWithKeyStore(true); @@ -100,10 +99,8 @@ protected MQTTCommonConfiguration initConfig() throws Exception { mqtt.setMqttAuthenticationEnabled(true); mqtt.setMqttAuthenticationMethods(ImmutableList.of("token", Constants.AUTH_MTLS)); mqtt.setSuperUserRoles(ImmutableSet.of("superUser")); - mqtt.setAuthenticationProviders(Sets.newHashSet(AuthenticationProviderToken.class.getName(), - AuthenticationProviderMTls.class.getName())); - mqtt.setAuthenticationProviders(Sets.newHashSet(AuthenticationProviderToken.class.getName())); + mqtt.setBrokerClientAuthenticationPlugin(AuthenticationToken.class.getName()); mqtt.setBrokerClientAuthenticationParameters("token:" + token); mqtt.setProperties(properties); From 2e07c95c1cc4a6272f657c825af5b8e4c114849f Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Tue, 10 Sep 2024 13:05:02 +0800 Subject: [PATCH 18/23] fix checkstyle issue --- .../pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java index 3e533a13b..97602bfb0 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java @@ -31,7 +31,6 @@ import io.streamnative.pulsar.handlers.mqtt.Constants; import io.streamnative.pulsar.handlers.mqtt.MQTTCommonConfiguration; import io.streamnative.pulsar.handlers.mqtt.base.MQTTTestBase; -import io.streamnative.pulsar.handlers.mqtt.identitypool.AuthenticationProviderMTls; import java.io.File; import java.io.FileInputStream; import java.security.KeyStore; From a72e615fa9c1ebfcc89602bed1e718c2f1188d6d Mon Sep 17 00:00:00 2001 From: Cong Zhao Date: Tue, 10 Sep 2024 14:52:06 +0800 Subject: [PATCH 19/23] Update tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java --- .../pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java index 97602bfb0..c31a8c17b 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java @@ -80,6 +80,8 @@ protected MQTTCommonConfiguration initConfig() throws Exception { mqtt.setMqttProxyEnabled(true); mqtt.setMqttProxyMTlsAuthenticationEnabled(true); mqtt.setMqttProxyTlsEnabled(true); + mqtt.setMqttTlsRequireTrustedClientCertOnConnect(true); + mqtt.setMqttTlsAllowInsecureConnection(false); mqtt.setMqttTlsEnabledWithKeyStore(true); mqtt.setMqttTlsKeyStoreType("JKS"); From 57925e2877e0b521dc1ce7f1db0fa37f99b53a91 Mon Sep 17 00:00:00 2001 From: Cong Zhao Date: Tue, 10 Sep 2024 14:57:08 +0800 Subject: [PATCH 20/23] Update mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java --- .../pulsar/handlers/mqtt/MQTTCommonConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java index 0b8db658e..a1a0c7f08 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTCommonConfiguration.java @@ -148,7 +148,7 @@ public class MQTTCommonConfiguration extends ServiceConfiguration { @FieldContext( category = CATEGORY_MQTT_PROXY, required = false, - doc = "Whether start mqtt protocol handler with proxy mtls" + doc = "Whether use mTLS authenticate for mTLS connection" ) private boolean mqttProxyMTlsAuthenticationEnabled = false; From b33c1733373b7f011ad2720404ae2d1aa242bf25 Mon Sep 17 00:00:00 2001 From: Jiwe Guo Date: Tue, 10 Sep 2024 15:29:43 +0800 Subject: [PATCH 21/23] update --- .../mqtt/MQTTAuthenticationService.java | 24 ++++++++++++------- .../pulsar/handlers/mqtt/MQTTService.java | 3 ++- .../mqtt3/fusesource/proxy/ProxyTest.java | 4 ++-- .../mqtt/mqtt5/hivemq/base/ProxyMtlsTest.java | 3 +-- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java index 84637873e..25dd2d74f 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTAuthenticationService.java @@ -48,8 +48,12 @@ public class MQTTAuthenticationService { private final BrokerService brokerService; - public MQTTAuthenticationService(BrokerService brokerService, List authenticationMethods) { + private final boolean mqttProxyMTlsAuthenticationEnabled; + + public MQTTAuthenticationService(BrokerService brokerService, List authenticationMethods, boolean + mqttProxyMTlsAuthenticationEnabled) { this.brokerService = brokerService; + this.mqttProxyMTlsAuthenticationEnabled = mqttProxyMTlsAuthenticationEnabled; this.authenticationService = brokerService.getAuthenticationService(); this.authenticationProviders = getAuthenticationProviders(authenticationMethods); } @@ -60,22 +64,24 @@ private Map getAuthenticationProviders(List Date: Tue, 10 Sep 2024 15:41:18 +0800 Subject: [PATCH 22/23] update --- .github/workflows/pr_test.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/pr_test.yml b/.github/workflows/pr_test.yml index 9ce8e86b5..3b74a0051 100644 --- a/.github/workflows/pr_test.yml +++ b/.github/workflows/pr_test.yml @@ -23,17 +23,17 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 - name: Set up JDK 17 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: 17 @@ -55,7 +55,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Get All Tests id: list-test @@ -78,17 +78,17 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 - name: Set up JDK 17 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: 17 @@ -125,17 +125,17 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache Maven packages - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 - name: Set up JDK 17 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: 17 @@ -144,7 +144,7 @@ jobs: run: mvn clean install -DskipTests - name: Download jacoco artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: path: mqtt-impl/target From 9af7e82af893d7a87b7e5d1cadbf2fb495feb169 Mon Sep 17 00:00:00 2001 From: Cong Zhao Date: Tue, 10 Sep 2024 16:29:11 +0800 Subject: [PATCH 23/23] Remove duplicate cel depend --- pom.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index e12255ec9..c95faa726 100644 --- a/pom.xml +++ b/pom.xml @@ -96,11 +96,7 @@ - - dev.cel - cel - 0.5.2 - + io.grpc grpc-all