[ISSUE 9362] [RIP-77] Deprecate and Remove ACL 1.0 (#9363)

This commit is contained in:
dingshuangxi888
2025-04-30 15:02:55 +08:00
committed by RongtongJin
parent 50160bfdea
commit f75dc5a4d2
114 changed files with 633 additions and 8364 deletions
-75
View File
@@ -1,75 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
load("//bazel:GenTestRules.bzl", "GenTestRules")
java_library(
name = "acl",
srcs = glob(["src/main/java/**/*.java"]),
visibility = ["//visibility:public"],
deps = [
"//common",
"//remoting",
"//srvutil",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:com_github_luben_zstd_jni",
"@maven//:com_google_guava_guava",
"@maven//:com_google_protobuf_protobuf_java",
"@maven//:commons_codec_commons_codec",
"@maven//:commons_validator_commons_validator",
"@maven//:io_netty_netty_all",
"@maven//:org_apache_commons_commons_lang3",
"@maven//:org_apache_rocketmq_rocketmq_proto",
"@maven//:org_lz4_lz4_java",
"@maven//:org_yaml_snakeyaml",
"@maven//:io_github_aliyunmq_rocketmq_slf4j_api",
"@maven//:io_github_aliyunmq_rocketmq_logback_classic",
],
)
java_library(
name = "tests",
srcs = glob(["src/test/java/**/*.java"]),
resources = glob(["src/test/resources/**/*.yml"]),
visibility = ["//visibility:public"],
deps = [
":acl",
"//:test_deps",
"//common",
"//remoting",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:com_google_guava_guava",
"@maven//:commons_codec_commons_codec",
"@maven//:io_netty_netty_all",
"@maven//:org_apache_commons_commons_lang3",
"@maven//:org_springframework_spring_core",
"@maven//:org_yaml_snakeyaml",
],
)
GenTestRules(
name = "GeneratedTestRules",
# The following tests are not hermetic. Fix them later.
exclude_tests = [
],
medium_tests = [
"src/test/java/org/apache/rocketmq/acl/plain/PlainAccessValidatorTest",
],
test_files = glob(["src/test/java/**/*Test.java"]),
deps = [
":tests",
],
)
-90
View File
@@ -1,90 +0,0 @@
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements. See the NOTICE file distributed with this work for additional
information regarding copyright ownership. The ASF licenses this file to
You under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of
the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License. -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-all</artifactId>
<version>5.3.3-SNAPSHOT</version>
</parent>
<artifactId>rocketmq-acl</artifactId>
<name>rocketmq-acl ${project.version}</name>
<properties>
<project.root>${basedir}/..</project.root>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-proto</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-remoting</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-common</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-srvutil</artifactId>
</dependency>
<dependency>
<groupId>io.github.aliyunmq</groupId>
<artifactId>rocketmq-slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>io.github.aliyunmq</groupId>
<artifactId>rocketmq-logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -1,100 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl;
import com.google.protobuf.GeneratedMessageV3;
import java.util.List;
import java.util.Map;
import org.apache.rocketmq.acl.common.AuthenticationHeader;
import org.apache.rocketmq.common.AclConfig;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
public interface AccessValidator {
/**
* Parse to get the AccessResource(user, resource, needed permission)
*
* @param request
* @param remoteAddr
* @return Plain access resource result,include access key,signature and some other access attributes.
*/
AccessResource parse(RemotingCommand request, String remoteAddr);
/**
* Parse to get the AccessResource from gRPC protocol
* @param messageV3
* @param header
* @return Plain access resource
*/
AccessResource parse(GeneratedMessageV3 messageV3, AuthenticationHeader header);
/**
* Validate the access resource.
*
* @param accessResource
*/
void validate(AccessResource accessResource);
/**
* Update the access resource config
*
* @param plainAccessConfig
* @return
*/
boolean updateAccessConfig(PlainAccessConfig plainAccessConfig);
/**
* Delete the access resource config
*
* @return
*/
boolean deleteAccessConfig(String accessKey);
/**
* Get the access resource config version information
*
* @return
*/
@Deprecated
String getAclConfigVersion();
/**
* Update globalWhiteRemoteAddresses in acl yaml config file
*
* @return
*/
boolean updateGlobalWhiteAddrsConfig(List<String> globalWhiteAddrsList);
boolean updateGlobalWhiteAddrsConfig(List<String> globalWhiteAddrsList, String aclFileFullPath);
/**
* get broker cluster acl config information
*
* @return
*/
AclConfig getAllAclConfig();
/**
* get all access resource config version information
*
* @return
*/
Map<String, DataVersion> getAllAclConfigVersion();
}
@@ -1,22 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl;
public interface PermissionChecker {
void check(AccessResource checkedAccess, AccessResource ownedAccess);
}
@@ -1,60 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.common;
public class AclConstants {
public static final String CONFIG_GLOBAL_WHITE_ADDRS = "globalWhiteRemoteAddresses";
public static final String CONFIG_ACCOUNTS = "accounts";
public static final String CONFIG_ACCESS_KEY = "accessKey";
public static final String CONFIG_SECRET_KEY = "secretKey";
public static final String CONFIG_WHITE_ADDR = "whiteRemoteAddress";
public static final String CONFIG_ADMIN_ROLE = "admin";
public static final String CONFIG_DEFAULT_TOPIC_PERM = "defaultTopicPerm";
public static final String CONFIG_DEFAULT_GROUP_PERM = "defaultGroupPerm";
public static final String CONFIG_TOPIC_PERMS = "topicPerms";
public static final String CONFIG_GROUP_PERMS = "groupPerms";
public static final String CONFIG_DATA_VERSION = "dataVersion";
public static final String CONFIG_COUNTER = "counter";
public static final String CONFIG_TIME_STAMP = "timestamp";
public static final String PUB = "PUB";
public static final String SUB = "SUB";
public static final String DENY = "DENY";
public static final String PUB_SUB = "PUB|SUB";
public static final String SUB_PUB = "SUB|PUB";
public static final int ACCESS_KEY_MIN_LENGTH = 6;
public static final int SECRET_KEY_MIN_LENGTH = 6;
}
@@ -1,237 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.common;
import com.google.common.base.MoreObjects;
public class AuthenticationHeader {
private String remoteAddress;
private String tenantId;
private String namespace;
private String authorization;
private String datetime;
private String sessionToken;
private String requestId;
private String language;
private String clientVersion;
private String protocol;
private int requestCode;
AuthenticationHeader(final String remoteAddress, final String tenantId, final String namespace,
final String authorization, final String datetime, final String sessionToken, final String requestId,
final String language, final String clientVersion, final String protocol, final int requestCode) {
this.remoteAddress = remoteAddress;
this.tenantId = tenantId;
this.namespace = namespace;
this.authorization = authorization;
this.datetime = datetime;
this.sessionToken = sessionToken;
this.requestId = requestId;
this.language = language;
this.clientVersion = clientVersion;
this.protocol = protocol;
this.requestCode = requestCode;
}
public static class MetadataHeaderBuilder {
private String remoteAddress;
private String tenantId;
private String namespace;
private String authorization;
private String datetime;
private String sessionToken;
private String requestId;
private String language;
private String clientVersion;
private String protocol;
private int requestCode;
MetadataHeaderBuilder() {
}
public AuthenticationHeader.MetadataHeaderBuilder remoteAddress(final String remoteAddress) {
this.remoteAddress = remoteAddress;
return this;
}
public AuthenticationHeader.MetadataHeaderBuilder tenantId(final String tenantId) {
this.tenantId = tenantId;
return this;
}
public AuthenticationHeader.MetadataHeaderBuilder namespace(final String namespace) {
this.namespace = namespace;
return this;
}
public AuthenticationHeader.MetadataHeaderBuilder authorization(final String authorization) {
this.authorization = authorization;
return this;
}
public AuthenticationHeader.MetadataHeaderBuilder datetime(final String datetime) {
this.datetime = datetime;
return this;
}
public AuthenticationHeader.MetadataHeaderBuilder sessionToken(final String sessionToken) {
this.sessionToken = sessionToken;
return this;
}
public AuthenticationHeader.MetadataHeaderBuilder requestId(final String requestId) {
this.requestId = requestId;
return this;
}
public AuthenticationHeader.MetadataHeaderBuilder language(final String language) {
this.language = language;
return this;
}
public AuthenticationHeader.MetadataHeaderBuilder clientVersion(final String clientVersion) {
this.clientVersion = clientVersion;
return this;
}
public AuthenticationHeader.MetadataHeaderBuilder protocol(final String protocol) {
this.protocol = protocol;
return this;
}
public AuthenticationHeader.MetadataHeaderBuilder requestCode(final int requestCode) {
this.requestCode = requestCode;
return this;
}
public AuthenticationHeader build() {
return new AuthenticationHeader(this.remoteAddress, this.tenantId, this.namespace, this.authorization,
this.datetime, this.sessionToken, this.requestId, this.language, this.clientVersion, this.protocol,
this.requestCode);
}
}
public static AuthenticationHeader.MetadataHeaderBuilder builder() {
return new AuthenticationHeader.MetadataHeaderBuilder();
}
public String getRemoteAddress() {
return this.remoteAddress;
}
public String getTenantId() {
return this.tenantId;
}
public String getNamespace() {
return this.namespace;
}
public String getAuthorization() {
return this.authorization;
}
public String getDatetime() {
return this.datetime;
}
public String getSessionToken() {
return this.sessionToken;
}
public String getRequestId() {
return this.requestId;
}
public String getLanguage() {
return this.language;
}
public String getClientVersion() {
return this.clientVersion;
}
public String getProtocol() {
return this.protocol;
}
public int getRequestCode() {
return this.requestCode;
}
public void setRemoteAddress(final String remoteAddress) {
this.remoteAddress = remoteAddress;
}
public void setTenantId(final String tenantId) {
this.tenantId = tenantId;
}
public void setNamespace(final String namespace) {
this.namespace = namespace;
}
public void setAuthorization(final String authorization) {
this.authorization = authorization;
}
public void setDatetime(final String datetime) {
this.datetime = datetime;
}
public void setSessionToken(final String sessionToken) {
this.sessionToken = sessionToken;
}
public void setRequestId(final String requestId) {
this.requestId = requestId;
}
public void setLanguage(final String language) {
this.language = language;
}
public void setClientVersion(final String clientVersion) {
this.clientVersion = clientVersion;
}
public void setProtocol(final String protocol) {
this.protocol = protocol;
}
public void setRequestCode(int requestCode) {
this.requestCode = requestCode;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("remoteAddress", remoteAddress)
.add("tenantId", tenantId)
.add("namespace", namespace)
.add("authorization", authorization)
.add("datetime", datetime)
.add("sessionToken", sessionToken)
.add("requestId", requestId)
.add("language", language)
.add("clientVersion", clientVersion)
.add("protocol", protocol)
.add("requestCode", requestCode)
.toString();
}
}
@@ -1,122 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.common;
import com.google.common.base.MoreObjects;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
public class AuthorizationHeader {
private static final String HEADER_SEPARATOR = " ";
private static final String CREDENTIALS_SEPARATOR = "/";
private static final int AUTH_HEADER_KV_LENGTH = 2;
private static final String CREDENTIAL = "Credential";
private static final String SIGNED_HEADERS = "SignedHeaders";
private static final String SIGNATURE = "Signature";
private String method;
private String accessKey;
private String[] signedHeaders;
private String signature;
/**
* Parse authorization from gRPC header.
*
* @param header gRPC header string.
* @throws Exception exception.
*/
public AuthorizationHeader(String header) throws DecoderException {
String[] result = header.split(HEADER_SEPARATOR, 2);
if (result.length != 2) {
throw new DecoderException("authorization header is incorrect");
}
this.method = result[0];
String[] keyValues = result[1].split(",");
for (String keyValue : keyValues) {
String[] kv = keyValue.trim().split("=", 2);
int kvLength = kv.length;
if (kv.length != AUTH_HEADER_KV_LENGTH) {
throw new DecoderException("authorization keyValues length is incorrect, actual length=" + kvLength);
}
String authItem = kv[0];
if (CREDENTIAL.equals(authItem)) {
String[] credential = kv[1].split(CREDENTIALS_SEPARATOR);
int credentialActualLength = credential.length;
if (credentialActualLength == 0) {
throw new DecoderException("authorization credential length is incorrect, actual length=" + credentialActualLength);
}
this.accessKey = credential[0];
continue;
}
if (SIGNED_HEADERS.equals(authItem)) {
this.signedHeaders = kv[1].split(";");
continue;
}
if (SIGNATURE.equals(authItem)) {
this.signature = this.hexToBase64(kv[1]);
}
}
}
public String hexToBase64(String input) throws DecoderException {
byte[] bytes = Hex.decodeHex(input);
return Base64.encodeBase64String(bytes);
}
public String getMethod() {
return this.method;
}
public String getAccessKey() {
return this.accessKey;
}
public String[] getSignedHeaders() {
return this.signedHeaders;
}
public String getSignature() {
return this.signature;
}
public void setMethod(final String method) {
this.method = method;
}
public void setAccessKey(final String accessKey) {
this.accessKey = accessKey;
}
public void setSignedHeaders(final String[] signedHeaders) {
this.signedHeaders = signedHeaders;
}
public void setSignature(final String signature) {
this.signature = signature;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("method", method)
.add("accessKey", accessKey)
.add("signedHeaders", signedHeaders)
.add("signature", signature)
.toString();
}
}
@@ -1,122 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.common;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.acl.plain.PlainAccessResource;
import org.apache.rocketmq.remoting.protocol.RequestCode;
public class Permission {
public static final byte DENY = 1;
public static final byte ANY = 1 << 1;
public static final byte PUB = 1 << 2;
public static final byte SUB = 1 << 3;
public static final Set<Integer> ADMIN_CODE = new HashSet<>();
static {
// UPDATE_AND_CREATE_TOPIC
ADMIN_CODE.add(RequestCode.UPDATE_AND_CREATE_TOPIC);
// UPDATE_BROKER_CONFIG
ADMIN_CODE.add(RequestCode.UPDATE_BROKER_CONFIG);
// DELETE_TOPIC_IN_BROKER
ADMIN_CODE.add(RequestCode.DELETE_TOPIC_IN_BROKER);
// UPDATE_AND_CREATE_SUBSCRIPTIONGROUP
ADMIN_CODE.add(RequestCode.UPDATE_AND_CREATE_SUBSCRIPTIONGROUP);
// DELETE_SUBSCRIPTIONGROUP
ADMIN_CODE.add(RequestCode.DELETE_SUBSCRIPTIONGROUP);
// UPDATE_AND_CREATE_STATIC_TOPIC
ADMIN_CODE.add(RequestCode.UPDATE_AND_CREATE_STATIC_TOPIC);
// UPDATE_AND_CREATE_ACL_CONFIG
ADMIN_CODE.add(RequestCode.UPDATE_AND_CREATE_ACL_CONFIG);
// DELETE_ACL_CONFIG
ADMIN_CODE.add(RequestCode.DELETE_ACL_CONFIG);
// GET_BROKER_CLUSTER_ACL_INFO
ADMIN_CODE.add(RequestCode.GET_BROKER_CLUSTER_ACL_INFO);
}
public static boolean checkPermission(byte neededPerm, byte ownedPerm) {
if ((ownedPerm & DENY) > 0) {
return false;
}
if ((neededPerm & ANY) > 0) {
return (ownedPerm & PUB) > 0 || (ownedPerm & SUB) > 0;
}
return (neededPerm & ownedPerm) > 0;
}
public static byte parsePermFromString(String permString) {
if (permString == null) {
return Permission.DENY;
}
switch (permString.trim()) {
case AclConstants.PUB:
return Permission.PUB;
case AclConstants.SUB:
return Permission.SUB;
case AclConstants.PUB_SUB:
case AclConstants.SUB_PUB:
return Permission.PUB | Permission.SUB;
case AclConstants.DENY:
return Permission.DENY;
default:
return Permission.DENY;
}
}
public static void parseResourcePerms(PlainAccessResource plainAccessResource, Boolean isTopic,
List<String> resources) {
if (resources == null || resources.isEmpty()) {
return;
}
for (String resource : resources) {
String[] items = StringUtils.split(resource, "=");
if (items.length == 2) {
plainAccessResource.addResourceAndPerm(isTopic ? items[0].trim() : PlainAccessResource.getRetryTopic(items[0].trim()), parsePermFromString(items[1].trim()));
} else {
throw new AclException(String.format("Parse resource permission failed for %s:%s", isTopic ? "topic" : "group", resource));
}
}
}
public static void checkResourcePerms(List<String> resources) {
if (resources == null || resources.isEmpty()) {
return;
}
for (String resource : resources) {
String[] items = StringUtils.split(resource, "=");
if (items.length != 2) {
throw new AclException(String.format("Parse Resource format error for %s.\n" +
"The expected resource format is 'Res=Perm'. For example: topicA=SUB", resource));
}
if (!AclConstants.DENY.equals(items[1].trim()) && Permission.DENY == Permission.parsePermFromString(items[1].trim())) {
throw new AclException(String.format("Parse resource permission error for %s.\n" +
"The expected permissions are 'SUB' or 'PUB' or 'SUB|PUB' or 'PUB|SUB'.", resource));
}
}
}
public static boolean needAdminPerm(Integer code) {
return ADMIN_CODE.contains(code);
}
}
@@ -1,471 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import apache.rocketmq.v2.AckMessageRequest;
import apache.rocketmq.v2.ChangeInvisibleDurationRequest;
import apache.rocketmq.v2.ClientType;
import apache.rocketmq.v2.EndTransactionRequest;
import apache.rocketmq.v2.ForwardMessageToDeadLetterQueueRequest;
import apache.rocketmq.v2.HeartbeatRequest;
import apache.rocketmq.v2.Message;
import apache.rocketmq.v2.NotifyClientTerminationRequest;
import apache.rocketmq.v2.QueryAssignmentRequest;
import apache.rocketmq.v2.QueryRouteRequest;
import apache.rocketmq.v2.RecallMessageRequest;
import apache.rocketmq.v2.ReceiveMessageRequest;
import apache.rocketmq.v2.Resource;
import apache.rocketmq.v2.SendMessageRequest;
import apache.rocketmq.v2.Subscription;
import apache.rocketmq.v2.SubscriptionEntry;
import apache.rocketmq.v2.TelemetryCommand;
import com.google.protobuf.GeneratedMessageV3;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.rocketmq.acl.AccessResource;
import org.apache.rocketmq.acl.common.AclException;
import org.apache.rocketmq.acl.common.AclUtils;
import org.apache.rocketmq.acl.common.AuthenticationHeader;
import org.apache.rocketmq.acl.common.AuthorizationHeader;
import org.apache.rocketmq.acl.common.Permission;
import org.apache.rocketmq.acl.common.SessionCredentials;
import org.apache.rocketmq.common.KeyBuilder;
import org.apache.rocketmq.common.MQVersion;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.protocol.NamespaceUtil;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.remoting.protocol.RequestCode;
import org.apache.rocketmq.remoting.protocol.ResponseCode;
import org.apache.rocketmq.remoting.protocol.header.GetConsumerListByGroupRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UnregisterClientRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UpdateConsumerOffsetRequestHeader;
import org.apache.rocketmq.remoting.protocol.heartbeat.ConsumerData;
import org.apache.rocketmq.remoting.protocol.heartbeat.HeartbeatData;
import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
public class PlainAccessResource implements AccessResource {
// Identify the user
private String accessKey;
private String secretKey;
private String whiteRemoteAddress;
private boolean admin;
private byte defaultTopicPerm = 1;
private byte defaultGroupPerm = 1;
private Map<String, Byte> resourcePermMap;
private RemoteAddressStrategy remoteAddressStrategy;
private int requestCode;
// The content to calculate the content
private byte[] content;
private String signature;
private String secretToken;
private String recognition;
public PlainAccessResource() {
}
public static PlainAccessResource parse(RemotingCommand request, String remoteAddr) {
PlainAccessResource accessResource = new PlainAccessResource();
if (remoteAddr != null && remoteAddr.contains(":")) {
accessResource.setWhiteRemoteAddress(remoteAddr.substring(0, remoteAddr.lastIndexOf(':')));
} else {
accessResource.setWhiteRemoteAddress(remoteAddr);
}
accessResource.setRequestCode(request.getCode());
if (request.getExtFields() == null) {
// If request's extFields is null,then return accessResource directly(users can use whiteAddress pattern)
// The following logic codes depend on the request's extFields not to be null.
return accessResource;
}
accessResource.setAccessKey(request.getExtFields().get(SessionCredentials.ACCESS_KEY));
accessResource.setSignature(request.getExtFields().get(SessionCredentials.SIGNATURE));
accessResource.setSecretToken(request.getExtFields().get(SessionCredentials.SECURITY_TOKEN));
try {
switch (request.getCode()) {
case RequestCode.SEND_MESSAGE:
final String topic = request.getExtFields().get("topic");
accessResource.addResourceAndPerm(topic, PlainAccessResource.isRetryTopic(topic) ? Permission.SUB : Permission.PUB);
break;
case RequestCode.SEND_MESSAGE_V2:
case RequestCode.SEND_BATCH_MESSAGE:
final String topicV2 = request.getExtFields().get("b");
accessResource.addResourceAndPerm(topicV2, PlainAccessResource.isRetryTopic(topicV2) ? Permission.SUB : Permission.PUB);
break;
case RequestCode.RECALL_MESSAGE:
accessResource.addResourceAndPerm(request.getExtFields().get("topic"), Permission.PUB);
break;
case RequestCode.CONSUMER_SEND_MSG_BACK:
accessResource.addResourceAndPerm(getRetryTopic(request.getExtFields().get("group")), Permission.SUB);
break;
case RequestCode.PULL_MESSAGE:
accessResource.addResourceAndPerm(request.getExtFields().get("topic"), Permission.SUB);
accessResource.addResourceAndPerm(getRetryTopic(request.getExtFields().get("consumerGroup")), Permission.SUB);
break;
case RequestCode.QUERY_MESSAGE:
accessResource.addResourceAndPerm(request.getExtFields().get("topic"), Permission.SUB);
break;
case RequestCode.HEART_BEAT:
HeartbeatData heartbeatData = HeartbeatData.decode(request.getBody(), HeartbeatData.class);
for (ConsumerData data : heartbeatData.getConsumerDataSet()) {
accessResource.addResourceAndPerm(getRetryTopic(data.getGroupName()), Permission.SUB);
for (SubscriptionData subscriptionData : data.getSubscriptionDataSet()) {
accessResource.addResourceAndPerm(subscriptionData.getTopic(), Permission.SUB);
}
}
break;
case RequestCode.UNREGISTER_CLIENT:
final UnregisterClientRequestHeader unregisterClientRequestHeader =
(UnregisterClientRequestHeader) request
.decodeCommandCustomHeader(UnregisterClientRequestHeader.class);
accessResource.addResourceAndPerm(getRetryTopic(unregisterClientRequestHeader.getConsumerGroup()), Permission.SUB);
break;
case RequestCode.GET_CONSUMER_LIST_BY_GROUP:
final GetConsumerListByGroupRequestHeader getConsumerListByGroupRequestHeader =
(GetConsumerListByGroupRequestHeader) request
.decodeCommandCustomHeader(GetConsumerListByGroupRequestHeader.class);
accessResource.addResourceAndPerm(getRetryTopic(getConsumerListByGroupRequestHeader.getConsumerGroup()), Permission.SUB);
break;
case RequestCode.UPDATE_CONSUMER_OFFSET:
final UpdateConsumerOffsetRequestHeader updateConsumerOffsetRequestHeader =
(UpdateConsumerOffsetRequestHeader) request
.decodeCommandCustomHeader(UpdateConsumerOffsetRequestHeader.class);
accessResource.addResourceAndPerm(getRetryTopic(updateConsumerOffsetRequestHeader.getConsumerGroup()), Permission.SUB);
accessResource.addResourceAndPerm(updateConsumerOffsetRequestHeader.getTopic(), Permission.SUB);
break;
default:
break;
}
} catch (Throwable t) {
throw new AclException(t.getMessage(), t);
}
// Content
SortedMap<String, String> map = new TreeMap<>();
for (Map.Entry<String, String> entry : request.getExtFields().entrySet()) {
if (request.getVersion() <= MQVersion.Version.V4_9_3.ordinal() &&
MixAll.UNIQUE_MSG_QUERY_FLAG.equals(entry.getKey())) {
continue;
}
if (!SessionCredentials.SIGNATURE.equals(entry.getKey())) {
map.put(entry.getKey(), entry.getValue());
}
}
accessResource.setContent(AclUtils.combineRequestContent(request, map));
return accessResource;
}
public static PlainAccessResource parse(GeneratedMessageV3 messageV3, AuthenticationHeader header) {
PlainAccessResource accessResource = new PlainAccessResource();
String remoteAddress = header.getRemoteAddress();
if (remoteAddress != null && remoteAddress.contains(":")) {
accessResource.setWhiteRemoteAddress(RemotingHelper.parseHostFromAddress(remoteAddress));
} else {
accessResource.setWhiteRemoteAddress(remoteAddress);
}
try {
AuthorizationHeader authorizationHeader = new AuthorizationHeader(header.getAuthorization());
accessResource.setAccessKey(authorizationHeader.getAccessKey());
accessResource.setSignature(authorizationHeader.getSignature());
} catch (DecoderException e) {
throw new AclException(e.getMessage(), e);
}
accessResource.setSecretToken(header.getSessionToken());
accessResource.setRequestCode(header.getRequestCode());
accessResource.setContent(header.getDatetime().getBytes(StandardCharsets.UTF_8));
try {
String rpcFullName = messageV3.getDescriptorForType().getFullName();
if (HeartbeatRequest.getDescriptor().getFullName().equals(rpcFullName)) {
HeartbeatRequest request = (HeartbeatRequest) messageV3;
if (ClientType.PUSH_CONSUMER.equals(request.getClientType())
|| ClientType.SIMPLE_CONSUMER.equals(request.getClientType())) {
if (!request.hasGroup()) {
throw new AclException("Consumer heartbeat doesn't have group");
} else {
accessResource.addGroupResourceAndPerm(request.getGroup(), Permission.SUB);
}
}
} else if (SendMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) {
SendMessageRequest request = (SendMessageRequest) messageV3;
if (request.getMessagesCount() <= 0) {
throw new AclException("SendMessageRequest, messageCount is zero", ResponseCode.MESSAGE_ILLEGAL);
}
Resource topic = request.getMessages(0).getTopic();
for (Message message : request.getMessagesList()) {
if (!message.getTopic().equals(topic)) {
throw new AclException("SendMessageRequest, messages' topic is not consistent", ResponseCode.MESSAGE_ILLEGAL);
}
}
accessResource.addResourceAndPerm(topic, Permission.PUB);
} else if (RecallMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) {
RecallMessageRequest request = (RecallMessageRequest) messageV3;
accessResource.addResourceAndPerm(request.getTopic(), Permission.PUB);
} else if (ReceiveMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) {
ReceiveMessageRequest request = (ReceiveMessageRequest) messageV3;
accessResource.addGroupResourceAndPerm(request.getGroup(), Permission.SUB);
accessResource.addResourceAndPerm(request.getMessageQueue().getTopic(), Permission.SUB);
} else if (AckMessageRequest.getDescriptor().getFullName().equals(rpcFullName)) {
AckMessageRequest request = (AckMessageRequest) messageV3;
accessResource.addGroupResourceAndPerm(request.getGroup(), Permission.SUB);
accessResource.addResourceAndPerm(request.getTopic(), Permission.SUB);
} else if (ForwardMessageToDeadLetterQueueRequest.getDescriptor().getFullName().equals(rpcFullName)) {
ForwardMessageToDeadLetterQueueRequest request = (ForwardMessageToDeadLetterQueueRequest) messageV3;
accessResource.addGroupResourceAndPerm(request.getGroup(), Permission.SUB);
accessResource.addResourceAndPerm(request.getTopic(), Permission.SUB);
} else if (EndTransactionRequest.getDescriptor().getFullName().equals(rpcFullName)) {
EndTransactionRequest request = (EndTransactionRequest) messageV3;
accessResource.addResourceAndPerm(request.getTopic(), Permission.PUB);
} else if (TelemetryCommand.getDescriptor().getFullName().equals(rpcFullName)) {
TelemetryCommand command = (TelemetryCommand) messageV3;
if (command.getCommandCase() == TelemetryCommand.CommandCase.SETTINGS) {
if (command.getSettings().hasPublishing()) {
List<Resource> topicList = command.getSettings().getPublishing().getTopicsList();
for (Resource topic : topicList) {
accessResource.addResourceAndPerm(topic, Permission.PUB);
}
}
if (command.getSettings().hasSubscription()) {
Subscription subscription = command.getSettings().getSubscription();
accessResource.addGroupResourceAndPerm(subscription.getGroup(), Permission.SUB);
for (SubscriptionEntry entry : subscription.getSubscriptionsList()) {
accessResource.addResourceAndPerm(entry.getTopic(), Permission.SUB);
}
}
if (!command.getSettings().hasPublishing() && !command.getSettings().hasSubscription()) {
throw new AclException("settings command doesn't have publishing or subscription");
}
}
} else if (NotifyClientTerminationRequest.getDescriptor().getFullName().equals(rpcFullName)) {
NotifyClientTerminationRequest request = (NotifyClientTerminationRequest) messageV3;
if (StringUtils.isNotBlank(request.getGroup().getName())) {
accessResource.addGroupResourceAndPerm(request.getGroup(), Permission.SUB);
}
} else if (QueryRouteRequest.getDescriptor().getFullName().equals(rpcFullName)) {
QueryRouteRequest request = (QueryRouteRequest) messageV3;
accessResource.addResourceAndPerm(request.getTopic(), Permission.ANY);
} else if (QueryAssignmentRequest.getDescriptor().getFullName().equals(rpcFullName)) {
QueryAssignmentRequest request = (QueryAssignmentRequest) messageV3;
accessResource.addGroupResourceAndPerm(request.getGroup(), Permission.SUB);
accessResource.addResourceAndPerm(request.getTopic(), Permission.SUB);
} else if (ChangeInvisibleDurationRequest.getDescriptor().getFullName().equals(rpcFullName)) {
ChangeInvisibleDurationRequest request = (ChangeInvisibleDurationRequest) messageV3;
accessResource.addGroupResourceAndPerm(request.getGroup(), Permission.SUB);
accessResource.addResourceAndPerm(request.getTopic(), Permission.SUB);
}
} catch (Throwable t) {
throw new AclException(t.getMessage(), t);
}
return accessResource;
}
private void addResourceAndPerm(Resource resource, byte permission) {
String resourceName = NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName());
addResourceAndPerm(resourceName, permission);
}
private void addGroupResourceAndPerm(Resource resource, byte permission) {
String resourceName = NamespaceUtil.wrapNamespace(resource.getResourceNamespace(), resource.getName());
addResourceAndPerm(getRetryTopic(resourceName), permission);
}
public static PlainAccessResource build(PlainAccessConfig plainAccessConfig, RemoteAddressStrategy remoteAddressStrategy) {
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setAccessKey(plainAccessConfig.getAccessKey());
plainAccessResource.setSecretKey(plainAccessConfig.getSecretKey());
plainAccessResource.setWhiteRemoteAddress(plainAccessConfig.getWhiteRemoteAddress());
plainAccessResource.setAdmin(plainAccessConfig.isAdmin());
plainAccessResource.setDefaultGroupPerm(Permission.parsePermFromString(plainAccessConfig.getDefaultGroupPerm()));
plainAccessResource.setDefaultTopicPerm(Permission.parsePermFromString(plainAccessConfig.getDefaultTopicPerm()));
Permission.parseResourcePerms(plainAccessResource, false, plainAccessConfig.getGroupPerms());
Permission.parseResourcePerms(plainAccessResource, true, plainAccessConfig.getTopicPerms());
plainAccessResource.setRemoteAddressStrategy(remoteAddressStrategy);
return plainAccessResource;
}
public static boolean isRetryTopic(String topic) {
return null != topic && topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX);
}
public static String printStr(String resource, boolean isGroup) {
if (resource == null) {
return null;
}
if (isGroup) {
return String.format("%s:%s", "group", getGroupFromRetryTopic(resource));
} else {
return String.format("%s:%s", "topic", resource);
}
}
public static String getGroupFromRetryTopic(String retryTopic) {
if (retryTopic == null) {
return null;
}
return KeyBuilder.parseGroup(retryTopic);
}
public static String getRetryTopic(String group) {
if (group == null) {
return null;
}
return MixAll.getRetryTopic(group);
}
public void addResourceAndPerm(String resource, byte perm) {
if (resource == null) {
return;
}
if (resourcePermMap == null) {
resourcePermMap = new HashMap<>();
}
resourcePermMap.put(resource, perm);
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getWhiteRemoteAddress() {
return whiteRemoteAddress;
}
public void setWhiteRemoteAddress(String whiteRemoteAddress) {
this.whiteRemoteAddress = whiteRemoteAddress;
}
public boolean isAdmin() {
return admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
public byte getDefaultTopicPerm() {
return defaultTopicPerm;
}
public void setDefaultTopicPerm(byte defaultTopicPerm) {
this.defaultTopicPerm = defaultTopicPerm;
}
public byte getDefaultGroupPerm() {
return defaultGroupPerm;
}
public void setDefaultGroupPerm(byte defaultGroupPerm) {
this.defaultGroupPerm = defaultGroupPerm;
}
public Map<String, Byte> getResourcePermMap() {
return resourcePermMap;
}
public String getRecognition() {
return recognition;
}
public void setRecognition(String recognition) {
this.recognition = recognition;
}
public int getRequestCode() {
return requestCode;
}
public void setRequestCode(int requestCode) {
this.requestCode = requestCode;
}
public String getSecretToken() {
return secretToken;
}
public void setSecretToken(String secretToken) {
this.secretToken = secretToken;
}
public RemoteAddressStrategy getRemoteAddressStrategy() {
return remoteAddressStrategy;
}
public void setRemoteAddressStrategy(RemoteAddressStrategy remoteAddressStrategy) {
this.remoteAddressStrategy = remoteAddressStrategy;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
public byte[] getContent() {
return content;
}
public void setContent(byte[] content) {
this.content = content;
}
}
@@ -1,87 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import com.google.protobuf.GeneratedMessageV3;
import java.util.List;
import java.util.Map;
import org.apache.rocketmq.acl.AccessResource;
import org.apache.rocketmq.acl.AccessValidator;
import org.apache.rocketmq.acl.common.AuthenticationHeader;
import org.apache.rocketmq.common.AclConfig;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
public class PlainAccessValidator implements AccessValidator {
private PlainPermissionManager aclPlugEngine;
public PlainAccessValidator() {
aclPlugEngine = new PlainPermissionManager();
}
@Override
public AccessResource parse(RemotingCommand request, String remoteAddr) {
return PlainAccessResource.parse(request, remoteAddr);
}
@Override
public AccessResource parse(GeneratedMessageV3 messageV3, AuthenticationHeader header) {
return PlainAccessResource.parse(messageV3, header);
}
@Override
public void validate(AccessResource accessResource) {
aclPlugEngine.validate((PlainAccessResource) accessResource);
}
@Override
public boolean updateAccessConfig(PlainAccessConfig plainAccessConfig) {
return aclPlugEngine.updateAccessConfig(plainAccessConfig);
}
@Override
public boolean deleteAccessConfig(String accessKey) {
return aclPlugEngine.deleteAccessConfig(accessKey);
}
@Override
public String getAclConfigVersion() {
return aclPlugEngine.getAclConfigDataVersion();
}
@Override
public boolean updateGlobalWhiteAddrsConfig(List<String> globalWhiteAddrsList) {
return aclPlugEngine.updateGlobalWhiteAddrsConfig(globalWhiteAddrsList);
}
@Override
public boolean updateGlobalWhiteAddrsConfig(List<String> globalWhiteAddrsList, String aclFileFullPath) {
return aclPlugEngine.updateGlobalWhiteAddrsConfig(globalWhiteAddrsList, aclFileFullPath);
}
@Override
public AclConfig getAllAclConfig() {
return aclPlugEngine.getAllAclConfig();
}
@Override
public Map<String, DataVersion> getAllAclConfigVersion() {
return aclPlugEngine.getDataVersionMap();
}
}
@@ -1,66 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import java.util.Map;
import org.apache.rocketmq.acl.AccessResource;
import org.apache.rocketmq.acl.PermissionChecker;
import org.apache.rocketmq.acl.common.AclException;
import org.apache.rocketmq.acl.common.Permission;
public class PlainPermissionChecker implements PermissionChecker {
public void check(AccessResource checkedAccess, AccessResource ownedAccess) {
PlainAccessResource checkedPlainAccess = (PlainAccessResource) checkedAccess;
PlainAccessResource ownedPlainAccess = (PlainAccessResource) ownedAccess;
if (ownedPlainAccess.isAdmin()) {
// admin user don't need verification
return;
}
if (Permission.needAdminPerm(checkedPlainAccess.getRequestCode())) {
throw new AclException(String.format("Need admin permission for request code=%d, but accessKey=%s is not", checkedPlainAccess.getRequestCode(), ownedPlainAccess.getAccessKey()));
}
Map<String, Byte> needCheckedPermMap = checkedPlainAccess.getResourcePermMap();
Map<String, Byte> ownedPermMap = ownedPlainAccess.getResourcePermMap();
if (needCheckedPermMap == null) {
// If the needCheckedPermMap is null,then return
return;
}
for (Map.Entry<String, Byte> needCheckedEntry : needCheckedPermMap.entrySet()) {
String resource = needCheckedEntry.getKey();
Byte neededPerm = needCheckedEntry.getValue();
boolean isGroup = PlainAccessResource.isRetryTopic(resource);
if (ownedPermMap == null || !ownedPermMap.containsKey(resource)) {
// Check the default perm
byte ownedPerm = isGroup ? ownedPlainAccess.getDefaultGroupPerm() :
ownedPlainAccess.getDefaultTopicPerm();
if (!Permission.checkPermission(neededPerm, ownedPerm)) {
throw new AclException(String.format("No default permission for %s", PlainAccessResource.printStr(resource, isGroup)));
}
continue;
}
if (!Permission.checkPermission(neededPerm, ownedPermMap.get(resource))) {
throw new AclException(String.format("No permission for %s", PlainAccessResource.printStr(resource, isGroup)));
}
}
}
}
@@ -1,644 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.acl.PermissionChecker;
import org.apache.rocketmq.acl.common.AclConstants;
import org.apache.rocketmq.acl.common.AclException;
import org.apache.rocketmq.acl.common.AclSigner;
import org.apache.rocketmq.acl.common.AclUtils;
import org.apache.rocketmq.acl.common.Permission;
import org.apache.rocketmq.common.AclConfig;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.topic.TopicValidator;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.apache.rocketmq.srvutil.AclFileWatchService;
public class PlainPermissionManager {
private static final Logger log = LoggerFactory.getLogger(LoggerName.COMMON_LOGGER_NAME);
private String fileHome = System.getProperty(MixAll.ROCKETMQ_HOME_PROPERTY,
System.getenv(MixAll.ROCKETMQ_HOME_ENV));
private String defaultAclDir;
private String defaultAclFile;
private Map<String/** fileFullPath **/, Map<String/** AccessKey **/, PlainAccessResource>> aclPlainAccessResourceMap = new HashMap<>();
private Map<String/** AccessKey **/, String/** fileFullPath **/> accessKeyTable = new HashMap<>();
private List<RemoteAddressStrategy> globalWhiteRemoteAddressStrategy = new ArrayList<>();
private RemoteAddressStrategyFactory remoteAddressStrategyFactory = new RemoteAddressStrategyFactory();
private Map<String/** fileFullPath **/, List<RemoteAddressStrategy>> globalWhiteRemoteAddressStrategyMap = new HashMap<>();
private boolean isWatchStart;
private Map<String/** fileFullPath **/, DataVersion> dataVersionMap = new HashMap<>();
@Deprecated
private final DataVersion dataVersion = new DataVersion();
private List<String> fileList = new ArrayList<>();
private final PermissionChecker permissionChecker = new PlainPermissionChecker();
public PlainPermissionManager() {
this.defaultAclDir = MixAll.dealFilePath(fileHome + File.separator + "conf" + File.separator + "acl");
this.defaultAclFile = MixAll.dealFilePath(fileHome + File.separator + System.getProperty("rocketmq.acl.plain.file", "conf" + File.separator + "plain_acl.yml"));
load();
watch();
}
public List<String> getAllAclFiles(String path) {
if (!new File(path).exists()) {
log.info("The default acl dir {} is not exist", path);
return new ArrayList<>();
}
List<String> allAclFileFullPath = new ArrayList<>();
File file = new File(path);
File[] files = file.listFiles();
for (int i = 0; files != null && i < files.length; i++) {
String fileName = files[i].getAbsolutePath();
File f = new File(fileName);
if (fileName.equals(fileHome + MixAll.ACL_CONF_TOOLS_FILE)) {
continue;
} else if (fileName.endsWith(".yml") || fileName.endsWith(".yaml")) {
allAclFileFullPath.add(fileName);
} else if (f.isDirectory()) {
allAclFileFullPath.addAll(getAllAclFiles(fileName));
}
}
return allAclFileFullPath;
}
public void load() {
if (fileHome == null || fileHome.isEmpty()) {
return;
}
Map<String, Map<String, PlainAccessResource>> aclPlainAccessResourceMap = new HashMap<>();
Map<String, String> accessKeyTable = new HashMap<>();
List<RemoteAddressStrategy> globalWhiteRemoteAddressStrategy = new ArrayList<>();
Map<String, List<RemoteAddressStrategy>> globalWhiteRemoteAddressStrategyMap = new HashMap<>();
Map<String, DataVersion> dataVersionMap = new HashMap<>();
assureAclConfigFilesExist();
fileList = getAllAclFiles(defaultAclDir);
if (new File(defaultAclFile).exists() && !fileList.contains(defaultAclFile)) {
fileList.add(defaultAclFile);
}
for (String path : fileList) {
final String currentFile = MixAll.dealFilePath(path);
PlainAccessData plainAclConfData = AclUtils.getYamlDataObject(currentFile, PlainAccessData.class);
if (plainAclConfData == null) {
log.warn("No data in file {}", currentFile);
continue;
}
log.info("Broker plain acl conf data is : {}", plainAclConfData.toString());
List<RemoteAddressStrategy> globalWhiteRemoteAddressStrategyList = new ArrayList<>();
List<String> globalWhiteRemoteAddressesList = plainAclConfData.getGlobalWhiteRemoteAddresses();
if (globalWhiteRemoteAddressesList != null && !globalWhiteRemoteAddressesList.isEmpty()) {
for (String address : globalWhiteRemoteAddressesList) {
globalWhiteRemoteAddressStrategyList.add(remoteAddressStrategyFactory.getRemoteAddressStrategy(address));
}
}
if (!globalWhiteRemoteAddressStrategyList.isEmpty()) {
globalWhiteRemoteAddressStrategyMap.put(currentFile, globalWhiteRemoteAddressStrategyList);
globalWhiteRemoteAddressStrategy.addAll(globalWhiteRemoteAddressStrategyList);
}
List<PlainAccessConfig> accounts = plainAclConfData.getAccounts();
Map<String, PlainAccessResource> plainAccessResourceMap = new HashMap<>();
if (accounts != null && !accounts.isEmpty()) {
for (PlainAccessConfig plainAccessConfig : accounts) {
PlainAccessResource plainAccessResource = buildPlainAccessResource(plainAccessConfig);
//AccessKey can not be defined in multiple ACL files
if (accessKeyTable.get(plainAccessResource.getAccessKey()) == null) {
plainAccessResourceMap.put(plainAccessResource.getAccessKey(), plainAccessResource);
accessKeyTable.put(plainAccessResource.getAccessKey(), currentFile);
} else {
log.warn("The accessKey {} is repeated in multiple ACL files", plainAccessResource.getAccessKey());
}
}
}
if (!plainAccessResourceMap.isEmpty()) {
aclPlainAccessResourceMap.put(currentFile, plainAccessResourceMap);
}
List<PlainAccessData.DataVersion> dataVersions = plainAclConfData.getDataVersion();
DataVersion dataVersion = new DataVersion();
if (dataVersions != null && !dataVersions.isEmpty()) {
DataVersion firstElement = new DataVersion();
firstElement.setCounter(new AtomicLong(dataVersions.get(0).getCounter()));
firstElement.setTimestamp(dataVersions.get(0).getTimestamp());
dataVersion.assignNewOne(firstElement);
}
dataVersionMap.put(currentFile, dataVersion);
}
if (dataVersionMap.containsKey(defaultAclFile)) {
this.dataVersion.assignNewOne(dataVersionMap.get(defaultAclFile));
}
this.dataVersionMap = dataVersionMap;
this.globalWhiteRemoteAddressStrategyMap = globalWhiteRemoteAddressStrategyMap;
this.globalWhiteRemoteAddressStrategy = globalWhiteRemoteAddressStrategy;
this.aclPlainAccessResourceMap = aclPlainAccessResourceMap;
this.accessKeyTable = accessKeyTable;
}
/**
* Currently GlobalWhiteAddress is defined in {@link #defaultAclFile}, so make sure it exists.
*/
private void assureAclConfigFilesExist() {
final Path defaultAclFilePath = Paths.get(this.defaultAclFile);
if (!Files.exists(defaultAclFilePath)) {
try {
Files.createFile(defaultAclFilePath);
} catch (FileAlreadyExistsException e) {
// Maybe created by other threads
} catch (IOException e) {
log.error("Error in creating " + this.defaultAclFile, e);
throw new AclException(e.getMessage());
}
}
}
public void load(String aclFilePath) {
aclFilePath = MixAll.dealFilePath(aclFilePath);
Map<String, PlainAccessResource> plainAccessResourceMap = new HashMap<>();
List<RemoteAddressStrategy> globalWhiteRemoteAddressStrategy = new ArrayList<>();
PlainAccessData plainAclConfData = AclUtils.getYamlDataObject(aclFilePath,
PlainAccessData.class);
if (plainAclConfData == null) {
log.warn("No data in {}, skip it", aclFilePath);
return;
}
log.info("Broker plain acl conf data is : {}", plainAclConfData.toString());
List<String> globalWhiteRemoteAddressesList = plainAclConfData.getGlobalWhiteRemoteAddresses();
if (globalWhiteRemoteAddressesList != null && !globalWhiteRemoteAddressesList.isEmpty()) {
for (String address : globalWhiteRemoteAddressesList) {
globalWhiteRemoteAddressStrategy.add(remoteAddressStrategyFactory.getRemoteAddressStrategy(address));
}
}
this.globalWhiteRemoteAddressStrategy.addAll(globalWhiteRemoteAddressStrategy);
if (this.globalWhiteRemoteAddressStrategyMap.get(aclFilePath) != null) {
List<RemoteAddressStrategy> remoteAddressStrategyList = this.globalWhiteRemoteAddressStrategyMap.get(aclFilePath);
for (RemoteAddressStrategy remoteAddressStrategy : remoteAddressStrategyList) {
this.globalWhiteRemoteAddressStrategy.remove(remoteAddressStrategy);
}
this.globalWhiteRemoteAddressStrategyMap.put(aclFilePath, globalWhiteRemoteAddressStrategy);
}
List<PlainAccessConfig> accounts = plainAclConfData.getAccounts();
if (accounts != null && !accounts.isEmpty()) {
for (PlainAccessConfig plainAccessConfig : accounts) {
PlainAccessResource plainAccessResource = buildPlainAccessResource(plainAccessConfig);
//AccessKey can not be defined in multiple ACL files
String oldPath = this.accessKeyTable.get(plainAccessResource.getAccessKey());
if (oldPath == null || aclFilePath.equals(oldPath)) {
plainAccessResourceMap.put(plainAccessResource.getAccessKey(), plainAccessResource);
this.accessKeyTable.put(plainAccessResource.getAccessKey(), aclFilePath);
} else {
log.warn("The accessKey {} is repeated in multiple ACL files", plainAccessResource.getAccessKey());
}
}
}
// For loading dataversion part just
List<PlainAccessData.DataVersion> dataVersions = plainAclConfData.getDataVersion();
DataVersion dataVersion = new DataVersion();
if (dataVersions != null && !dataVersions.isEmpty()) {
DataVersion firstElement = new DataVersion();
firstElement.setCounter(new AtomicLong(dataVersions.get(0).getCounter()));
firstElement.setTimestamp(dataVersions.get(0).getTimestamp());
dataVersion.assignNewOne(firstElement);
}
this.aclPlainAccessResourceMap.put(aclFilePath, plainAccessResourceMap);
this.dataVersionMap.put(aclFilePath, dataVersion);
if (aclFilePath.equals(defaultAclFile)) {
this.dataVersion.assignNewOne(dataVersion);
}
}
@Deprecated
public String getAclConfigDataVersion() {
return this.dataVersion.toJson();
}
public Map<String, DataVersion> getDataVersionMap() {
return this.dataVersionMap;
}
public PlainAccessData updateAclConfigFileVersion(String aclFileName, PlainAccessData updateAclConfigMap) {
List<PlainAccessData.DataVersion> dataVersions = updateAclConfigMap.getDataVersion();
DataVersion dataVersion = new DataVersion();
if (dataVersions != null && !dataVersions.isEmpty()) {
dataVersion.setTimestamp(dataVersions.get(0).getTimestamp());
dataVersion.setCounter(new AtomicLong(dataVersions.get(0).getCounter()));
}
dataVersion.nextVersion();
List<PlainAccessData.DataVersion> versionElement = new ArrayList<>();
PlainAccessData.DataVersion dataVersionNew = new PlainAccessData.DataVersion();
dataVersionNew.setTimestamp(dataVersion.getTimestamp());
dataVersionNew.setCounter(dataVersion.getCounter().get());
versionElement.add(dataVersionNew);
updateAclConfigMap.setDataVersion(versionElement);
dataVersionMap.put(aclFileName, dataVersion);
return updateAclConfigMap;
}
public boolean updateAccessConfig(PlainAccessConfig plainAccessConfig) {
if (plainAccessConfig == null) {
log.error("Parameter value plainAccessConfig is null,Please check your parameter");
throw new AclException("Parameter value plainAccessConfig is null, Please check your parameter");
}
checkPlainAccessConfig(plainAccessConfig);
Permission.checkResourcePerms(plainAccessConfig.getTopicPerms());
Permission.checkResourcePerms(plainAccessConfig.getGroupPerms());
if (accessKeyTable.containsKey(plainAccessConfig.getAccessKey())) {
PlainAccessConfig updateAccountMap = null;
String aclFileName = accessKeyTable.get(plainAccessConfig.getAccessKey());
PlainAccessData aclAccessConfigMap = AclUtils.getYamlDataObject(aclFileName, PlainAccessData.class);
List<PlainAccessConfig> accounts = aclAccessConfigMap.getAccounts();
if (null != accounts) {
for (PlainAccessConfig account : accounts) {
if (account.getAccessKey().equals(plainAccessConfig.getAccessKey())) {
// Update acl access config elements
accounts.remove(account);
updateAccountMap = createAclAccessConfigMap(account, plainAccessConfig);
accounts.add(updateAccountMap);
aclAccessConfigMap.setAccounts(accounts);
break;
}
}
} else {
// Maybe deleted in file, add it back
accounts = new LinkedList<>();
updateAccountMap = createAclAccessConfigMap(null, plainAccessConfig);
accounts.add(updateAccountMap);
aclAccessConfigMap.setAccounts(accounts);
}
Map<String, PlainAccessResource> accountMap = aclPlainAccessResourceMap.get(aclFileName);
if (accountMap == null) {
accountMap = new HashMap<>(1);
accountMap.put(plainAccessConfig.getAccessKey(), buildPlainAccessResource(plainAccessConfig));
} else if (accountMap.isEmpty()) {
accountMap.put(plainAccessConfig.getAccessKey(), buildPlainAccessResource(plainAccessConfig));
} else {
for (Map.Entry<String, PlainAccessResource> entry : accountMap.entrySet()) {
if (entry.getValue().getAccessKey().equals(plainAccessConfig.getAccessKey())) {
PlainAccessResource plainAccessResource = buildPlainAccessResource(plainAccessConfig);
accountMap.put(entry.getKey(), plainAccessResource);
break;
}
}
}
aclPlainAccessResourceMap.put(aclFileName, accountMap);
return AclUtils.writeDataObject(aclFileName, updateAclConfigFileVersion(aclFileName, aclAccessConfigMap));
} else {
String fileName = MixAll.dealFilePath(defaultAclFile);
//Create acl access config elements on the default acl file
if (aclPlainAccessResourceMap.get(defaultAclFile) == null || aclPlainAccessResourceMap.get(defaultAclFile).size() == 0) {
try {
File defaultAclFile = new File(fileName);
if (!defaultAclFile.exists()) {
defaultAclFile.createNewFile();
}
} catch (IOException e) {
log.warn("create default acl file has exception when update accessConfig. ", e);
}
}
PlainAccessData aclAccessConfigMap = AclUtils.getYamlDataObject(defaultAclFile, PlainAccessData.class);
if (aclAccessConfigMap == null) {
aclAccessConfigMap = new PlainAccessData();
}
List<PlainAccessConfig> accounts = aclAccessConfigMap.getAccounts();
// When no accounts defined
if (null == accounts) {
accounts = new ArrayList<>();
}
accounts.add(createAclAccessConfigMap(null, plainAccessConfig));
aclAccessConfigMap.setAccounts(accounts);
accessKeyTable.put(plainAccessConfig.getAccessKey(), fileName);
if (aclPlainAccessResourceMap.get(fileName) == null) {
Map<String, PlainAccessResource> plainAccessResourceMap = new HashMap<>(1);
plainAccessResourceMap.put(plainAccessConfig.getAccessKey(), buildPlainAccessResource(plainAccessConfig));
aclPlainAccessResourceMap.put(fileName, plainAccessResourceMap);
} else {
Map<String, PlainAccessResource> plainAccessResourceMap = aclPlainAccessResourceMap.get(fileName);
plainAccessResourceMap.put(plainAccessConfig.getAccessKey(), buildPlainAccessResource(plainAccessConfig));
aclPlainAccessResourceMap.put(fileName, plainAccessResourceMap);
}
return AclUtils.writeDataObject(defaultAclFile, updateAclConfigFileVersion(defaultAclFile, aclAccessConfigMap));
}
}
public PlainAccessConfig createAclAccessConfigMap(PlainAccessConfig existedAccountMap,
PlainAccessConfig plainAccessConfig) {
PlainAccessConfig newAccountsMap = null;
if (existedAccountMap == null) {
newAccountsMap = new PlainAccessConfig();
} else {
newAccountsMap = existedAccountMap;
}
if (StringUtils.isEmpty(plainAccessConfig.getAccessKey()) ||
plainAccessConfig.getAccessKey().length() <= AclConstants.ACCESS_KEY_MIN_LENGTH) {
throw new AclException(String.format(
"The accessKey=%s cannot be null and length should longer than 6",
plainAccessConfig.getAccessKey()));
}
newAccountsMap.setAccessKey(plainAccessConfig.getAccessKey());
if (!StringUtils.isEmpty(plainAccessConfig.getSecretKey())) {
if (plainAccessConfig.getSecretKey().length() <= AclConstants.SECRET_KEY_MIN_LENGTH) {
throw new AclException(String.format(
"The secretKey=%s value length should longer than 6",
plainAccessConfig.getSecretKey()));
}
newAccountsMap.setSecretKey(plainAccessConfig.getSecretKey());
}
if (plainAccessConfig.getWhiteRemoteAddress() != null) {
newAccountsMap.setWhiteRemoteAddress(plainAccessConfig.getWhiteRemoteAddress());
}
if (!StringUtils.isEmpty(String.valueOf(plainAccessConfig.isAdmin()))) {
newAccountsMap.setAdmin(plainAccessConfig.isAdmin());
}
if (!StringUtils.isEmpty(plainAccessConfig.getDefaultTopicPerm())) {
newAccountsMap.setDefaultTopicPerm(plainAccessConfig.getDefaultTopicPerm());
}
if (!StringUtils.isEmpty(plainAccessConfig.getDefaultGroupPerm())) {
newAccountsMap.setDefaultGroupPerm(plainAccessConfig.getDefaultGroupPerm());
}
if (plainAccessConfig.getTopicPerms() != null) {
newAccountsMap.setTopicPerms(plainAccessConfig.getTopicPerms());
}
if (plainAccessConfig.getGroupPerms() != null) {
newAccountsMap.setGroupPerms(plainAccessConfig.getGroupPerms());
}
return newAccountsMap;
}
public boolean deleteAccessConfig(String accessKey) {
if (StringUtils.isEmpty(accessKey)) {
log.error("Parameter value accessKey is null or empty String,Please check your parameter");
return false;
}
if (accessKeyTable.containsKey(accessKey)) {
String aclFileName = accessKeyTable.get(accessKey);
PlainAccessData aclAccessConfigData = AclUtils.getYamlDataObject(aclFileName,
PlainAccessData.class);
if (aclAccessConfigData == null) {
log.warn("No data found in {} when deleting access config of {}", aclFileName, accessKey);
return true;
}
List<PlainAccessConfig> accounts = aclAccessConfigData.getAccounts();
Iterator<PlainAccessConfig> itemIterator = accounts.iterator();
while (itemIterator.hasNext()) {
if (itemIterator.next().getAccessKey().equals(accessKey)) {
// Delete the related acl config element
itemIterator.remove();
accessKeyTable.remove(accessKey);
aclAccessConfigData.setAccounts(accounts);
return AclUtils.writeDataObject(aclFileName, updateAclConfigFileVersion(aclFileName, aclAccessConfigData));
}
}
}
return false;
}
public boolean updateGlobalWhiteAddrsConfig(List<String> globalWhiteAddrsList) {
return this.updateGlobalWhiteAddrsConfig(globalWhiteAddrsList, this.defaultAclFile);
}
public boolean updateGlobalWhiteAddrsConfig(List<String> globalWhiteAddrsList, String fileName) {
if (fileName == null || fileName.isEmpty()) {
fileName = this.defaultAclFile;
}
if (globalWhiteAddrsList == null) {
log.error("Parameter value globalWhiteAddrsList is null,Please check your parameter");
return false;
}
File file = new File(fileName);
if (!file.exists() || file.isDirectory()) {
log.error("Parameter value " + fileName + " is not exist or is a directory, please check your parameter");
return false;
}
if (!file.getAbsolutePath().startsWith(fileHome)) {
log.error("Parameter value " + fileName + " is not in the directory rocketmq.home.dir " + fileHome);
return false;
}
if (!fileName.endsWith(".yml") && fileName.endsWith(".yaml")) {
log.error("Parameter value " + fileName + " is not a ACL configuration file");
return false;
}
PlainAccessData aclAccessConfigMap = AclUtils.getYamlDataObject(fileName, PlainAccessData.class);
if (aclAccessConfigMap == null) {
aclAccessConfigMap = new PlainAccessData();
log.info("No data in {}, create a new aclAccessConfigMap", fileName);
}
// Update globalWhiteRemoteAddr element in memory map firstly
aclAccessConfigMap.setGlobalWhiteRemoteAddresses(new ArrayList<>(globalWhiteAddrsList));
return AclUtils.writeDataObject(fileName, updateAclConfigFileVersion(fileName, aclAccessConfigMap));
}
public AclConfig getAllAclConfig() {
AclConfig aclConfig = new AclConfig();
List<PlainAccessConfig> configs = new ArrayList<>();
List<String> whiteAddrs = new ArrayList<>();
Set<String> accessKeySets = new HashSet<>();
for (String path : fileList) {
PlainAccessData plainAclConfData = AclUtils.getYamlDataObject(path, PlainAccessData.class);
if (plainAclConfData == null) {
continue;
}
List<String> globalWhiteAddrs = plainAclConfData.getGlobalWhiteRemoteAddresses();
if (globalWhiteAddrs != null && !globalWhiteAddrs.isEmpty()) {
whiteAddrs.addAll(globalWhiteAddrs);
}
List<PlainAccessConfig> plainAccessConfigs = plainAclConfData.getAccounts();
if (plainAccessConfigs != null && !plainAccessConfigs.isEmpty()) {
for (PlainAccessConfig accessConfig : plainAccessConfigs) {
if (!accessKeySets.contains(accessConfig.getAccessKey())) {
accessKeySets.add(accessConfig.getAccessKey());
PlainAccessConfig plainAccessConfig = new PlainAccessConfig();
plainAccessConfig.setGroupPerms(accessConfig.getGroupPerms());
plainAccessConfig.setDefaultTopicPerm(accessConfig.getDefaultTopicPerm());
plainAccessConfig.setDefaultGroupPerm(accessConfig.getDefaultGroupPerm());
plainAccessConfig.setAccessKey(accessConfig.getAccessKey());
plainAccessConfig.setSecretKey(accessConfig.getSecretKey());
plainAccessConfig.setAdmin(accessConfig.isAdmin());
plainAccessConfig.setTopicPerms(accessConfig.getTopicPerms());
plainAccessConfig.setWhiteRemoteAddress(accessConfig.getWhiteRemoteAddress());
configs.add(plainAccessConfig);
}
}
}
}
aclConfig.setPlainAccessConfigs(configs);
aclConfig.setGlobalWhiteAddrs(whiteAddrs);
return aclConfig;
}
private void watch() {
try {
AclFileWatchService aclFileWatchService = new AclFileWatchService(defaultAclDir, defaultAclFile, new AclFileWatchService.Listener() {
@Override
public void onFileChanged(String aclFileName) {
load(aclFileName);
}
@Override
public void onFileNumChanged(String path) {
load();
}
});
aclFileWatchService.start();
log.info("Succeed to start AclFileWatchService");
this.isWatchStart = true;
} catch (Exception e) {
log.error("Failed to start AclWatcherService", e);
}
}
void checkPerm(PlainAccessResource needCheckedAccess, PlainAccessResource ownedAccess) {
permissionChecker.check(needCheckedAccess, ownedAccess);
}
void clearPermissionInfo() {
this.aclPlainAccessResourceMap.clear();
this.accessKeyTable.clear();
this.globalWhiteRemoteAddressStrategy.clear();
}
public void checkPlainAccessConfig(PlainAccessConfig plainAccessConfig) throws AclException {
if (plainAccessConfig.getAccessKey() == null
|| plainAccessConfig.getSecretKey() == null
|| plainAccessConfig.getAccessKey().length() <= AclConstants.ACCESS_KEY_MIN_LENGTH
|| plainAccessConfig.getSecretKey().length() <= AclConstants.SECRET_KEY_MIN_LENGTH) {
throw new AclException(String.format(
"The accessKey=%s and secretKey=%s cannot be null and length should longer than 6",
plainAccessConfig.getAccessKey(), plainAccessConfig.getSecretKey()));
}
}
public PlainAccessResource buildPlainAccessResource(PlainAccessConfig plainAccessConfig) throws AclException {
checkPlainAccessConfig(plainAccessConfig);
return PlainAccessResource.build(plainAccessConfig, remoteAddressStrategyFactory.
getRemoteAddressStrategy(plainAccessConfig.getWhiteRemoteAddress()));
}
public void validate(PlainAccessResource plainAccessResource) {
// Check the global white remote addr
for (RemoteAddressStrategy remoteAddressStrategy : globalWhiteRemoteAddressStrategy) {
if (remoteAddressStrategy.match(plainAccessResource)) {
return;
}
}
if (plainAccessResource.getAccessKey() == null) {
throw new AclException("No accessKey is configured");
}
if (!accessKeyTable.containsKey(plainAccessResource.getAccessKey())) {
throw new AclException(String.format("No acl config for %s", plainAccessResource.getAccessKey()));
}
// Check the white addr for accessKey
String aclFileName = accessKeyTable.get(plainAccessResource.getAccessKey());
PlainAccessResource ownedAccess = aclPlainAccessResourceMap.getOrDefault(aclFileName, new HashMap<>()).get(plainAccessResource.getAccessKey());
if (ownedAccess == null) {
throw new AclException(String.format("No PlainAccessResource for accessKey=%s", plainAccessResource.getAccessKey()));
}
if (ownedAccess.getRemoteAddressStrategy().match(plainAccessResource)) {
return;
}
// Check the signature
String signature = AclUtils.calSignature(plainAccessResource.getContent(), ownedAccess.getSecretKey());
if (plainAccessResource.getSignature() == null
|| !MessageDigest.isEqual(signature.getBytes(AclSigner.DEFAULT_CHARSET), plainAccessResource.getSignature().getBytes(AclSigner.DEFAULT_CHARSET))) {
throw new AclException(String.format("Check signature failed for accessKey=%s", plainAccessResource.getAccessKey()));
}
//Skip the topic RMQ_SYS_TRACE_TOPIC permission check,if the topic RMQ_SYS_TRACE_TOPIC is used for message trace
Map<String, Byte> resourcePermMap = plainAccessResource.getResourcePermMap();
if (resourcePermMap != null) {
Byte permission = resourcePermMap.get(TopicValidator.RMQ_SYS_TRACE_TOPIC);
if (permission != null && permission == Permission.PUB) {
return;
}
}
// Check perm of each resource
checkPerm(plainAccessResource, ownedAccess);
}
public boolean isWatchStart() {
return isWatchStart;
}
}
@@ -1,255 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.validator.routines.InetAddressValidator;
import org.apache.rocketmq.acl.common.AclException;
import org.apache.rocketmq.acl.common.AclUtils;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
public class RemoteAddressStrategyFactory {
private static final Logger log = LoggerFactory.getLogger(LoggerName.COMMON_LOGGER_NAME);
public static final NullRemoteAddressStrategy NULL_NET_ADDRESS_STRATEGY = new NullRemoteAddressStrategy();
public static final BlankRemoteAddressStrategy BLANK_NET_ADDRESS_STRATEGY = new BlankRemoteAddressStrategy();
public RemoteAddressStrategy getRemoteAddressStrategy(PlainAccessResource plainAccessResource) {
return getRemoteAddressStrategy(plainAccessResource.getWhiteRemoteAddress());
}
public RemoteAddressStrategy getRemoteAddressStrategy(String remoteAddr) {
if (StringUtils.isBlank(remoteAddr)) {
return BLANK_NET_ADDRESS_STRATEGY;
}
if ("*".equals(remoteAddr) || "*.*.*.*".equals(remoteAddr) || "*:*:*:*:*:*:*:*".equals(remoteAddr)) {
return NULL_NET_ADDRESS_STRATEGY;
}
if (remoteAddr.endsWith("}")) {
if (AclUtils.isColon(remoteAddr)) {
String[] strArray = StringUtils.split(remoteAddr, ":");
String last = strArray[strArray.length - 1];
if (!last.startsWith("{")) {
throw new AclException(String.format("MultipleRemoteAddressStrategy netAddress examine scope Exception netAddress: %s", remoteAddr));
}
return new MultipleRemoteAddressStrategy(AclUtils.getAddresses(remoteAddr, last));
} else {
String[] strArray = StringUtils.split(remoteAddr, ".");
// However a right IP String provided by user,it always can be divided into 4 parts by '.'.
if (strArray.length < 4) {
throw new AclException(String.format("MultipleRemoteAddressStrategy has got a/some wrong format IP(s): %s ", remoteAddr));
}
String lastStr = strArray[strArray.length - 1];
if (!lastStr.startsWith("{")) {
throw new AclException(String.format("MultipleRemoteAddressStrategy netAddress examine scope Exception netAddress: %s", remoteAddr));
}
return new MultipleRemoteAddressStrategy(AclUtils.getAddresses(remoteAddr, lastStr));
}
} else if (AclUtils.isComma(remoteAddr)) {
return new MultipleRemoteAddressStrategy(StringUtils.split(remoteAddr, ","));
} else if (AclUtils.isAsterisk(remoteAddr) || AclUtils.isMinus(remoteAddr)) {
return new RangeRemoteAddressStrategy(remoteAddr);
}
return new OneRemoteAddressStrategy(remoteAddr);
}
public static class NullRemoteAddressStrategy implements RemoteAddressStrategy {
@Override
public boolean match(PlainAccessResource plainAccessResource) {
return true;
}
}
public static class BlankRemoteAddressStrategy implements RemoteAddressStrategy {
@Override
public boolean match(PlainAccessResource plainAccessResource) {
return false;
}
}
public static class MultipleRemoteAddressStrategy implements RemoteAddressStrategy {
private final Set<String> multipleSet = new HashSet<>();
public MultipleRemoteAddressStrategy(String[] strArray) {
InetAddressValidator validator = InetAddressValidator.getInstance();
for (String netAddress : strArray) {
if (validator.isValidInet4Address(netAddress)) {
multipleSet.add(netAddress);
} else if (validator.isValidInet6Address(netAddress)) {
multipleSet.add(AclUtils.expandIP(netAddress, 8));
} else {
throw new AclException(String.format("NetAddress examine Exception netAddress is %s", netAddress));
}
}
}
@Override
public boolean match(PlainAccessResource plainAccessResource) {
InetAddressValidator validator = InetAddressValidator.getInstance();
String whiteRemoteAddress = plainAccessResource.getWhiteRemoteAddress();
if (validator.isValidInet6Address(whiteRemoteAddress)) {
whiteRemoteAddress = AclUtils.expandIP(whiteRemoteAddress, 8);
}
return multipleSet.contains(whiteRemoteAddress);
}
}
public static class OneRemoteAddressStrategy implements RemoteAddressStrategy {
private String netAddress;
public OneRemoteAddressStrategy(String netAddress) {
this.netAddress = netAddress;
InetAddressValidator validator = InetAddressValidator.getInstance();
if (!(validator.isValidInet4Address(netAddress) || validator.isValidInet6Address(
netAddress))) {
throw new AclException(String.format("NetAddress examine Exception netAddress is %s",
netAddress));
}
}
@Override
public boolean match(PlainAccessResource plainAccessResource) {
String writeRemoteAddress = AclUtils.expandIP(plainAccessResource.getWhiteRemoteAddress(), 8).toUpperCase();
return AclUtils.expandIP(netAddress, 8).toUpperCase().equals(writeRemoteAddress);
}
}
public static class RangeRemoteAddressStrategy implements RemoteAddressStrategy {
private String head;
private int start;
private int end;
private int index;
public RangeRemoteAddressStrategy(String remoteAddr) {
// IPv6 Address
if (AclUtils.isColon(remoteAddr)) {
AclUtils.IPv6AddressCheck(remoteAddr);
String[] strArray = StringUtils.split(remoteAddr, ":");
for (int i = 1; i < strArray.length; i++) {
if (ipv6Analysis(strArray, i)) {
AclUtils.verify(remoteAddr, index - 1);
String preAddress = AclUtils.v6ipProcess(remoteAddr);
this.index = StringUtils.split(preAddress, ":").length;
this.head = preAddress;
break;
}
}
} else {
String[] strArray = StringUtils.split(remoteAddr, ".");
if (analysis(strArray, 1) || analysis(strArray, 2) || analysis(strArray, 3)) {
AclUtils.verify(remoteAddr, index - 1);
StringBuilder sb = new StringBuilder();
for (int j = 0; j < index; j++) {
sb.append(strArray[j].trim()).append(".");
}
this.head = sb.toString();
}
}
}
private boolean analysis(String[] strArray, int index) {
String value = strArray[index].trim();
this.index = index;
if ("*".equals(value)) {
setValue(0, 255);
} else if (AclUtils.isMinus(value)) {
if (value.indexOf("-") == 0) {
throw new AclException(String.format("RangeRemoteAddressStrategy netAddress examine scope Exception value %s ", value));
}
String[] valueArray = StringUtils.split(value, "-");
this.start = Integer.parseInt(valueArray[0]);
this.end = Integer.parseInt(valueArray[1]);
if (!(AclUtils.isScope(end) && AclUtils.isScope(start) && start <= end)) {
throw new AclException(String.format("RangeRemoteAddressStrategy netAddress examine scope Exception start is %s , end is %s", start, end));
}
}
return this.end > 0;
}
private boolean ipv6Analysis(String[] strArray, int index) {
String value = strArray[index].trim();
this.index = index;
if ("*".equals(value)) {
int min = Integer.parseInt("0", 16);
int max = Integer.parseInt("ffff", 16);
setValue(min, max);
} else if (AclUtils.isMinus(value)) {
if (value.indexOf("-") == 0) {
throw new AclException(String.format("RangeRemoteAddressStrategy netAddress examine scope Exception value %s ", value));
}
String[] valueArray = StringUtils.split(value, "-");
this.start = Integer.parseInt(valueArray[0], 16);
this.end = Integer.parseInt(valueArray[1], 16);
if (!(AclUtils.isIPv6Scope(end) && AclUtils.isIPv6Scope(start) && start <= end)) {
throw new AclException(String.format("RangeRemoteAddressStrategy netAddress examine scope Exception start is %s , end is %s", start, end));
}
}
return this.end > 0;
}
private void setValue(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public boolean match(PlainAccessResource plainAccessResource) {
String netAddress = plainAccessResource.getWhiteRemoteAddress();
InetAddressValidator validator = InetAddressValidator.getInstance();
if (validator.isValidInet4Address(netAddress)) {
if (netAddress.startsWith(this.head)) {
String value;
if (index == 3) {
value = netAddress.substring(this.head.length());
} else if (index == 2) {
value = netAddress.substring(this.head.length(), netAddress.lastIndexOf('.'));
} else {
value = netAddress.substring(this.head.length(), netAddress.lastIndexOf('.', netAddress.lastIndexOf('.') - 1));
}
Integer address = Integer.valueOf(value);
return address >= this.start && address <= this.end;
}
} else if (validator.isValidInet6Address(netAddress)) {
netAddress = AclUtils.expandIP(netAddress, 8).toUpperCase();
if (netAddress.startsWith(this.head)) {
String value = netAddress.substring(5 * index, 5 * index + 4);
Integer address = Integer.parseInt(value, 16);
return address >= this.start && address <= this.end;
}
}
return false;
}
}
}
@@ -1,189 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.apache.rocketmq.acl.common.AclClientRPCHook;
import org.apache.rocketmq.acl.common.AclException;
import org.apache.rocketmq.acl.common.SessionCredentials;
import org.apache.rocketmq.acl.plain.AclTestHelper;
import org.apache.rocketmq.acl.plain.PlainAccessResource;
import org.apache.rocketmq.acl.plain.PlainAccessValidator;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.remoting.protocol.RequestCode;
import org.apache.rocketmq.remoting.protocol.header.PullMessageRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.SendMessageRequestHeader;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class RemotingClientAccessTest {
private PlainAccessValidator plainAccessValidator;
private AclClientRPCHook aclClient;
private SessionCredentials sessionCredentials;
private File confHome;
private String clientAddress = "10.7.1.3";
@Before
public void init() throws IOException {
String folder = "access_acl_conf";
confHome = AclTestHelper.copyResources(folder, true);
System.setProperty("rocketmq.home.dir", confHome.getAbsolutePath());
System.setProperty("rocketmq.acl.plain.file", "/access_acl_conf/acl/plain_acl.yml".replace("/", File.separator));
plainAccessValidator = new PlainAccessValidator();
sessionCredentials = new SessionCredentials();
sessionCredentials.setAccessKey("rocketmq3");
sessionCredentials.setSecretKey("12345678");
aclClient = new AclClientRPCHook(sessionCredentials);
}
@After
public void cleanUp() {
AclTestHelper.recursiveDelete(confHome);
}
@Test(expected = AclException.class)
public void testProduceDenyTopic() {
SendMessageRequestHeader messageRequestHeader = new SendMessageRequestHeader();
messageRequestHeader.setTopic("topicD");
RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, messageRequestHeader);
aclClient.doBeforeRequest(clientAddress, remotingCommand);
ByteBuffer buf = remotingCommand.encodeHeader();
buf.getInt();
buf = ByteBuffer.allocate(buf.limit() - buf.position()).put(buf);
buf.position(0);
try {
PlainAccessResource accessResource = (PlainAccessResource) plainAccessValidator.parse(RemotingCommand.decode(buf), clientAddress);
plainAccessValidator.validate(accessResource);
} catch (RemotingCommandException e) {
e.printStackTrace();
Assert.fail("Should not throw IOException");
}
}
@Test
public void testProduceAuthorizedTopic() {
SendMessageRequestHeader messageRequestHeader = new SendMessageRequestHeader();
messageRequestHeader.setTopic("topicA");
RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, messageRequestHeader);
aclClient.doBeforeRequest(clientAddress, remotingCommand);
ByteBuffer buf = remotingCommand.encodeHeader();
buf.getInt();
buf = ByteBuffer.allocate(buf.limit() - buf.position()).put(buf);
buf.position(0);
try {
PlainAccessResource accessResource = (PlainAccessResource) plainAccessValidator.parse(RemotingCommand.decode(buf), clientAddress);
plainAccessValidator.validate(accessResource);
} catch (RemotingCommandException e) {
e.printStackTrace();
Assert.fail("Should not throw IOException");
}
}
@Test(expected = AclException.class)
public void testConsumeDenyTopic() {
PullMessageRequestHeader pullMessageRequestHeader = new PullMessageRequestHeader();
pullMessageRequestHeader.setTopic("topicD");
pullMessageRequestHeader.setConsumerGroup("groupB");
RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, pullMessageRequestHeader);
aclClient.doBeforeRequest("", remotingCommand);
ByteBuffer buf = remotingCommand.encodeHeader();
buf.getInt();
buf = ByteBuffer.allocate(buf.limit() - buf.position()).put(buf);
buf.position(0);
try {
PlainAccessResource accessResource = (PlainAccessResource) plainAccessValidator.parse(RemotingCommand.decode(buf), "123.4.5.6");
plainAccessValidator.validate(accessResource);
} catch (RemotingCommandException e) {
e.printStackTrace();
Assert.fail("Should not throw IOException");
}
}
@Test
public void testConsumeAuthorizedTopic() {
PullMessageRequestHeader pullMessageRequestHeader = new PullMessageRequestHeader();
pullMessageRequestHeader.setTopic("topicB");
pullMessageRequestHeader.setConsumerGroup("groupB");
RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, pullMessageRequestHeader);
aclClient.doBeforeRequest("", remotingCommand);
ByteBuffer buf = remotingCommand.encodeHeader();
buf.getInt();
buf = ByteBuffer.allocate(buf.limit() - buf.position()).put(buf);
buf.position(0);
try {
PlainAccessResource accessResource = (PlainAccessResource) plainAccessValidator.parse(RemotingCommand.decode(buf), "123.4.5.6");
plainAccessValidator.validate(accessResource);
} catch (RemotingCommandException e) {
e.printStackTrace();
Assert.fail("Should not throw IOException");
}
}
@Test(expected = AclException.class)
public void testConsumeInDeniedGroup() {
PullMessageRequestHeader pullMessageRequestHeader = new PullMessageRequestHeader();
pullMessageRequestHeader.setTopic("topicB");
pullMessageRequestHeader.setConsumerGroup("groupD");
RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, pullMessageRequestHeader);
aclClient.doBeforeRequest("", remotingCommand);
ByteBuffer buf = remotingCommand.encodeHeader();
buf.getInt();
buf = ByteBuffer.allocate(buf.limit() - buf.position()).put(buf);
buf.position(0);
try {
PlainAccessResource accessResource = (PlainAccessResource) plainAccessValidator.parse(RemotingCommand.decode(buf), "123.4.5.6");
plainAccessValidator.validate(accessResource);
} catch (RemotingCommandException e) {
e.printStackTrace();
Assert.fail("Should not throw IOException");
}
}
@Test
public void testConsumeInAuthorizedGroup() {
PullMessageRequestHeader pullMessageRequestHeader = new PullMessageRequestHeader();
pullMessageRequestHeader.setTopic("topicB");
pullMessageRequestHeader.setConsumerGroup("groupB");
RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE, pullMessageRequestHeader);
aclClient.doBeforeRequest("", remotingCommand);
ByteBuffer buf = remotingCommand.encodeHeader();
buf.getInt();
buf = ByteBuffer.allocate(buf.limit() - buf.position()).put(buf);
buf.position(0);
try {
PlainAccessResource accessResource = (PlainAccessResource) plainAccessValidator.parse(RemotingCommand.decode(buf), "123.4.5.6");
plainAccessValidator.validate(accessResource);
} catch (RemotingCommandException e) {
e.printStackTrace();
Assert.fail("Should not throw IOException");
}
}
}
@@ -1,64 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.common;
import org.junit.Before;
import org.junit.Test;
import org.junit.Assert;
public class AuthorizationHeaderTest {
private static final String AUTH_HEADER = "Signature Credential=1234567890/test, SignedHeaders=host, Signature=1234567890";
private AuthorizationHeader authorizationHeader;
@Before
public void setUp() throws Exception {
authorizationHeader = new AuthorizationHeader(AUTH_HEADER);
}
@Test
public void testGetMethod() {
Assert.assertEquals("Signature", authorizationHeader.getMethod());
}
@Test
public void testGetAccessKey() {
Assert.assertEquals("1234567890", authorizationHeader.getAccessKey());
}
@Test
public void testGetSignedHeaders() {
String[] expectedHeaders = {"host"};
Assert.assertArrayEquals(expectedHeaders, authorizationHeader.getSignedHeaders());
}
@Test
public void testGetSignature() {
Assert.assertEquals("EjRWeJA=", authorizationHeader.getSignature());
}
@Test(expected = Exception.class)
public void testInvalidAuthorizationHeader() throws Exception {
new AuthorizationHeader("Invalid Header");
}
@Test(expected = Exception.class)
public void testMalformedAuthorizationHeader() throws Exception {
new AuthorizationHeader("Malformed, Header");
}
}
@@ -1,197 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.common;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.rocketmq.acl.plain.PlainAccessResource;
import org.apache.rocketmq.remoting.protocol.RequestCode;
import org.junit.Assert;
import org.junit.Test;
public class PermissionTest {
@Test
public void fromStringGetPermissionTest() {
byte perm = Permission.parsePermFromString("PUB");
Assert.assertEquals(perm, Permission.PUB);
perm = Permission.parsePermFromString("SUB");
Assert.assertEquals(perm, Permission.SUB);
perm = Permission.parsePermFromString("PUB|SUB");
Assert.assertEquals(perm, Permission.PUB | Permission.SUB);
perm = Permission.parsePermFromString("SUB|PUB");
Assert.assertEquals(perm, Permission.PUB | Permission.SUB);
perm = Permission.parsePermFromString("DENY");
Assert.assertEquals(perm, Permission.DENY);
perm = Permission.parsePermFromString("1");
Assert.assertEquals(perm, Permission.DENY);
perm = Permission.parsePermFromString(null);
Assert.assertEquals(perm, Permission.DENY);
}
@Test
public void checkPermissionTest() {
boolean boo = Permission.checkPermission(Permission.DENY, Permission.DENY);
Assert.assertFalse(boo);
boo = Permission.checkPermission(Permission.PUB, Permission.PUB);
Assert.assertTrue(boo);
boo = Permission.checkPermission(Permission.SUB, Permission.SUB);
Assert.assertTrue(boo);
boo = Permission.checkPermission(Permission.PUB, (byte) (Permission.PUB | Permission.SUB));
Assert.assertTrue(boo);
boo = Permission.checkPermission(Permission.SUB, (byte) (Permission.PUB | Permission.SUB));
Assert.assertTrue(boo);
boo = Permission.checkPermission(Permission.ANY, (byte) (Permission.PUB | Permission.SUB));
Assert.assertTrue(boo);
boo = Permission.checkPermission(Permission.ANY, Permission.SUB);
Assert.assertTrue(boo);
boo = Permission.checkPermission(Permission.ANY, Permission.PUB);
Assert.assertTrue(boo);
boo = Permission.checkPermission(Permission.DENY, Permission.ANY);
Assert.assertFalse(boo);
boo = Permission.checkPermission(Permission.DENY, Permission.PUB);
Assert.assertFalse(boo);
boo = Permission.checkPermission(Permission.DENY, Permission.SUB);
Assert.assertFalse(boo);
}
@Test(expected = AclException.class)
public void setTopicPermTest() {
PlainAccessResource plainAccessResource = new PlainAccessResource();
Map<String, Byte> resourcePermMap = plainAccessResource.getResourcePermMap();
Permission.parseResourcePerms(plainAccessResource, false, null);
Assert.assertNull(resourcePermMap);
List<String> groups = new ArrayList<>();
Permission.parseResourcePerms(plainAccessResource, false, groups);
Assert.assertNull(resourcePermMap);
groups.add("groupA=DENY");
groups.add("groupB=PUB|SUB");
groups.add("groupC=PUB");
Permission.parseResourcePerms(plainAccessResource, false, groups);
resourcePermMap = plainAccessResource.getResourcePermMap();
byte perm = resourcePermMap.get(PlainAccessResource.getRetryTopic("groupA"));
Assert.assertEquals(perm, Permission.DENY);
perm = resourcePermMap.get(PlainAccessResource.getRetryTopic("groupB"));
Assert.assertEquals(perm,Permission.PUB | Permission.SUB);
perm = resourcePermMap.get(PlainAccessResource.getRetryTopic("groupC"));
Assert.assertEquals(perm, Permission.PUB);
List<String> topics = new ArrayList<>();
topics.add("topicA=DENY");
topics.add("topicB=PUB|SUB");
topics.add("topicC=PUB");
Permission.parseResourcePerms(plainAccessResource, true, topics);
perm = resourcePermMap.get("topicA");
Assert.assertEquals(perm, Permission.DENY);
perm = resourcePermMap.get("topicB");
Assert.assertEquals(perm, Permission.PUB | Permission.SUB);
perm = resourcePermMap.get("topicC");
Assert.assertEquals(perm, Permission.PUB);
List<String> erron = new ArrayList<>();
erron.add("");
Permission.parseResourcePerms(plainAccessResource, false, erron);
}
@Test
public void checkAdminCodeTest() {
Set<Integer> code = new HashSet<>();
code.add(RequestCode.UPDATE_AND_CREATE_TOPIC);
code.add(RequestCode.UPDATE_BROKER_CONFIG);
code.add(RequestCode.DELETE_TOPIC_IN_BROKER);
code.add(RequestCode.UPDATE_AND_CREATE_SUBSCRIPTIONGROUP);
code.add(RequestCode.DELETE_SUBSCRIPTIONGROUP);
code.add(RequestCode.UPDATE_AND_CREATE_STATIC_TOPIC);
code.add(RequestCode.UPDATE_AND_CREATE_ACL_CONFIG);
code.add(RequestCode.DELETE_ACL_CONFIG);
code.add(RequestCode.GET_BROKER_CLUSTER_ACL_INFO);
for (int i = 0; i < 400; i++) {
boolean boo = Permission.needAdminPerm(i);
if (boo) {
Assert.assertTrue(code.contains(i));
}
}
}
@Test
public void AclExceptionTest() {
AclException aclException = new AclException("CAL_SIGNATURE_FAILED",10015);
AclException aclExceptionWithMessage = new AclException("CAL_SIGNATURE_FAILED",10015,"CAL_SIGNATURE_FAILED Exception");
Assert.assertEquals(aclException.getCode(),10015);
Assert.assertEquals(aclExceptionWithMessage.getStatus(),"CAL_SIGNATURE_FAILED");
aclException.setCode(10016);
Assert.assertEquals(aclException.getCode(),10016);
aclException.setStatus("netAddress examine scope Exception netAddress");
Assert.assertEquals(aclException.getStatus(),"netAddress examine scope Exception netAddress");
}
@Test
public void checkResourcePermsNormalTest() {
Permission.checkResourcePerms(null);
Permission.checkResourcePerms(new ArrayList<>());
Permission.checkResourcePerms(Arrays.asList("topicA=PUB"));
Permission.checkResourcePerms(Arrays.asList("topicA=PUB", "topicB=SUB", "topicC=PUB|SUB"));
}
@Test(expected = AclException.class)
public void checkResourcePermsExceptionTest1() {
Permission.checkResourcePerms(Arrays.asList("topicA"));
}
@Test(expected = AclException.class)
public void checkResourcePermsExceptionTest2() {
Permission.checkResourcePerms(Arrays.asList("topicA="));
}
@Test(expected = AclException.class)
public void checkResourcePermsExceptionTest3() {
Permission.checkResourcePerms(Arrays.asList("topicA=DENY1"));
}
}
@@ -1,120 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.UUID;
import java.util.Iterator;
import org.junit.Assert;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
public final class AclTestHelper {
private AclTestHelper() {
}
private static void copyTo(String path, InputStream src, File dstDir, String flag, boolean into)
throws IOException {
Preconditions.checkNotNull(flag);
Iterator<String> iterator = Splitter.on(File.separatorChar).split(path).iterator();
boolean found = false;
File dir = dstDir;
while (iterator.hasNext()) {
String current = iterator.next();
if (!found && flag.equals(current)) {
found = true;
if (into) {
dir = new File(dir, flag);
if (!dir.exists()) {
Assert.assertTrue(dir.mkdirs());
}
}
continue;
}
if (found) {
if (!iterator.hasNext()) {
dir = new File(dir, current);
} else {
dir = new File(dir, current);
if (!dir.exists()) {
Assert.assertTrue(dir.mkdir());
}
}
}
}
Assert.assertTrue(dir.createNewFile());
byte[] buffer = new byte[4096];
BufferedInputStream bis = new BufferedInputStream(src);
int len = 0;
try (BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(dir.toPath()))) {
while ((len = bis.read(buffer)) > 0) {
bos.write(buffer, 0, len);
}
}
}
public static void recursiveDelete(File file) {
if (file.isFile()) {
file.delete();
} else {
File[] files = file.listFiles();
if (null != files) {
for (File f : files) {
recursiveDelete(f);
}
}
file.delete();
}
}
public static File copyResources(String folder) throws IOException {
return copyResources(folder, false);
}
public static File copyResources(String folder, boolean into) throws IOException {
File home = new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString().replace('-', '_'));
if (!home.exists()) {
Assert.assertTrue(home.mkdirs());
}
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(AclTestHelper.class.getClassLoader());
Resource[] resources = resolver.getResources(String.format("classpath:%s/**/*", folder));
for (Resource resource : resources) {
if (!resource.isReadable()) {
continue;
}
String description = resource.getDescription();
int start = description.indexOf('[');
int end = description.lastIndexOf(']');
String path = description.substring(start + 1, end);
try (InputStream inputStream = resource.getInputStream()) {
copyTo(path, inputStream, home, folder, into);
}
}
return home;
}
}
@@ -1,311 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import org.apache.rocketmq.acl.common.AclClientRPCHook;
import org.apache.rocketmq.acl.common.AclConstants;
import org.apache.rocketmq.acl.common.AclException;
import org.apache.rocketmq.acl.common.AclUtils;
import org.apache.rocketmq.acl.common.SessionCredentials;
import org.apache.rocketmq.common.AclConfig;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.remoting.protocol.RequestCode;
import org.apache.rocketmq.remoting.protocol.header.PullMessageRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.SendMessageRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.SendMessageRequestHeaderV2;
import org.junit.Assert;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* <p> In this class, we'll test the following scenarios, each containing several consecutive operations on ACL,
* <p> like updating and deleting ACL, changing config files and checking validations.
* <p> Case 1: Only conf/plain_acl.yml exists;
* <p> Case 2: Only conf/acl/plain_acl.yml exists;
* <p> Case 3: Both conf/plain_acl.yml and conf/acl/plain_acl.yml exists.
*/
public class PlainAccessControlFlowTest {
public static final String DEFAULT_TOPIC = "topic-acl";
public static final String DEFAULT_GROUP = "GID_acl";
public static final String DEFAULT_PRODUCER_AK = "ak11111";
public static final String DEFAULT_PRODUCER_SK = "1234567";
public static final String DEFAULT_CONSUMER_SK = "7654321";
public static final String DEFAULT_CONSUMER_AK = "ak22222";
public static final String DEFAULT_GLOBAL_WHITE_ADDR = "172.16.123.123";
public static final List<String> DEFAULT_GLOBAL_WHITE_ADDRS_LIST = Collections.singletonList(DEFAULT_GLOBAL_WHITE_ADDR);
@Test
public void testEmptyAclFolderCase() throws NoSuchFieldException, IllegalAccessException,
IOException {
String folder = "empty_acl_folder_conf";
File home = AclTestHelper.copyResources(folder);
System.setProperty("rocketmq.home.dir", home.getAbsolutePath());
PlainAccessValidator plainAccessValidator = new PlainAccessValidator();
checkDefaultAclFileExists();
testValidationAfterConsecutiveUpdates(plainAccessValidator);
testValidationAfterConfigFileChanged(plainAccessValidator);
AclTestHelper.recursiveDelete(home);
}
@Test
public void testOnlyAclFolderCase() throws NoSuchFieldException, IllegalAccessException, IOException {
String folder = "only_acl_folder_conf";
File home = AclTestHelper.copyResources(folder);
System.setProperty("rocketmq.home.dir", home.getAbsolutePath());
PlainAccessValidator plainAccessValidator = new PlainAccessValidator();
checkDefaultAclFileExists();
testValidationAfterConsecutiveUpdates(plainAccessValidator);
testValidationAfterConfigFileChanged(plainAccessValidator);
AclTestHelper.recursiveDelete(home);
}
@Test
public void testBothAclFileAndFolderCase() throws NoSuchFieldException, IllegalAccessException,
IOException {
String folder = "both_acl_file_folder_conf";
File root = AclTestHelper.copyResources(folder);
System.setProperty("rocketmq.home.dir", root.getAbsolutePath());
PlainAccessValidator plainAccessValidator = new PlainAccessValidator();
checkDefaultAclFileExists();
testValidationAfterConsecutiveUpdates(plainAccessValidator);
testValidationAfterConfigFileChanged(plainAccessValidator);
AclTestHelper.recursiveDelete(root);
}
private void testValidationAfterConfigFileChanged(
PlainAccessValidator plainAccessValidator) throws NoSuchFieldException, IllegalAccessException {
PlainAccessConfig producerAccessConfig = generateProducerAccessConfig();
PlainAccessConfig consumerAccessConfig = generateConsumerAccessConfig();
List<PlainAccessConfig> plainAccessConfigList = new LinkedList<>();
plainAccessConfigList.add(producerAccessConfig);
plainAccessConfigList.add(consumerAccessConfig);
PlainAccessData ymlMap = new PlainAccessData();
ymlMap.setAccounts(plainAccessConfigList);
// write prepared PlainAccessConfigs to file
final String aclConfigFile = System.getProperty("rocketmq.home.dir") + File.separator + "conf/plain_acl.yml";
AclUtils.writeDataObject(aclConfigFile, ymlMap);
loadConfigFile(plainAccessValidator, aclConfigFile);
// check if added successfully
final AclConfig allAclConfig = plainAccessValidator.getAllAclConfig();
final List<PlainAccessConfig> plainAccessConfigs = allAclConfig.getPlainAccessConfigs();
checkPlainAccessConfig(producerAccessConfig, plainAccessConfigs);
checkPlainAccessConfig(consumerAccessConfig, plainAccessConfigs);
//delete consumer account
plainAccessConfigList.remove(consumerAccessConfig);
AclUtils.writeDataObject(aclConfigFile, ymlMap);
loadConfigFile(plainAccessValidator, aclConfigFile);
// sending messages will be successful using prepared credentials
SessionCredentials producerCredential = new SessionCredentials(DEFAULT_PRODUCER_AK, DEFAULT_PRODUCER_SK);
AclClientRPCHook producerHook = new AclClientRPCHook(producerCredential);
validateSendMessage(RequestCode.SEND_MESSAGE, DEFAULT_TOPIC, producerHook, "", plainAccessValidator);
validateSendMessage(RequestCode.SEND_MESSAGE_V2, DEFAULT_TOPIC, producerHook, "", plainAccessValidator);
// consuming messages will be failed for account has been deleted
SessionCredentials consumerCredential = new SessionCredentials(DEFAULT_CONSUMER_AK, DEFAULT_CONSUMER_SK);
AclClientRPCHook consumerHook = new AclClientRPCHook(consumerCredential);
boolean isConsumeFailed = false;
try {
validatePullMessage(DEFAULT_TOPIC, DEFAULT_GROUP, consumerHook, "", plainAccessValidator);
} catch (AclException e) {
isConsumeFailed = true;
}
Assert.assertTrue("Message should not be consumed after account deleted", isConsumeFailed);
}
private void testValidationAfterConsecutiveUpdates(
PlainAccessValidator plainAccessValidator) throws NoSuchFieldException, IllegalAccessException {
PlainAccessConfig producerAccessConfig = generateProducerAccessConfig();
plainAccessValidator.updateAccessConfig(producerAccessConfig);
PlainAccessConfig consumerAccessConfig = generateConsumerAccessConfig();
plainAccessValidator.updateAccessConfig(consumerAccessConfig);
plainAccessValidator.updateGlobalWhiteAddrsConfig(DEFAULT_GLOBAL_WHITE_ADDRS_LIST, null);
// check if the above config updated successfully
final AclConfig allAclConfig = plainAccessValidator.getAllAclConfig();
final List<PlainAccessConfig> plainAccessConfigs = allAclConfig.getPlainAccessConfigs();
checkPlainAccessConfig(producerAccessConfig, plainAccessConfigs);
checkPlainAccessConfig(consumerAccessConfig, plainAccessConfigs);
Assert.assertEquals(DEFAULT_GLOBAL_WHITE_ADDRS_LIST, allAclConfig.getGlobalWhiteAddrs());
// check sending and consuming messages
SessionCredentials producerCredential = new SessionCredentials(DEFAULT_PRODUCER_AK, DEFAULT_PRODUCER_SK);
AclClientRPCHook producerHook = new AclClientRPCHook(producerCredential);
validateSendMessage(RequestCode.SEND_MESSAGE, DEFAULT_TOPIC, producerHook, "", plainAccessValidator);
validateSendMessage(RequestCode.SEND_MESSAGE_V2, DEFAULT_TOPIC, producerHook, "", plainAccessValidator);
SessionCredentials consumerCredential = new SessionCredentials(DEFAULT_CONSUMER_AK, DEFAULT_CONSUMER_SK);
AclClientRPCHook consumerHook = new AclClientRPCHook(consumerCredential);
validatePullMessage(DEFAULT_TOPIC, DEFAULT_GROUP, consumerHook, "", plainAccessValidator);
// load from file
loadConfigFile(plainAccessValidator,
System.getProperty("rocketmq.home.dir") + File.separator + "conf/plain_acl.yml");
SessionCredentials unmatchedCredential = new SessionCredentials("non_exists_sk", "non_exists_sk");
AclClientRPCHook dummyHook = new AclClientRPCHook(unmatchedCredential);
validateSendMessage(RequestCode.SEND_MESSAGE, DEFAULT_TOPIC, dummyHook, DEFAULT_GLOBAL_WHITE_ADDR, plainAccessValidator);
validateSendMessage(RequestCode.SEND_MESSAGE_V2, DEFAULT_TOPIC, dummyHook, DEFAULT_GLOBAL_WHITE_ADDR, plainAccessValidator);
validatePullMessage(DEFAULT_TOPIC, DEFAULT_GROUP, dummyHook, DEFAULT_GLOBAL_WHITE_ADDR, plainAccessValidator);
//recheck after reloading
validateSendMessage(RequestCode.SEND_MESSAGE, DEFAULT_TOPIC, producerHook, "", plainAccessValidator);
validateSendMessage(RequestCode.SEND_MESSAGE_V2, DEFAULT_TOPIC, producerHook, "", plainAccessValidator);
validatePullMessage(DEFAULT_TOPIC, DEFAULT_GROUP, consumerHook, "", plainAccessValidator);
}
private void loadConfigFile(PlainAccessValidator plainAccessValidator,
String configFileName) throws NoSuchFieldException, IllegalAccessException {
Class<PlainAccessValidator> clazz = PlainAccessValidator.class;
Field f = clazz.getDeclaredField("aclPlugEngine");
f.setAccessible(true);
PlainPermissionManager aclPlugEngine = (PlainPermissionManager) f.get(plainAccessValidator);
aclPlugEngine.load(configFileName);
}
private PlainAccessConfig generateConsumerAccessConfig() {
PlainAccessConfig plainAccessConfig2 = new PlainAccessConfig();
plainAccessConfig2.setAccessKey(DEFAULT_CONSUMER_AK);
plainAccessConfig2.setSecretKey(DEFAULT_CONSUMER_SK);
plainAccessConfig2.setAdmin(false);
plainAccessConfig2.setDefaultTopicPerm(AclConstants.DENY);
plainAccessConfig2.setDefaultGroupPerm(AclConstants.DENY);
plainAccessConfig2.setTopicPerms(Collections.singletonList(DEFAULT_TOPIC + "=" + AclConstants.SUB));
plainAccessConfig2.setGroupPerms(Collections.singletonList(DEFAULT_GROUP + "=" + AclConstants.SUB));
return plainAccessConfig2;
}
private PlainAccessConfig generateProducerAccessConfig() {
PlainAccessConfig plainAccessConfig = new PlainAccessConfig();
plainAccessConfig.setAccessKey(DEFAULT_PRODUCER_AK);
plainAccessConfig.setSecretKey(DEFAULT_PRODUCER_SK);
plainAccessConfig.setAdmin(false);
plainAccessConfig.setDefaultTopicPerm(AclConstants.DENY);
plainAccessConfig.setDefaultGroupPerm(AclConstants.DENY);
plainAccessConfig.setTopicPerms(Collections.singletonList(DEFAULT_TOPIC + "=" + AclConstants.PUB));
return plainAccessConfig;
}
public void validatePullMessage(String topic,
String group,
AclClientRPCHook aclClientRPCHook,
String remoteAddr,
PlainAccessValidator plainAccessValidator) {
PullMessageRequestHeader pullMessageRequestHeader = new PullMessageRequestHeader();
pullMessageRequestHeader.setTopic(topic);
pullMessageRequestHeader.setConsumerGroup(group);
RemotingCommand remotingCommand = RemotingCommand.createRequestCommand(RequestCode.PULL_MESSAGE,
pullMessageRequestHeader);
aclClientRPCHook.doBeforeRequest(remoteAddr, remotingCommand);
ByteBuffer buf = remotingCommand.encodeHeader();
buf.getInt();
buf = ByteBuffer.allocate(buf.limit() - buf.position()).put(buf);
buf.position(0);
try {
PlainAccessResource accessResource = (PlainAccessResource) plainAccessValidator.parse(
RemotingCommand.decode(buf), remoteAddr);
plainAccessValidator.validate(accessResource);
} catch (RemotingCommandException e) {
e.printStackTrace();
Assert.fail("Should not throw RemotingCommandException");
}
}
public void validateSendMessage(int requestCode,
String topic,
AclClientRPCHook aclClientRPCHook,
String remoteAddr,
PlainAccessValidator plainAccessValidator) {
SendMessageRequestHeader messageRequestHeader = new SendMessageRequestHeader();
messageRequestHeader.setTopic(topic);
RemotingCommand remotingCommand;
if (RequestCode.SEND_MESSAGE == requestCode) {
remotingCommand = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, messageRequestHeader);
} else {
remotingCommand = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE_V2,
SendMessageRequestHeaderV2.createSendMessageRequestHeaderV2(messageRequestHeader));
}
aclClientRPCHook.doBeforeRequest(remoteAddr, remotingCommand);
ByteBuffer buf = remotingCommand.encodeHeader();
buf.getInt();
buf = ByteBuffer.allocate(buf.limit() - buf.position()).put(buf);
buf.position(0);
try {
PlainAccessResource accessResource = (PlainAccessResource) plainAccessValidator.parse(
RemotingCommand.decode(buf), remoteAddr);
plainAccessValidator.validate(accessResource);
} catch (RemotingCommandException e) {
e.printStackTrace();
Assert.fail("Should not throw RemotingCommandException");
}
}
private void checkPlainAccessConfig(final PlainAccessConfig plainAccessConfig,
final List<PlainAccessConfig> plainAccessConfigs) {
for (PlainAccessConfig config : plainAccessConfigs) {
if (config.getAccessKey().equals(plainAccessConfig.getAccessKey())) {
Assert.assertEquals(plainAccessConfig.getSecretKey(), config.getSecretKey());
Assert.assertEquals(plainAccessConfig.isAdmin(), config.isAdmin());
Assert.assertEquals(plainAccessConfig.getDefaultGroupPerm(), config.getDefaultGroupPerm());
Assert.assertEquals(plainAccessConfig.getDefaultGroupPerm(), config.getDefaultGroupPerm());
Assert.assertEquals(plainAccessConfig.getWhiteRemoteAddress(), config.getWhiteRemoteAddress());
if (null != plainAccessConfig.getTopicPerms()) {
Assert.assertNotNull(config.getTopicPerms());
Assert.assertTrue(config.getTopicPerms().containsAll(plainAccessConfig.getTopicPerms()));
}
if (null != plainAccessConfig.getGroupPerms()) {
Assert.assertNotNull(config.getGroupPerms());
Assert.assertTrue(config.getGroupPerms().containsAll(plainAccessConfig.getGroupPerms()));
}
}
}
}
private void checkDefaultAclFileExists() {
boolean isExists = Files.exists(Paths.get(System.getProperty("rocketmq.home.dir")
+ File.separator + "conf" + File.separator + "plain_acl.yml"));
Assert.assertTrue("default acl config file should exist", isExists);
}
}
@@ -1,133 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import java.util.HashMap;
import java.util.Map;
import apache.rocketmq.v2.RecallMessageRequest;
import apache.rocketmq.v2.Resource;
import com.google.protobuf.GeneratedMessageV3;
import org.apache.rocketmq.acl.common.AuthenticationHeader;
import org.apache.rocketmq.acl.common.Permission;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.remoting.protocol.RequestCode;
import org.apache.rocketmq.remoting.protocol.header.RecallMessageRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.SendMessageRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.SendMessageRequestHeaderV2;
import org.junit.Assert;
import org.junit.Test;
public class PlainAccessResourceTest {
public static final String DEFAULT_TOPIC = "topic-acl";
public static final String DEFAULT_PRODUCER_GROUP = "PID_acl";
public static final String DEFAULT_CONSUMER_GROUP = "GID_acl";
public static final String DEFAULT_REMOTE_ADDR = "192.128.1.1";
public static final String AUTH_HEADER =
"Signature Credential=1234567890/test, SignedHeaders=host, Signature=1234567890";
@Test
public void testParseSendNormal() {
SendMessageRequestHeader requestHeader = new SendMessageRequestHeader();
requestHeader.setTopic(DEFAULT_TOPIC);
requestHeader.setProducerGroup(DEFAULT_PRODUCER_GROUP);
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader);
request.makeCustomHeaderToNet();
PlainAccessResource accessResource = PlainAccessResource.parse(request, DEFAULT_REMOTE_ADDR);
Map<String, Byte> permMap = new HashMap<>(1);
permMap.put(DEFAULT_TOPIC, Permission.PUB);
Assert.assertEquals(permMap, accessResource.getResourcePermMap());
}
@Test
public void testParseSendRetry() {
SendMessageRequestHeader requestHeader = new SendMessageRequestHeader();
requestHeader.setTopic(MixAll.getRetryTopic(DEFAULT_CONSUMER_GROUP));
requestHeader.setProducerGroup(DEFAULT_PRODUCER_GROUP);
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE, requestHeader);
request.makeCustomHeaderToNet();
PlainAccessResource accessResource = PlainAccessResource.parse(request, DEFAULT_REMOTE_ADDR);
Map<String, Byte> permMap = new HashMap<>(1);
permMap.put(MixAll.getRetryTopic(DEFAULT_CONSUMER_GROUP), Permission.SUB);
Assert.assertEquals(permMap, accessResource.getResourcePermMap());
}
@Test
public void testParseSendNormalV2() {
SendMessageRequestHeaderV2 requestHeaderV2 = new SendMessageRequestHeaderV2();
requestHeaderV2.setB(DEFAULT_TOPIC);
requestHeaderV2.setA(DEFAULT_PRODUCER_GROUP);
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE_V2, requestHeaderV2);
request.makeCustomHeaderToNet();
PlainAccessResource accessResource = PlainAccessResource.parse(request, DEFAULT_REMOTE_ADDR);
Map<String, Byte> permMap = new HashMap<>(1);
permMap.put(DEFAULT_TOPIC, Permission.PUB);
Assert.assertEquals(permMap, accessResource.getResourcePermMap());
}
@Test
public void testParseSendRetryV2() {
SendMessageRequestHeaderV2 requestHeaderV2 = new SendMessageRequestHeaderV2();
requestHeaderV2.setB(MixAll.getRetryTopic(DEFAULT_CONSUMER_GROUP));
requestHeaderV2.setA(DEFAULT_PRODUCER_GROUP);
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.SEND_MESSAGE_V2, requestHeaderV2);
request.makeCustomHeaderToNet();
PlainAccessResource accessResource = PlainAccessResource.parse(request, DEFAULT_REMOTE_ADDR);
Map<String, Byte> permMap = new HashMap<>(1);
permMap.put(MixAll.getRetryTopic(DEFAULT_CONSUMER_GROUP), Permission.SUB);
Assert.assertEquals(permMap, accessResource.getResourcePermMap());
}
@Test
public void testParseRecallMessage() {
// remoting
RecallMessageRequestHeader requestHeader = new RecallMessageRequestHeader();
requestHeader.setTopic(DEFAULT_TOPIC);
requestHeader.setProducerGroup(DEFAULT_PRODUCER_GROUP);
requestHeader.setRecallHandle("handle");
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.RECALL_MESSAGE, requestHeader);
request.makeCustomHeaderToNet();
PlainAccessResource accessResource = PlainAccessResource.parse(request, DEFAULT_REMOTE_ADDR);
Assert.assertTrue(Permission.PUB == accessResource.getResourcePermMap().get(DEFAULT_TOPIC));
// grpc
GeneratedMessageV3 grpcRequest = RecallMessageRequest.newBuilder()
.setTopic(Resource.newBuilder().setName(DEFAULT_TOPIC).build())
.setRecallHandle("handle")
.build();
accessResource = PlainAccessResource.parse(grpcRequest, mockAuthenticationHeader());
Assert.assertTrue(Permission.PUB == accessResource.getResourcePermMap().get(DEFAULT_TOPIC));
}
private AuthenticationHeader mockAuthenticationHeader() {
return AuthenticationHeader.builder()
.remoteAddress(DEFAULT_REMOTE_ADDR)
.authorization(AUTH_HEADER)
.datetime("datetime")
.build();
}
}
File diff suppressed because it is too large Load Diff
@@ -1,88 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import org.apache.rocketmq.acl.common.AclException;
import org.apache.rocketmq.acl.common.Permission;
import org.junit.Before;
import org.junit.Test;
import org.junit.Assert;
public class PlainPermissionCheckerTest {
private PlainPermissionChecker permissionChecker;
@Before
public void setUp() {
permissionChecker = new PlainPermissionChecker();
}
@Test
public void testCheck_withAdminPermission_shouldPass() {
PlainAccessResource checkedAccess = new PlainAccessResource();
checkedAccess.setRequestCode(Permission.SUB);
checkedAccess.addResourceAndPerm("topic1", Permission.PUB);
PlainAccessResource ownedAccess = new PlainAccessResource();
ownedAccess.setAccessKey("adminUser");
ownedAccess.setAdmin(true);
try {
permissionChecker.check(checkedAccess, ownedAccess);
} catch (AclException e) {
Assert.fail("Should not throw any exception for admin user");
}
}
@Test(expected = AclException.class)
public void testCheck_withoutAdminPermissionAndNoDefaultPerm_shouldThrowAclException() {
PlainAccessResource checkedAccess = new PlainAccessResource();
checkedAccess.setRequestCode(Permission.SUB);
checkedAccess.addResourceAndPerm("topic1", Permission.PUB);
PlainAccessResource ownedAccess = new PlainAccessResource();
ownedAccess.setAccessKey("nonAdminUser");
ownedAccess.setAdmin(false);
permissionChecker.check(checkedAccess, ownedAccess);
}
@Test
public void testCheck_withDefaultPermissions_shouldPass() {
PlainAccessResource checkedAccess = new PlainAccessResource();
checkedAccess.setRequestCode(Permission.SUB);
checkedAccess.addResourceAndPerm("topic1", Permission.PUB);
PlainAccessResource ownedAccess = new PlainAccessResource();
ownedAccess.setAccessKey("nonAdminUser");
ownedAccess.setAdmin(false);
ownedAccess.setDefaultTopicPerm(Permission.PUB);
try {
permissionChecker.check(checkedAccess, ownedAccess);
} catch (AclException e) {
Assert.fail("Should not throw any exception for default permissions");
}
}
@Test(expected = AclException.class)
public void testCheck_withoutPermission_shouldThrowAclException() {
PlainAccessResource checkedAccess = new PlainAccessResource();
checkedAccess.setRequestCode(Permission.SUB);
checkedAccess.addResourceAndPerm("topic1", Permission.PUB);
PlainAccessResource ownedAccess = new PlainAccessResource();
ownedAccess.setAccessKey("nonAdminUser");
ownedAccess.setAdmin(false);
ownedAccess.setDefaultTopicPerm(Permission.SUB);
permissionChecker.check(checkedAccess, ownedAccess);
}
}
@@ -1,379 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import com.google.common.base.Joiner;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.rocketmq.acl.common.AclConstants;
import org.apache.rocketmq.acl.common.AclException;
import org.apache.rocketmq.acl.common.AclUtils;
import org.apache.rocketmq.acl.common.Permission;
import org.apache.rocketmq.common.AclConfig;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.assertj.core.api.Assertions;
import org.assertj.core.util.Lists;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class PlainPermissionManagerTest {
PlainPermissionManager plainPermissionManager;
PlainAccessResource pubPlainAccessResource;
PlainAccessResource subPlainAccessResource;
PlainAccessResource anyPlainAccessResource;
PlainAccessResource denyPlainAccessResource;
PlainAccessResource plainAccessResource = new PlainAccessResource();
PlainAccessConfig plainAccessConfig = new PlainAccessConfig();
Set<Integer> adminCode = new HashSet<>();
private static final String DEFAULT_TOPIC = "topic-acl";
private File confHome;
@Before
public void init() throws NoSuchFieldException, SecurityException, IOException {
// UPDATE_AND_CREATE_TOPIC
adminCode.add(17);
// UPDATE_BROKER_CONFIG
adminCode.add(25);
// DELETE_TOPIC_IN_BROKER
adminCode.add(215);
// UPDATE_AND_CREATE_SUBSCRIPTIONGROUP
adminCode.add(200);
// DELETE_SUBSCRIPTIONGROUP
adminCode.add(207);
pubPlainAccessResource = clonePlainAccessResource(Permission.PUB);
subPlainAccessResource = clonePlainAccessResource(Permission.SUB);
anyPlainAccessResource = clonePlainAccessResource(Permission.ANY);
denyPlainAccessResource = clonePlainAccessResource(Permission.DENY);
String folder = "conf";
confHome = AclTestHelper.copyResources(folder, true);
System.setProperty("rocketmq.home.dir", confHome.getAbsolutePath());
plainPermissionManager = new PlainPermissionManager();
}
public PlainAccessResource clonePlainAccessResource(byte perm) {
PlainAccessResource painAccessResource = new PlainAccessResource();
painAccessResource.setAccessKey("RocketMQ");
painAccessResource.setSecretKey("12345678");
painAccessResource.setWhiteRemoteAddress("127.0." + perm + ".*");
painAccessResource.setDefaultGroupPerm(perm);
painAccessResource.setDefaultTopicPerm(perm);
painAccessResource.addResourceAndPerm(PlainAccessResource.getRetryTopic("groupA"), Permission.PUB);
painAccessResource.addResourceAndPerm(PlainAccessResource.getRetryTopic("groupB"), Permission.SUB);
painAccessResource.addResourceAndPerm(PlainAccessResource.getRetryTopic("groupC"), Permission.ANY);
painAccessResource.addResourceAndPerm(PlainAccessResource.getRetryTopic("groupD"), Permission.DENY);
painAccessResource.addResourceAndPerm("topicA", Permission.PUB);
painAccessResource.addResourceAndPerm("topicB", Permission.SUB);
painAccessResource.addResourceAndPerm("topicC", Permission.ANY);
painAccessResource.addResourceAndPerm("topicD", Permission.DENY);
return painAccessResource;
}
@Test
public void buildPlainAccessResourceTest() {
PlainAccessResource plainAccessResource = null;
PlainAccessConfig plainAccess = new PlainAccessConfig();
plainAccess.setAccessKey("RocketMQ");
plainAccess.setSecretKey("12345678");
plainAccessResource = plainPermissionManager.buildPlainAccessResource(plainAccess);
Assert.assertEquals(plainAccessResource.getAccessKey(), "RocketMQ");
Assert.assertEquals(plainAccessResource.getSecretKey(), "12345678");
plainAccess.setWhiteRemoteAddress("127.0.0.1");
plainAccessResource = plainPermissionManager.buildPlainAccessResource(plainAccess);
Assert.assertEquals(plainAccessResource.getWhiteRemoteAddress(), "127.0.0.1");
plainAccess.setAdmin(true);
plainAccessResource = plainPermissionManager.buildPlainAccessResource(plainAccess);
Assert.assertEquals(plainAccessResource.isAdmin(), true);
List<String> groups = new ArrayList<>();
groups.add("groupA=DENY");
groups.add("groupB=PUB|SUB");
groups.add("groupC=PUB");
plainAccess.setGroupPerms(groups);
plainAccessResource = plainPermissionManager.buildPlainAccessResource(plainAccess);
Map<String, Byte> resourcePermMap = plainAccessResource.getResourcePermMap();
Assert.assertEquals(resourcePermMap.size(), 3);
Assert.assertEquals(resourcePermMap.get(PlainAccessResource.getRetryTopic("groupA")).byteValue(), Permission.DENY);
Assert.assertEquals(resourcePermMap.get(PlainAccessResource.getRetryTopic("groupB")).byteValue(), Permission.PUB | Permission.SUB);
Assert.assertEquals(resourcePermMap.get(PlainAccessResource.getRetryTopic("groupC")).byteValue(), Permission.PUB);
List<String> topics = new ArrayList<>();
topics.add("topicA=DENY");
topics.add("topicB=PUB|SUB");
topics.add("topicC=PUB");
plainAccess.setTopicPerms(topics);
plainAccessResource = plainPermissionManager.buildPlainAccessResource(plainAccess);
resourcePermMap = plainAccessResource.getResourcePermMap();
Assert.assertEquals(resourcePermMap.size(), 6);
Assert.assertEquals(resourcePermMap.get("topicA").byteValue(), Permission.DENY);
Assert.assertEquals(resourcePermMap.get("topicB").byteValue(), Permission.PUB | Permission.SUB);
Assert.assertEquals(resourcePermMap.get("topicC").byteValue(), Permission.PUB);
}
@Test(expected = AclException.class)
public void checkPermAdmin() {
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setRequestCode(17);
plainPermissionManager.checkPerm(plainAccessResource, pubPlainAccessResource);
}
@Test
public void checkPerm() {
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.addResourceAndPerm("topicA", Permission.PUB);
plainPermissionManager.checkPerm(plainAccessResource, pubPlainAccessResource);
plainAccessResource.addResourceAndPerm("topicB", Permission.SUB);
plainPermissionManager.checkPerm(plainAccessResource, anyPlainAccessResource);
plainAccessResource = new PlainAccessResource();
plainAccessResource.addResourceAndPerm("topicB", Permission.SUB);
plainPermissionManager.checkPerm(plainAccessResource, subPlainAccessResource);
plainAccessResource.addResourceAndPerm("topicA", Permission.PUB);
plainPermissionManager.checkPerm(plainAccessResource, anyPlainAccessResource);
}
@Test(expected = AclException.class)
public void checkErrorPermDefaultValueNotMatch() {
plainAccessResource = new PlainAccessResource();
plainAccessResource.addResourceAndPerm("topicF", Permission.PUB);
plainPermissionManager.checkPerm(plainAccessResource, subPlainAccessResource);
}
@Test(expected = AclException.class)
public void accountNullTest() {
plainAccessConfig.setAccessKey(null);
plainPermissionManager.buildPlainAccessResource(plainAccessConfig);
}
@Test(expected = AclException.class)
public void accountThanTest() {
plainAccessConfig.setAccessKey("123");
plainPermissionManager.buildPlainAccessResource(plainAccessConfig);
}
@Test(expected = AclException.class)
public void passWordtNullTest() {
plainAccessConfig.setAccessKey(null);
plainPermissionManager.buildPlainAccessResource(plainAccessConfig);
}
@Test(expected = AclException.class)
public void passWordThanTest() {
plainAccessConfig.setSecretKey("123");
plainPermissionManager.buildPlainAccessResource(plainAccessConfig);
}
@SuppressWarnings("unchecked")
@Test
public void cleanAuthenticationInfoTest() throws IllegalAccessException {
// PlainPermissionManager.addPlainAccessResource(plainAccessResource);
Map<String, Map<String, PlainAccessResource>> plainAccessResourceMap = (Map<String, Map<String, PlainAccessResource>>) FieldUtils.readDeclaredField(plainPermissionManager, "aclPlainAccessResourceMap", true);
Assert.assertFalse(plainAccessResourceMap.isEmpty());
plainPermissionManager.clearPermissionInfo();
plainAccessResourceMap = (Map<String, Map<String, PlainAccessResource>>) FieldUtils.readDeclaredField(plainPermissionManager, "aclPlainAccessResourceMap", true);
Assert.assertTrue(plainAccessResourceMap.isEmpty());
}
@Test
public void isWatchStartTest() {
PlainPermissionManager plainPermissionManager = new PlainPermissionManager();
Assert.assertTrue(plainPermissionManager.isWatchStart());
}
@Test
public void testWatch() throws IOException, IllegalAccessException, InterruptedException {
String fileName = Joiner.on(File.separator).join(new String[]{System.getProperty("rocketmq.home.dir"), "conf", "acl", "plain_acl_test.yml"});
File transport = new File(fileName);
transport.delete();
transport.createNewFile();
FileWriter writer = new FileWriter(transport);
writer.write("accounts:\r\n");
writer.write("- accessKey: watchrocketmqx\r\n");
writer.write(" secretKey: 12345678\r\n");
writer.write(" whiteRemoteAddress: 127.0.0.1\r\n");
writer.write(" admin: true\r\n");
writer.flush();
writer.close();
Thread.sleep(1000);
PlainPermissionManager plainPermissionManager = new PlainPermissionManager();
Assert.assertTrue(plainPermissionManager.isWatchStart());
Map<String, String> accessKeyTable = (Map<String, String>) FieldUtils.readDeclaredField(plainPermissionManager, "accessKeyTable", true);
String aclFileName = accessKeyTable.get("watchrocketmqx");
{
Map<String, Map<String, PlainAccessResource>> plainAccessResourceMap = (Map<String, Map<String, PlainAccessResource>>) FieldUtils.readDeclaredField(plainPermissionManager, "aclPlainAccessResourceMap", true);
PlainAccessResource accessResource = plainAccessResourceMap.get(aclFileName).get("watchrocketmqx");
Assert.assertNotNull(accessResource);
Assert.assertEquals(accessResource.getSecretKey(), "12345678");
Assert.assertTrue(accessResource.isAdmin());
}
PlainAccessData updatedMap = AclUtils.getYamlDataObject(fileName, PlainAccessData.class);
List<PlainAccessConfig> accounts = updatedMap.getAccounts();
accounts.get(0).setAccessKey("watchrocketmq1y");
accounts.get(0).setSecretKey("88888888");
accounts.get(0).setAdmin(false);
// Update file and flush to yaml file
AclUtils.writeDataObject(fileName, updatedMap);
Thread.sleep(10000);
{
Map<String, Map<String, PlainAccessResource>> plainAccessResourceMap = (Map<String, Map<String, PlainAccessResource>>) FieldUtils.readDeclaredField(plainPermissionManager, "aclPlainAccessResourceMap", true);
PlainAccessResource accessResource = plainAccessResourceMap.get(aclFileName).get("watchrocketmq1y");
Assert.assertNotNull(accessResource);
Assert.assertEquals(accessResource.getSecretKey(), "88888888");
Assert.assertFalse(accessResource.isAdmin());
}
transport.delete();
}
@Test
public void updateAccessConfigTest() {
Assert.assertThrows(AclException.class, () -> plainPermissionManager.updateAccessConfig(null));
plainAccessConfig.setAccessKey("admin_test");
// Invalid parameter
plainAccessConfig.setSecretKey("123456");
plainAccessConfig.setAdmin(true);
Assert.assertThrows(AclException.class, () -> plainPermissionManager.updateAccessConfig(plainAccessConfig));
plainAccessConfig.setSecretKey("12345678");
// Invalid parameter
plainAccessConfig.setGroupPerms(Lists.newArrayList("groupA!SUB"));
Assert.assertThrows(AclException.class, () -> plainPermissionManager.updateAccessConfig(plainAccessConfig));
// first update
plainAccessConfig.setGroupPerms(Lists.newArrayList("groupA=SUB"));
plainPermissionManager.updateAccessConfig(plainAccessConfig);
// second update
plainAccessConfig.setTopicPerms(Lists.newArrayList("topicA=SUB"));
plainPermissionManager.updateAccessConfig(plainAccessConfig);
}
@Test
public void getAllAclFilesTest() {
final List<String> notExistList = plainPermissionManager.getAllAclFiles("aa/bb");
Assertions.assertThat(notExistList).isEmpty();
final List<String> files = plainPermissionManager.getAllAclFiles(confHome.getAbsolutePath());
Assertions.assertThat(files).isNotEmpty();
}
@Test
public void loadTest() {
plainPermissionManager.load();
final Map<String, DataVersion> map = plainPermissionManager.getDataVersionMap();
Assertions.assertThat(map).isNotEmpty();
}
@Test
public void updateAclConfigFileVersionTest() {
String aclFileName = "test_plain_acl";
PlainAccessData updateAclConfigMap = new PlainAccessData();
List<PlainAccessData.DataVersion> versionElement = new ArrayList<>();
PlainAccessData.DataVersion accountsMap = new PlainAccessData.DataVersion();
accountsMap.setCounter(1);
accountsMap.setTimestamp(System.currentTimeMillis());
versionElement.add(accountsMap);
updateAclConfigMap.setDataVersion(versionElement);
final PlainAccessData map = plainPermissionManager.updateAclConfigFileVersion(aclFileName, updateAclConfigMap);
final List<PlainAccessData.DataVersion> version = map.getDataVersion();
Assert.assertEquals(2L, version.get(0).getCounter());
}
@Test
public void createAclAccessConfigMapTest() {
PlainAccessConfig existedAccountMap = new PlainAccessConfig();
plainAccessConfig.setAccessKey("admin123");
plainAccessConfig.setSecretKey("12345678");
plainAccessConfig.setWhiteRemoteAddress("192.168.1.1");
plainAccessConfig.setAdmin(false);
plainAccessConfig.setDefaultGroupPerm(AclConstants.SUB_PUB);
plainAccessConfig.setTopicPerms(Arrays.asList(DEFAULT_TOPIC + "=" + AclConstants.PUB));
plainAccessConfig.setGroupPerms(Lists.newArrayList("groupA=SUB"));
final PlainAccessConfig map = plainPermissionManager.createAclAccessConfigMap(existedAccountMap, plainAccessConfig);
Assert.assertEquals(AclConstants.SUB_PUB, map.getDefaultGroupPerm());
Assert.assertEquals("groupA=SUB", map.getGroupPerms().get(0));
Assert.assertEquals("12345678", map.getSecretKey());
Assert.assertEquals("admin123", map.getAccessKey());
Assert.assertEquals("192.168.1.1", map.getWhiteRemoteAddress());
Assert.assertEquals("topic-acl=PUB", map.getTopicPerms().get(0));
Assert.assertEquals(false, map.isAdmin());
}
@Test
public void deleteAccessConfigTest() throws InterruptedException {
// delete not exist accessConfig
final boolean flag1 = plainPermissionManager.deleteAccessConfig("test_delete");
assert !flag1;
plainAccessConfig.setAccessKey("test_delete");
plainAccessConfig.setSecretKey("12345678");
plainAccessConfig.setWhiteRemoteAddress("192.168.1.1");
plainAccessConfig.setAdmin(false);
plainAccessConfig.setDefaultGroupPerm(AclConstants.SUB_PUB);
plainAccessConfig.setTopicPerms(Arrays.asList(DEFAULT_TOPIC + "=" + AclConstants.PUB));
plainAccessConfig.setGroupPerms(Lists.newArrayList("groupA=SUB"));
plainPermissionManager.updateAccessConfig(plainAccessConfig);
//delete existed accessConfig
final boolean flag2 = plainPermissionManager.deleteAccessConfig("test_delete");
assert flag2;
}
@Test
public void updateGlobalWhiteAddrsConfigTest() {
final boolean flag = plainPermissionManager.updateGlobalWhiteAddrsConfig(Lists.newArrayList("192.168.1.2"));
assert flag;
final AclConfig config = plainPermissionManager.getAllAclConfig();
Assert.assertEquals(true, config.getGlobalWhiteAddrs().contains("192.168.1.2"));
}
}
@@ -1,379 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import org.apache.rocketmq.acl.common.AclException;
import org.junit.Assert;
import org.junit.Test;
public class RemoteAddressStrategyTest {
RemoteAddressStrategyFactory remoteAddressStrategyFactory = new RemoteAddressStrategyFactory();
@Test
public void netAddressStrategyFactoryExceptionTest() {
PlainAccessResource plainAccessResource = new PlainAccessResource();
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource).getClass(),
RemoteAddressStrategyFactory.BlankRemoteAddressStrategy.class);
}
@Test
public void netAddressStrategyFactoryTest() {
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress("*");
RemoteAddressStrategy remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy, RemoteAddressStrategyFactory.NULL_NET_ADDRESS_STRATEGY);
plainAccessResource.setWhiteRemoteAddress("*.*.*.*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy, RemoteAddressStrategyFactory.NULL_NET_ADDRESS_STRATEGY);
plainAccessResource.setWhiteRemoteAddress("127.0.0.1");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.OneRemoteAddressStrategy.class);
plainAccessResource.setWhiteRemoteAddress("127.0.0.1,127.0.0.2,127.0.0.3");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.MultipleRemoteAddressStrategy.class);
plainAccessResource.setWhiteRemoteAddress("127.0.0.{1,2,3}");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.MultipleRemoteAddressStrategy.class);
plainAccessResource.setWhiteRemoteAddress("127.0.0.1-200");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.RangeRemoteAddressStrategy.class);
plainAccessResource.setWhiteRemoteAddress("127.0.0.*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.RangeRemoteAddressStrategy.class);
plainAccessResource.setWhiteRemoteAddress("127.0.1-20.*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.RangeRemoteAddressStrategy.class);
plainAccessResource.setWhiteRemoteAddress("");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.BlankRemoteAddressStrategy.class);
// IPv6 test
plainAccessResource.setWhiteRemoteAddress("*:*:*:*:*:*:*:*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy, RemoteAddressStrategyFactory.NULL_NET_ADDRESS_STRATEGY);
plainAccessResource.setWhiteRemoteAddress("1050:0000:0000:0000:0005:0600:300c:326b");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.OneRemoteAddressStrategy.class);
plainAccessResource.setWhiteRemoteAddress("1050::0005:0600:300c:3261,1050::0005:0600:300c:3262,1050::0005:0600:300c:3263");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.MultipleRemoteAddressStrategy.class);
plainAccessResource.setWhiteRemoteAddress("1050::0005:0600:300c:3261:{1,2,3}");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.MultipleRemoteAddressStrategy.class);
plainAccessResource.setWhiteRemoteAddress("1050::0005:0600:300c:3261:1-200");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.RangeRemoteAddressStrategy.class);
plainAccessResource.setWhiteRemoteAddress("1050:0005:0600:300c:3261:*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.RangeRemoteAddressStrategy.class);
plainAccessResource.setWhiteRemoteAddress("1050::0005:0600:300c:3261:1-20:*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
Assert.assertEquals(remoteAddressStrategy.getClass(), RemoteAddressStrategyFactory.RangeRemoteAddressStrategy.class);
}
@Test(expected = AclException.class)
public void verifyTest() {
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress("127.0.0.1");
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
plainAccessResource.setWhiteRemoteAddress("256.0.0.1");
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
plainAccessResource.setWhiteRemoteAddress("::1ggg");
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
}
@Test
public void nullNetAddressStrategyTest() {
boolean isMatch = RemoteAddressStrategyFactory.NULL_NET_ADDRESS_STRATEGY.match(new PlainAccessResource());
Assert.assertTrue(isMatch);
}
@Test
public void blankNetAddressStrategyTest() {
boolean isMatch = RemoteAddressStrategyFactory.BLANK_NET_ADDRESS_STRATEGY.match(new PlainAccessResource());
Assert.assertFalse(isMatch);
}
@Test
public void oneNetAddressStrategyTest() {
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress("127.0.0.1");
RemoteAddressStrategy remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
plainAccessResource.setWhiteRemoteAddress("");
boolean match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertFalse(match);
plainAccessResource.setWhiteRemoteAddress("127.0.0.2");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertFalse(match);
plainAccessResource.setWhiteRemoteAddress("127.0.0.1");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertTrue(match);
// Ipv6 test
plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress("::1");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
plainAccessResource.setWhiteRemoteAddress("");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertFalse(match);
plainAccessResource.setWhiteRemoteAddress("::2");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertFalse(match);
plainAccessResource.setWhiteRemoteAddress("::1");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertTrue(match);
plainAccessResource.setWhiteRemoteAddress("0000:0000:0000:0000:0000:0000:0000:0001");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertTrue(match);
}
@Test
public void multipleNetAddressStrategyTest() {
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress("127.0.0.1,127.0.0.2,127.0.0.3");
RemoteAddressStrategy remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
multipleNetAddressStrategyTest(remoteAddressStrategy);
plainAccessResource.setWhiteRemoteAddress("127.0.0.{1,2,3}");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
multipleNetAddressStrategyTest(remoteAddressStrategy);
plainAccessResource.setWhiteRemoteAddress("192.100-150.*.*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
plainAccessResource.setWhiteRemoteAddress("192.130.0.2");
boolean match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertTrue(match);
plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress("1050::0005:0600:300c:1,1050::0005:0600:300c:2,1050::0005:0600:300c:3");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
multipleIPv6NetAddressStrategyTest(remoteAddressStrategy);
plainAccessResource.setWhiteRemoteAddress("1050::0005:0600:300c:{1,2,3}");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
multipleIPv6NetAddressStrategyTest(remoteAddressStrategy);
}
@Test(expected = AclException.class)
public void multipleNetAddressStrategyExceptionTest() {
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress("127.0.0.1,2,3}");
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
plainAccessResource.setWhiteRemoteAddress("::1,2,3}");
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
plainAccessResource.setWhiteRemoteAddress("192.168.1.{1}");
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
plainAccessResource.setWhiteRemoteAddress("192.168.1.{1,2}");
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
plainAccessResource.setWhiteRemoteAddress("192.168.{1}");
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
plainAccessResource.setWhiteRemoteAddress("{192.168.1}");
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
plainAccessResource.setWhiteRemoteAddress("{192.168.1.1}");
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
}
private void multipleNetAddressStrategyTest(RemoteAddressStrategy remoteAddressStrategy) {
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress("127.0.0.1");
boolean match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertTrue(match);
plainAccessResource.setWhiteRemoteAddress("127.0.0.2");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertTrue(match);
plainAccessResource.setWhiteRemoteAddress("127.0.0.3");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertTrue(match);
plainAccessResource.setWhiteRemoteAddress("127.0.0.4");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertFalse(match);
plainAccessResource.setWhiteRemoteAddress("127.0.0.0");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertFalse(match);
}
private void multipleIPv6NetAddressStrategyTest(RemoteAddressStrategy remoteAddressStrategy) {
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress("1050:0000:0000:0000:0005:0600:300c:1");
boolean match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertTrue(match);
plainAccessResource.setWhiteRemoteAddress("1050:0000:0000:0000:0005:0600:300c:2");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertTrue(match);
plainAccessResource.setWhiteRemoteAddress("1050:0000:0000:0000:0005:0600:300c:3");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertTrue(match);
plainAccessResource.setWhiteRemoteAddress("1050:0000:0000:0000:0005:0600:300c:4");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertFalse(match);
plainAccessResource.setWhiteRemoteAddress("1050:0000:0000:0000:0005:0600:300c:0");
match = remoteAddressStrategy.match(plainAccessResource);
Assert.assertFalse(match);
}
@Test
public void rangeNetAddressStrategyTest() {
String head = "127.0.0.";
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress("127.0.0.1-200");
RemoteAddressStrategy remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
rangeNetAddressStrategyTest(remoteAddressStrategy, head, 1, 200, true);
plainAccessResource.setWhiteRemoteAddress("127.0.0.*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
rangeNetAddressStrategyTest(remoteAddressStrategy, head, 0, 255, true);
plainAccessResource.setWhiteRemoteAddress("127.0.1-200.*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
rangeNetAddressStrategyThirdlyTest(remoteAddressStrategy, head, 1, 200);
plainAccessResource.setWhiteRemoteAddress("127.*.*.*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
rangeNetAddressStrategyTest(remoteAddressStrategy, head, 0, 255, true);
plainAccessResource.setWhiteRemoteAddress("127.1-150.*.*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
rangeNetAddressStrategyThirdlyTest(remoteAddressStrategy, head, 1, 200);
// IPv6 test
head = "1050::0005:0600:300c:";
plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress("1050::0005:0600:300c:1-200");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
rangeIPv6NetAddressStrategyTest(remoteAddressStrategy, head, "1", "200", true);
plainAccessResource.setWhiteRemoteAddress("1050::0005:0600:300c:*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
rangeIPv6NetAddressStrategyTest(remoteAddressStrategy, head, "0", "ffff", true);
plainAccessResource.setWhiteRemoteAddress("1050::0005:0600:3001:*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
rangeIPv6NetAddressStrategyTest(remoteAddressStrategy, head, "0", "ffff", false);
head = "1050::0005:0600:300c:1:";
plainAccessResource.setWhiteRemoteAddress("1050::0005:0600:300c:1-200:*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
rangeIPv6NetAddressStrategyTest(remoteAddressStrategy, head, "0", "ffff", true);
head = "1050::0005:0600:300c:201:";
plainAccessResource.setWhiteRemoteAddress("1050::0005:0600:300c:1-200:*");
remoteAddressStrategy = remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
rangeIPv6NetAddressStrategyTest(remoteAddressStrategy, head, "0", "ffff", false);
}
private void rangeNetAddressStrategyTest(RemoteAddressStrategy remoteAddressStrategy, String head, int start,
int end,
boolean isFalse) {
PlainAccessResource plainAccessResource = new PlainAccessResource();
for (int i = -10; i < 300; i++) {
plainAccessResource.setWhiteRemoteAddress(head + i);
boolean match = remoteAddressStrategy.match(plainAccessResource);
if (isFalse && i >= start && i <= end) {
Assert.assertTrue(match);
continue;
}
Assert.assertFalse(match);
}
}
private void rangeNetAddressStrategyThirdlyTest(RemoteAddressStrategy remoteAddressStrategy, String head, int start,
int end) {
String newHead;
for (int i = -10; i < 300; i++) {
newHead = head + i;
if (i >= start && i <= end) {
rangeNetAddressStrategyTest(remoteAddressStrategy, newHead, 0, 255, false);
}
}
}
private void rangeIPv6NetAddressStrategyTest(RemoteAddressStrategy remoteAddressStrategy, String head, String start,
String end,
boolean isFalse) {
PlainAccessResource plainAccessResource = new PlainAccessResource();
for (int i = -10; i < 65536 + 100; i++) {
String hex = Integer.toHexString(i);
plainAccessResource.setWhiteRemoteAddress(head + hex);
boolean match = remoteAddressStrategy.match(plainAccessResource);
int startNum = Integer.parseInt(start, 16);
int endNum = Integer.parseInt(end, 16);
if (isFalse && i >= startNum && i <= endNum) {
Assert.assertTrue(match);
continue;
}
Assert.assertFalse(match);
}
}
@Test(expected = AclException.class)
public void rangeNetAddressStrategyExceptionStartGreaterEndTest() {
rangeNetAddressStrategyExceptionTest("127.0.0.2-1");
}
@Test(expected = AclException.class)
public void rangeNetAddressStrategyExceptionScopeTest() {
rangeNetAddressStrategyExceptionTest("127.0.0.-1-200");
}
@Test(expected = AclException.class)
public void rangeNetAddressStrategyExceptionScopeTwoTest() {
rangeNetAddressStrategyExceptionTest("127.0.0.0-256");
}
private void rangeNetAddressStrategyExceptionTest(String netAddress) {
PlainAccessResource plainAccessResource = new PlainAccessResource();
plainAccessResource.setWhiteRemoteAddress(netAddress);
remoteAddressStrategyFactory.getRemoteAddressStrategy(plainAccessResource);
}
}
@@ -1,31 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
accounts:
- accessKey: rocketmq3
secretKey: 12345678
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: DENY
topicPerms:
- topicA=PUB
- topicB=SUB
- topicC=PUB|SUB
- topicD=DENY
groupPerms:
- groupB=SUB
- groupC=PUB|SUB
- groupD=DENY
@@ -1,39 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## no global white addresses in this file, define them in ../plain_acl.yml
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress: 192.168.0.*
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
# the group should convert to retry topic
- groupA=DENY
- groupB=SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
# if it is admin, it could access all resources
admin: true
@@ -1,21 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
@@ -1,43 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress: 192.168.0.*
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
# the group should convert to retry topic
- groupA=DENY
- groupB=SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
# if it is admin, it could access all resources
admin: true
-39
View File
@@ -1,39 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress: 192.168.0.*
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
- groupA=DENY
- groupB=SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
admin: true
@@ -1,39 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress: 192.168.0.*
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
- groupA=DENY
- groupB=SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
admin: true
@@ -1,39 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress: 192.168.0.*
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
- groupA=DENY
- groupB=SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
admin: true
@@ -1,39 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress: 192.168.0.*
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
- groupA=DENY
- groupB=SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
admin: true
@@ -1,39 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress: 192.168.0.*
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
- groupA=DENY
- groupB=SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
admin: true
@@ -1,39 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress: 192.168.0.*
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
- groupA=DENY
- groupB=SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
admin: true
@@ -1,20 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
@@ -1,25 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
accounts:
- accessKey: watchrocketmq
secretKey: 12345678
whiteRemoteAddress: 127.0.0.1
admin: true
- accessKey: watchrocketmq1
secretKey: 88888888
whiteRemoteAddress: 127.0.0.1
admin: false
@@ -1,19 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
@@ -1,39 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## no global white addresses in this file, define them in ../plain_acl.yml
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress: 192.168.0.*
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
# the group should convert to retry topic
- groupA=DENY
- groupB=SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
# if it is admin, it could access all resources
admin: true
@@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<logger name="org.apache.rocketmq" level="error" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
@@ -1,18 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
accounts: []
@@ -1,39 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress: 192.168.0.*
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
- groupA=DENY
- groupB=SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
admin: true
@@ -1,36 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
## suggested format
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress: 192.168.0.*
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
- groupA=DENY
- groupB=SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
admin: true
+2 -2
View File
@@ -21,10 +21,10 @@ java_library(
srcs = glob(["src/main/java/**/*.java"]),
visibility = ["//visibility:public"],
deps = [
"//acl",
"//common",
"//remoting",
"//srvutil",
"//client",
"@maven//:commons_codec_commons_codec",
"@maven//:org_apache_commons_commons_lang3",
"@maven//:commons_collections_commons_collections",
@@ -48,10 +48,10 @@ java_library(
visibility = ["//visibility:public"],
deps = [
":auth",
"//acl",
"//:test_deps",
"//common",
"//remoting",
"//client",
"@maven//:commons_codec_commons_codec",
"@maven//:org_apache_commons_commons_lang3",
"@maven//:commons_collections_commons_collections",
+9 -9
View File
@@ -29,11 +29,7 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-remoting</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-common</artifactId>
<artifactId>rocketmq-client</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
@@ -44,12 +40,12 @@
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-acl</artifactId>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
@@ -61,6 +57,10 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
<build>
@@ -16,14 +16,9 @@
*/
package org.apache.rocketmq.auth.migration;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.acl.common.AclConstants;
import org.apache.rocketmq.acl.plain.PlainPermissionManager;
import org.apache.rocketmq.auth.authentication.enums.UserType;
import org.apache.rocketmq.auth.authentication.factory.AuthenticationFactory;
import org.apache.rocketmq.auth.authentication.manager.AuthenticationMetadataManager;
@@ -38,8 +33,9 @@ import org.apache.rocketmq.auth.authorization.model.Policy;
import org.apache.rocketmq.auth.authorization.model.PolicyEntry;
import org.apache.rocketmq.auth.authorization.model.Resource;
import org.apache.rocketmq.auth.config.AuthConfig;
import org.apache.rocketmq.common.AclConfig;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.auth.migration.v1.PlainPermissionManager;
import org.apache.rocketmq.auth.migration.v1.AclConfig;
import org.apache.rocketmq.auth.migration.v1.PlainAccessConfig;
import org.apache.rocketmq.common.action.Action;
import org.apache.rocketmq.common.constant.CommonConstants;
import org.apache.rocketmq.common.constant.LoggerName;
@@ -48,6 +44,11 @@ import org.apache.rocketmq.common.resource.ResourceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
public class AuthMigrator {
protected static final Logger LOG = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
@@ -15,7 +15,7 @@
* limitations under the License.
*/
package org.apache.rocketmq.acl;
package org.apache.rocketmq.auth.migration.v1;
public interface AccessResource {
}
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.common;
package org.apache.rocketmq.auth.migration.v1;
import java.util.List;
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.common;
package org.apache.rocketmq.auth.migration.v1;
import java.io.Serializable;
import java.util.List;
@@ -14,9 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
import org.apache.rocketmq.common.PlainAccessConfig;
package org.apache.rocketmq.auth.migration.v1;
import java.io.Serializable;
import java.util.ArrayList;
@@ -0,0 +1,177 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.auth.migration.v1;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.rocketmq.common.KeyBuilder;
import org.apache.rocketmq.common.MixAll;
import java.util.HashMap;
import java.util.Map;
public class PlainAccessResource implements AccessResource {
// Identify the user
private String accessKey;
private String secretKey;
private String whiteRemoteAddress;
private boolean admin;
private byte defaultTopicPerm = 1;
private byte defaultGroupPerm = 1;
private Map<String, Byte> resourcePermMap;
private int requestCode;
// The content to calculate the content
private byte[] content;
private String signature;
private String secretToken;
private String recognition;
public PlainAccessResource() {
}
public static String getGroupFromRetryTopic(String retryTopic) {
if (retryTopic == null) {
return null;
}
return KeyBuilder.parseGroup(retryTopic);
}
public static String getRetryTopic(String group) {
if (group == null) {
return null;
}
return MixAll.getRetryTopic(group);
}
public void addResourceAndPerm(String resource, byte perm) {
if (resource == null) {
return;
}
if (resourcePermMap == null) {
resourcePermMap = new HashMap<>();
}
resourcePermMap.put(resource, perm);
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getWhiteRemoteAddress() {
return whiteRemoteAddress;
}
public void setWhiteRemoteAddress(String whiteRemoteAddress) {
this.whiteRemoteAddress = whiteRemoteAddress;
}
public boolean isAdmin() {
return admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
public byte getDefaultTopicPerm() {
return defaultTopicPerm;
}
public void setDefaultTopicPerm(byte defaultTopicPerm) {
this.defaultTopicPerm = defaultTopicPerm;
}
public byte getDefaultGroupPerm() {
return defaultGroupPerm;
}
public void setDefaultGroupPerm(byte defaultGroupPerm) {
this.defaultGroupPerm = defaultGroupPerm;
}
public Map<String, Byte> getResourcePermMap() {
return resourcePermMap;
}
public String getRecognition() {
return recognition;
}
public void setRecognition(String recognition) {
this.recognition = recognition;
}
public int getRequestCode() {
return requestCode;
}
public void setRequestCode(int requestCode) {
this.requestCode = requestCode;
}
public String getSecretToken() {
return secretToken;
}
public void setSecretToken(String secretToken) {
this.secretToken = secretToken;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
public byte[] getContent() {
return content;
}
public void setContent(byte[] content) {
this.content = content;
}
}
@@ -0,0 +1,148 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.auth.migration.v1;
import org.apache.rocketmq.acl.common.AclException;
import org.apache.rocketmq.acl.common.AclUtils;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.constant.LoggerName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class PlainPermissionManager {
private static final Logger log = LoggerFactory.getLogger(LoggerName.COMMON_LOGGER_NAME);
private String fileHome = System.getProperty(MixAll.ROCKETMQ_HOME_PROPERTY,
System.getenv(MixAll.ROCKETMQ_HOME_ENV));
private String defaultAclDir;
private String defaultAclFile;
private List<String> fileList = new ArrayList<>();
public PlainPermissionManager() {
this.defaultAclDir = MixAll.dealFilePath(fileHome + File.separator + "conf" + File.separator + "acl");
this.defaultAclFile = MixAll.dealFilePath(fileHome + File.separator + System.getProperty("rocketmq.acl.plain.file", "conf" + File.separator + "plain_acl.yml"));
load();
}
public List<String> getAllAclFiles(String path) {
if (!new File(path).exists()) {
log.info("The default acl dir {} is not exist", path);
return new ArrayList<>();
}
List<String> allAclFileFullPath = new ArrayList<>();
File file = new File(path);
File[] files = file.listFiles();
for (int i = 0; files != null && i < files.length; i++) {
String fileName = files[i].getAbsolutePath();
File f = new File(fileName);
if (fileName.equals(fileHome + MixAll.ACL_CONF_TOOLS_FILE)) {
continue;
} else if (fileName.endsWith(".yml") || fileName.endsWith(".yaml")) {
allAclFileFullPath.add(fileName);
} else if (f.isDirectory()) {
allAclFileFullPath.addAll(getAllAclFiles(fileName));
}
}
return allAclFileFullPath;
}
public void load() {
if (fileHome == null || fileHome.isEmpty()) {
return;
}
assureAclConfigFilesExist();
fileList = getAllAclFiles(defaultAclDir);
if (new File(defaultAclFile).exists() && !fileList.contains(defaultAclFile)) {
fileList.add(defaultAclFile);
}
}
/**
* Currently GlobalWhiteAddress is defined in {@link #defaultAclFile}, so make sure it exists.
*/
private void assureAclConfigFilesExist() {
final Path defaultAclFilePath = Paths.get(this.defaultAclFile);
if (!Files.exists(defaultAclFilePath)) {
try {
Files.createFile(defaultAclFilePath);
} catch (FileAlreadyExistsException e) {
// Maybe created by other threads
} catch (IOException e) {
log.error("Error in creating " + this.defaultAclFile, e);
throw new AclException(e.getMessage());
}
}
}
public AclConfig getAllAclConfig() {
AclConfig aclConfig = new AclConfig();
List<PlainAccessConfig> configs = new ArrayList<>();
List<String> whiteAddrs = new ArrayList<>();
Set<String> accessKeySets = new HashSet<>();
for (String path : fileList) {
PlainAccessData plainAclConfData = AclUtils.getYamlDataObject(path, PlainAccessData.class);
if (plainAclConfData == null) {
continue;
}
List<String> globalWhiteAddrs = plainAclConfData.getGlobalWhiteRemoteAddresses();
if (globalWhiteAddrs != null && !globalWhiteAddrs.isEmpty()) {
whiteAddrs.addAll(globalWhiteAddrs);
}
List<PlainAccessConfig> plainAccessConfigs = plainAclConfData.getAccounts();
if (plainAccessConfigs != null && !plainAccessConfigs.isEmpty()) {
for (PlainAccessConfig accessConfig : plainAccessConfigs) {
if (!accessKeySets.contains(accessConfig.getAccessKey())) {
accessKeySets.add(accessConfig.getAccessKey());
PlainAccessConfig plainAccessConfig = new PlainAccessConfig();
plainAccessConfig.setGroupPerms(accessConfig.getGroupPerms());
plainAccessConfig.setDefaultTopicPerm(accessConfig.getDefaultTopicPerm());
plainAccessConfig.setDefaultGroupPerm(accessConfig.getDefaultGroupPerm());
plainAccessConfig.setAccessKey(accessConfig.getAccessKey());
plainAccessConfig.setSecretKey(accessConfig.getSecretKey());
plainAccessConfig.setAdmin(accessConfig.isAdmin());
plainAccessConfig.setTopicPerms(accessConfig.getTopicPerms());
plainAccessConfig.setWhiteRemoteAddress(accessConfig.getWhiteRemoteAddress());
configs.add(plainAccessConfig);
}
}
}
}
aclConfig.setPlainAccessConfigs(configs);
aclConfig.setGlobalWhiteAddrs(whiteAddrs);
return aclConfig;
}
}
@@ -17,13 +17,13 @@
package org.apache.rocketmq.auth.migration;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.rocketmq.acl.plain.PlainPermissionManager;
import org.apache.rocketmq.auth.authentication.manager.AuthenticationMetadataManager;
import org.apache.rocketmq.auth.authentication.model.User;
import org.apache.rocketmq.auth.authorization.manager.AuthorizationMetadataManager;
import org.apache.rocketmq.auth.config.AuthConfig;
import org.apache.rocketmq.common.AclConfig;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.auth.migration.v1.PlainPermissionManager;
import org.apache.rocketmq.auth.migration.v1.AclConfig;
import org.apache.rocketmq.auth.migration.v1.PlainAccessConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+5 -3
View File
@@ -21,7 +21,6 @@ java_library(
srcs = glob(["src/main/java/**/*.java"]),
visibility = ["//visibility:public"],
deps = [
"//acl",
"//auth",
"//client",
"//common",
@@ -52,6 +51,7 @@ java_library(
"@maven//:io_opentelemetry_opentelemetry_sdk_common",
"@maven//:io_opentelemetry_opentelemetry_sdk_metrics",
"@maven//:org_apache_commons_commons_lang3",
"@maven//:commons_codec_commons_codec",
"@maven//:org_lz4_lz4_java",
"@maven//:io_github_aliyunmq_rocketmq_slf4j_api",
"@maven//:io_github_aliyunmq_rocketmq_logback_classic",
@@ -66,7 +66,6 @@ java_library(
name = "tests",
srcs = glob(["src/test/java/**/*.java"]),
resources = [
"src/test/resources/META-INF/service/org.apache.rocketmq.acl.AccessValidator",
"src/test/resources/META-INF/service/org.apache.rocketmq.broker.transaction.AbstractTransactionalMessageCheckListener",
"src/test/resources/META-INF/service/org.apache.rocketmq.broker.transaction.TransactionalMessageService",
"src/test/resources/rmq.logback-test.xml",
@@ -75,7 +74,6 @@ java_library(
deps = [
":broker",
"//:test_deps",
"//acl",
"//auth",
"//client",
"//common",
@@ -84,15 +82,19 @@ java_library(
"//store",
"//tieredstore",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:org_slf4j_slf4j_api",
"@maven//:com_google_guava_guava",
"@maven//:io_netty_netty_all",
"@maven//:org_apache_commons_commons_lang3",
"@maven//:commons_codec_commons_codec",
"@maven//:commons_io_commons_io",
"@maven//:io_github_aliyunmq_rocketmq_slf4j_api",
"@maven//:org_powermock_powermock_core",
"@maven//:io_opentelemetry_opentelemetry_api",
"@maven//:com_googlecode_concurrentlinkedhashmap_concurrentlinkedhashmap_lru",
"@maven//:org_apache_rocketmq_rocketmq_rocksdb",
"@maven//:commons_collections_commons_collections",
"@maven//:org_junit_jupiter_junit_jupiter_api",
],
)
-4
View File
@@ -58,10 +58,6 @@
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-filter</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-acl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-auth</artifactId>
@@ -18,32 +18,6 @@ package org.apache.rocketmq.broker;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import java.net.InetSocketAddress;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.rocketmq.acl.AccessValidator;
import org.apache.rocketmq.acl.plain.PlainAccessValidator;
import org.apache.rocketmq.auth.authentication.factory.AuthenticationFactory;
import org.apache.rocketmq.auth.authentication.manager.AuthenticationMetadataManager;
import org.apache.rocketmq.auth.authorization.factory.AuthorizationFactory;
@@ -61,6 +35,15 @@ import org.apache.rocketmq.broker.client.net.Broker2Client;
import org.apache.rocketmq.broker.client.rebalance.RebalanceLockManager;
import org.apache.rocketmq.broker.coldctr.ColdDataCgCtrService;
import org.apache.rocketmq.broker.coldctr.ColdDataPullRequestHoldService;
import org.apache.rocketmq.broker.config.v1.RocksDBConsumerOffsetManager;
import org.apache.rocketmq.broker.config.v1.RocksDBLmqSubscriptionGroupManager;
import org.apache.rocketmq.broker.config.v1.RocksDBLmqTopicConfigManager;
import org.apache.rocketmq.broker.config.v1.RocksDBSubscriptionGroupManager;
import org.apache.rocketmq.broker.config.v1.RocksDBTopicConfigManager;
import org.apache.rocketmq.broker.config.v2.ConfigStorage;
import org.apache.rocketmq.broker.config.v2.ConsumerOffsetManagerV2;
import org.apache.rocketmq.broker.config.v2.SubscriptionGroupManagerV2;
import org.apache.rocketmq.broker.config.v2.TopicConfigManagerV2;
import org.apache.rocketmq.broker.controller.ReplicasManager;
import org.apache.rocketmq.broker.dledger.DLedgerRoleChangeHandler;
import org.apache.rocketmq.broker.failover.EscapeBridge;
@@ -77,7 +60,6 @@ import org.apache.rocketmq.broker.offset.BroadcastOffsetManager;
import org.apache.rocketmq.broker.offset.ConsumerOffsetManager;
import org.apache.rocketmq.broker.offset.ConsumerOrderInfoManager;
import org.apache.rocketmq.broker.offset.LmqConsumerOffsetManager;
import org.apache.rocketmq.broker.config.v1.RocksDBConsumerOffsetManager;
import org.apache.rocketmq.broker.out.BrokerOuterAPI;
import org.apache.rocketmq.broker.plugin.BrokerAttachedPlugin;
import org.apache.rocketmq.broker.pop.PopConsumerService;
@@ -101,16 +83,8 @@ import org.apache.rocketmq.broker.processor.SendMessageProcessor;
import org.apache.rocketmq.broker.schedule.ScheduleMessageService;
import org.apache.rocketmq.broker.slave.SlaveSynchronize;
import org.apache.rocketmq.broker.subscription.LmqSubscriptionGroupManager;
import org.apache.rocketmq.broker.config.v1.RocksDBLmqSubscriptionGroupManager;
import org.apache.rocketmq.broker.config.v1.RocksDBSubscriptionGroupManager;
import org.apache.rocketmq.broker.subscription.SubscriptionGroupManager;
import org.apache.rocketmq.broker.config.v2.ConsumerOffsetManagerV2;
import org.apache.rocketmq.broker.config.v2.SubscriptionGroupManagerV2;
import org.apache.rocketmq.broker.config.v2.TopicConfigManagerV2;
import org.apache.rocketmq.broker.config.v2.ConfigStorage;
import org.apache.rocketmq.broker.topic.LmqTopicConfigManager;
import org.apache.rocketmq.broker.config.v1.RocksDBLmqTopicConfigManager;
import org.apache.rocketmq.broker.config.v1.RocksDBTopicConfigManager;
import org.apache.rocketmq.broker.topic.TopicConfigManager;
import org.apache.rocketmq.broker.topic.TopicQueueMappingCleanService;
import org.apache.rocketmq.broker.topic.TopicQueueMappingManager;
@@ -154,7 +128,6 @@ import org.apache.rocketmq.remoting.pipeline.RequestPipeline;
import org.apache.rocketmq.remoting.protocol.BrokerSyncInfo;
import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.apache.rocketmq.remoting.protocol.NamespaceUtil;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.remoting.protocol.RequestCode;
import org.apache.rocketmq.remoting.protocol.RequestHeaderRegistry;
import org.apache.rocketmq.remoting.protocol.body.BrokerMemberGroup;
@@ -183,6 +156,30 @@ import org.apache.rocketmq.store.timer.TimerCheckpoint;
import org.apache.rocketmq.store.timer.TimerMessageStore;
import org.apache.rocketmq.store.timer.TimerMetrics;
import java.net.InetSocketAddress;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class BrokerController {
protected static final Logger LOG = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
private static final Logger LOG_PROTECTION = LoggerFactory.getLogger(LoggerName.PROTECTION_LOGGER_NAME);
@@ -281,7 +278,6 @@ public class BrokerController {
protected TransactionalMessageCheckService transactionalMessageCheckService;
protected TransactionalMessageService transactionalMessageService;
protected AbstractTransactionalMessageCheckListener transactionalMessageCheckListener;
protected Map<Class, AccessValidator> accessValidatorMap = new HashMap<>();
protected volatile boolean shutdown = false;
protected ShutdownHook shutdownHook;
private volatile boolean isScheduleServiceStart = false;
@@ -917,8 +913,6 @@ public class BrokerController {
initialTransaction();
initialAcl();
initialRpcHooks();
initialRequestPipeline();
@@ -1052,37 +1046,6 @@ public class BrokerController {
}
private void initialAcl() {
if (!this.brokerConfig.isAclEnable()) {
LOG.info("The broker does not enable acl");
return;
}
List<AccessValidator> accessValidators = ServiceProvider.load(AccessValidator.class);
if (accessValidators.isEmpty()) {
LOG.info("ServiceProvider loaded no AccessValidator, using default org.apache.rocketmq.acl.plain.PlainAccessValidator");
accessValidators.add(new PlainAccessValidator());
}
for (AccessValidator accessValidator : accessValidators) {
final AccessValidator validator = accessValidator;
accessValidatorMap.put(validator.getClass(), validator);
this.registerServerRPCHook(new RPCHook() {
@Override
public void doBeforeRequest(String remoteAddr, RemotingCommand request) {
//Do not catch the exception
validator.validate(validator.parse(request, remoteAddr));
}
@Override
public void doAfterResponse(String remoteAddr, RemotingCommand request, RemotingCommand response) {
}
});
}
}
private void initialRpcHooks() {
List<RPCHook> rpcHooks = ServiceProvider.load(RPCHook.class);
@@ -2510,10 +2473,6 @@ public class BrokerController {
}
public Map<Class, AccessValidator> getAccessValidatorMap() {
return accessValidatorMap;
}
public ExecutorService getSendMessageExecutor() {
return sendMessageExecutor;
}
@@ -24,9 +24,6 @@ import io.netty.channel.ChannelHandlerContext;
import io.opentelemetry.api.common.Attributes;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.acl.AccessValidator;
import org.apache.rocketmq.acl.common.AclException;
import org.apache.rocketmq.acl.plain.PlainAccessValidator;
import org.apache.rocketmq.auth.authentication.enums.UserType;
import org.apache.rocketmq.auth.authentication.exception.AuthenticationException;
import org.apache.rocketmq.auth.authentication.model.Subject;
@@ -59,7 +56,6 @@ import org.apache.rocketmq.common.LockCallback;
import org.apache.rocketmq.common.MQVersion;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.common.TopicAttributes;
import org.apache.rocketmq.common.TopicConfig;
import org.apache.rocketmq.common.UnlockCallback;
@@ -87,7 +83,6 @@ import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
import org.apache.rocketmq.remoting.netty.NettyRemotingAbstract;
import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
import org.apache.rocketmq.remoting.protocol.LanguageCode;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -131,11 +126,9 @@ import org.apache.rocketmq.remoting.protocol.body.UserInfo;
import org.apache.rocketmq.remoting.protocol.header.CheckRocksdbCqWriteProgressRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CloneGroupOffsetRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.ConsumeMessageDirectlyResultRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateAccessConfigRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateAclRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateTopicRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateUserRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.DeleteAccessConfigRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.DeleteAclRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.DeleteSubscriptionGroupRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.DeleteTopicRequestHeader;
@@ -146,7 +139,6 @@ import org.apache.rocketmq.remoting.protocol.header.ExportRocksDBConfigToJsonReq
import org.apache.rocketmq.remoting.protocol.header.GetAclRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.GetAllProducerInfoRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.GetAllTopicConfigResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.GetBrokerAclConfigResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.GetBrokerConfigResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.GetConsumeStatsInBrokerHeader;
import org.apache.rocketmq.remoting.protocol.header.GetConsumeStatsRequestHeader;
@@ -180,7 +172,6 @@ import org.apache.rocketmq.remoting.protocol.header.ResumeCheckHalfMessageReques
import org.apache.rocketmq.remoting.protocol.header.SearchOffsetRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.SearchOffsetResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.UpdateAclRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UpdateGlobalWhiteAddrsConfigRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UpdateGroupForbiddenRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UpdateUserRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.ViewBrokerStatsDataRequestHeader;
@@ -368,14 +359,6 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
return this.updateAndGetGroupForbidden(ctx, request);
case RequestCode.GET_SUBSCRIPTIONGROUP_CONFIG:
return this.getSubscriptionGroup(ctx, request);
case RequestCode.UPDATE_AND_CREATE_ACL_CONFIG:
return updateAndCreateAccessConfig(ctx, request);
case RequestCode.DELETE_ACL_CONFIG:
return deleteAccessConfig(ctx, request);
case RequestCode.GET_BROKER_CLUSTER_ACL_INFO:
return getBrokerAclConfigVersion(ctx, request);
case RequestCode.UPDATE_GLOBAL_WHITE_ADDRS_CONFIG:
return updateGlobalWhiteAddrsConfig(ctx, request);
case RequestCode.RESUME_CHECK_HALF_MESSAGE:
return resumeCheckHalfMessage(ctx, request);
case RequestCode.GET_TOPIC_CONFIG:
@@ -828,148 +811,6 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
this.brokerController.getMessageStore().getTimerMessageStore().getTimerMetrics().removeTimingCount(topic);
}
private synchronized RemotingCommand updateAndCreateAccessConfig(ChannelHandlerContext ctx, RemotingCommand request) {
final RemotingCommand response = RemotingCommand.createResponseCommand(null);
try {
ensureAclEnabled();
final CreateAccessConfigRequestHeader requestHeader = request.decodeCommandCustomHeader(CreateAccessConfigRequestHeader.class);
AccessValidator accessValidator = this.brokerController.getAccessValidatorMap().get(PlainAccessValidator.class);
if (accessValidator.updateAccessConfig(createAccessConfig(requestHeader))) {
response.setCode(ResponseCode.SUCCESS);
response.setOpaque(request.getOpaque());
response.markResponseType();
response.setRemark(null);
NettyRemotingAbstract.writeResponse(ctx.channel(), request, response);
} else {
String errorMsg = "The accessKey[" + requestHeader.getAccessKey() + "] corresponding to accessConfig has been updated failed.";
LOGGER.warn(errorMsg);
response.setCode(ResponseCode.UPDATE_AND_CREATE_ACL_CONFIG_FAILED);
response.setRemark(errorMsg);
return response;
}
} catch (Exception e) {
LOGGER.error("Failed to generate a proper update accessValidator response", e);
response.setCode(ResponseCode.UPDATE_AND_CREATE_ACL_CONFIG_FAILED);
response.setRemark(e.getMessage());
return response;
}
return null;
}
private PlainAccessConfig createAccessConfig(final CreateAccessConfigRequestHeader requestHeader) {
PlainAccessConfig accessConfig = new PlainAccessConfig();
accessConfig.setAccessKey(requestHeader.getAccessKey());
accessConfig.setSecretKey(requestHeader.getSecretKey());
accessConfig.setWhiteRemoteAddress(requestHeader.getWhiteRemoteAddress());
accessConfig.setDefaultTopicPerm(requestHeader.getDefaultTopicPerm());
accessConfig.setDefaultGroupPerm(requestHeader.getDefaultGroupPerm());
accessConfig.setTopicPerms(UtilAll.split(requestHeader.getTopicPerms(), ","));
accessConfig.setGroupPerms(UtilAll.split(requestHeader.getGroupPerms(), ","));
accessConfig.setAdmin(requestHeader.isAdmin());
return accessConfig;
}
private synchronized RemotingCommand deleteAccessConfig(ChannelHandlerContext ctx, RemotingCommand request) {
final RemotingCommand response = RemotingCommand.createResponseCommand(null);
LOGGER.info("DeleteAccessConfig called by {}", RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
try {
ensureAclEnabled();
final DeleteAccessConfigRequestHeader requestHeader = request.decodeCommandCustomHeader(DeleteAccessConfigRequestHeader.class);
String accessKey = requestHeader.getAccessKey();
AccessValidator accessValidator = this.brokerController.getAccessValidatorMap().get(PlainAccessValidator.class);
if (accessValidator.deleteAccessConfig(accessKey)) {
response.setCode(ResponseCode.SUCCESS);
response.setOpaque(request.getOpaque());
response.markResponseType();
response.setRemark(null);
NettyRemotingAbstract.writeResponse(ctx.channel(), request, response);
} else {
String errorMsg = "The accessKey[" + requestHeader.getAccessKey() + "] corresponding to accessConfig has been deleted failed.";
LOGGER.warn(errorMsg);
response.setCode(ResponseCode.DELETE_ACL_CONFIG_FAILED);
response.setRemark(errorMsg);
return response;
}
} catch (Exception e) {
LOGGER.error("Failed to generate a proper delete accessValidator response", e);
response.setCode(ResponseCode.DELETE_ACL_CONFIG_FAILED);
response.setRemark(e.getMessage());
return response;
}
return null;
}
private synchronized RemotingCommand updateGlobalWhiteAddrsConfig(ChannelHandlerContext ctx, RemotingCommand request) {
final RemotingCommand response = RemotingCommand.createResponseCommand(null);
try {
ensureAclEnabled();
final UpdateGlobalWhiteAddrsConfigRequestHeader requestHeader = request.decodeCommandCustomHeader(UpdateGlobalWhiteAddrsConfigRequestHeader.class);
AccessValidator accessValidator = this.brokerController.getAccessValidatorMap().get(PlainAccessValidator.class);
if (accessValidator.updateGlobalWhiteAddrsConfig(UtilAll.split(requestHeader.getGlobalWhiteAddrs(), ","),
requestHeader.getAclFileFullPath())) {
response.setCode(ResponseCode.SUCCESS);
response.setOpaque(request.getOpaque());
response.markResponseType();
response.setRemark(null);
NettyRemotingAbstract.writeResponse(ctx.channel(), request, response);
} else {
String errorMsg = "The globalWhiteAddresses[" + requestHeader.getGlobalWhiteAddrs() + "] has been updated failed.";
LOGGER.warn(errorMsg);
response.setCode(ResponseCode.UPDATE_GLOBAL_WHITE_ADDRS_CONFIG_FAILED);
response.setRemark(errorMsg);
return response;
}
} catch (Exception e) {
LOGGER.error("Failed to generate a proper update globalWhiteAddresses response", e);
response.setCode(ResponseCode.UPDATE_GLOBAL_WHITE_ADDRS_CONFIG_FAILED);
response.setRemark(e.getMessage());
return response;
}
return null;
}
private RemotingCommand getBrokerAclConfigVersion(ChannelHandlerContext ctx, RemotingCommand request) {
final RemotingCommand response = RemotingCommand.createResponseCommand(GetBrokerAclConfigResponseHeader.class);
try {
ensureAclEnabled();
final GetBrokerAclConfigResponseHeader responseHeader = (GetBrokerAclConfigResponseHeader) response.readCustomHeader();
AccessValidator accessValidator = this.brokerController.getAccessValidatorMap().get(PlainAccessValidator.class);
responseHeader.setVersion(accessValidator.getAclConfigVersion());
responseHeader.setBrokerAddr(this.brokerController.getBrokerAddr());
responseHeader.setBrokerName(this.brokerController.getBrokerConfig().getBrokerName());
responseHeader.setClusterName(this.brokerController.getBrokerConfig().getBrokerClusterName());
response.setCode(ResponseCode.SUCCESS);
response.setRemark(null);
return response;
} catch (Exception e) {
LOGGER.error("Failed to generate a proper getBrokerAclConfigVersion response", e);
response.setCode(ResponseCode.SYSTEM_ERROR);
response.setRemark(e.getMessage());
return response;
}
}
private void ensureAclEnabled() {
if (!brokerController.getBrokerConfig().isAclEnable()) {
throw new AclException("The broker does not enable acl.");
}
}
private RemotingCommand getUnknownCmdResponse(ChannelHandlerContext ctx, RemotingCommand request) {
String error = " request type " + request.getCode() + " not supported";
final RemotingCommand response =
@@ -17,7 +17,6 @@
package org.apache.rocketmq.broker.util;
import org.apache.rocketmq.acl.AccessValidator;
import org.apache.rocketmq.broker.transaction.AbstractTransactionalMessageCheckListener;
import org.apache.rocketmq.broker.transaction.TransactionalMessageService;
import org.apache.rocketmq.common.utils.ServiceProvider;
@@ -25,8 +24,6 @@ import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
public class ServiceProviderTest {
@Test
@@ -41,10 +38,4 @@ public class ServiceProviderTest {
AbstractTransactionalMessageCheckListener.class);
assertThat(listener).isNotNull();
}
@Test
public void loadAccessValidatorTest() {
List<AccessValidator> accessValidators = ServiceProvider.load(AccessValidator.class);
assertThat(accessValidators).isNotNull();
}
}
@@ -1 +0,0 @@
org.apache.rocketmq.acl.plain.PlainAccessValidator
+5 -1
View File
@@ -28,12 +28,15 @@ java_library(
"@maven//:com_github_luben_zstd_jni",
"@maven//:org_lz4_lz4_java",
"@maven//:com_alibaba_fastjson",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:io_netty_netty_all",
"@maven//:io_opentracing_opentracing_api",
"@maven//:commons_collections_commons_collections",
"@maven//:io_github_aliyunmq_rocketmq_slf4j_api",
"@maven//:io_github_aliyunmq_rocketmq_logback_classic",
"@maven//:com_google_guava_guava",
"@maven//:commons_codec_commons_codec",
"@maven//:org_yaml_snakeyaml",
],
)
@@ -52,8 +55,9 @@ java_library(
"@maven//:io_opentracing_opentracing_mock",
"@maven//:org_awaitility_awaitility",
"@maven//:org_mockito_mockito_junit_jupiter",
"@maven//:com_alibaba_fastjson2_fastjson2",
],
resources = glob(["src/test/resources/certs/*.pem"]) + glob(["src/test/resources/certs/*.key"])
resources = glob(["src/test/resources/certs/*.pem"]) + glob(["src/test/resources/certs/*.key"]) + glob(["src/test/resources/**/*.yml"])
)
GenTestRules(
+4
View File
@@ -62,5 +62,9 @@
<groupId>io.github.aliyunmq</groupId>
<artifactId>rocketmq-logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
</dependencies>
</project>
@@ -16,15 +16,12 @@
*/
package org.apache.rocketmq.acl.common;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import static org.apache.rocketmq.acl.common.SessionCredentials.ACCESS_KEY;
import static org.apache.rocketmq.acl.common.SessionCredentials.SECURITY_TOKEN;
import static org.apache.rocketmq.acl.common.SessionCredentials.SIGNATURE;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
public class AclClientRPCHook implements RPCHook {
private final SessionCredentials sessionCredentials;
@@ -36,14 +33,14 @@ public class AclClientRPCHook implements RPCHook {
@Override
public void doBeforeRequest(String remoteAddr, RemotingCommand request) {
// Add AccessKey and SecurityToken into signature calculating.
request.addExtField(ACCESS_KEY, sessionCredentials.getAccessKey());
request.addExtField(SessionCredentials.ACCESS_KEY, sessionCredentials.getAccessKey());
// The SecurityToken value is unnecessary,user can choose this one.
if (sessionCredentials.getSecurityToken() != null) {
request.addExtField(SECURITY_TOKEN, sessionCredentials.getSecurityToken());
request.addExtField(SessionCredentials.SECURITY_TOKEN, sessionCredentials.getSecurityToken());
}
byte[] total = AclUtils.combineRequestContent(request, parseRequestContent(request));
String signature = AclUtils.calSignature(total, sessionCredentials.getSecretKey());
request.addExtField(SIGNATURE, signature);
request.addExtField(SessionCredentials.SIGNATURE, signature);
}
@Override
@@ -14,9 +14,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.plain;
package org.apache.rocketmq.acl.common;
public interface RemoteAddressStrategy {
public class AclConstants {
boolean match(PlainAccessResource plainAccessResource);
public static final String CONFIG_ACCESS_KEY = "accessKey";
public static final String CONFIG_SECRET_KEY = "secretKey";
public static final String PUB = "PUB";
public static final String SUB = "SUB";
public static final String DENY = "DENY";
public static final String PUB_SUB = "PUB|SUB";
public static final String SUB_PUB = "SUB|PUB";
}
@@ -16,15 +16,16 @@
*/
package org.apache.rocketmq.acl.common;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class AclSigner {
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
public static final SigningAlgorithm DEFAULT_ALGORITHM = SigningAlgorithm.HmacSHA1;
@@ -16,13 +16,6 @@
*/
package org.apache.rocketmq.acl.common;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Map;
import java.util.SortedMap;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.common.constant.LoggerName;
@@ -32,6 +25,12 @@ import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.yaml.snakeyaml.Yaml;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Map;
import java.util.SortedMap;
import static org.apache.rocketmq.acl.common.SessionCredentials.CHARSET;
public class AclUtils {
@@ -248,18 +247,6 @@ public class AclUtils {
}
}
public static boolean writeDataObject(String path, Object dataMap) {
Yaml yaml = new Yaml();
try (PrintWriter pw = new PrintWriter(path, "UTF-8")) {
String dumpAsMap = yaml.dumpAsMap(dataMap);
pw.print(dumpAsMap);
pw.flush();
} catch (Exception e) {
throw new AclException(e.getMessage(), e);
}
return true;
}
public static RPCHook getAclRPCHook(String fileName) {
JSONObject yamlDataObject;
try {
@@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.common;
public class Permission {
public static final byte DENY = 1;
public static final byte ANY = 1 << 1;
public static final byte PUB = 1 << 2;
public static final byte SUB = 1 << 3;
public static byte parsePermFromString(String permString) {
if (permString == null) {
return Permission.DENY;
}
switch (permString.trim()) {
case AclConstants.PUB:
return Permission.PUB;
case AclConstants.SUB:
return Permission.SUB;
case AclConstants.PUB_SUB:
case AclConstants.SUB_PUB:
return Permission.PUB | Permission.SUB;
case AclConstants.DENY:
return Permission.DENY;
default:
return Permission.DENY;
}
}
}
@@ -16,12 +16,13 @@
*/
package org.apache.rocketmq.acl.common;
import org.apache.rocketmq.common.MixAll;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import org.apache.rocketmq.common.MixAll;
public class SessionCredentials {
public static final Charset CHARSET = StandardCharsets.UTF_8;
@@ -17,19 +17,6 @@
package org.apache.rocketmq.client.impl;
import com.alibaba.fastjson.JSON;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.ClientConfig;
@@ -61,7 +48,6 @@ import org.apache.rocketmq.common.MQVersion;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.ObjectCreator;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.common.TopicConfig;
import org.apache.rocketmq.common.UtilAll;
import org.apache.rocketmq.common.attribute.AttributeParser;
@@ -99,7 +85,6 @@ import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException;
import org.apache.rocketmq.remoting.netty.NettyClientConfig;
import org.apache.rocketmq.remoting.netty.NettyRemotingClient;
import org.apache.rocketmq.remoting.netty.ResponseFuture;
import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.apache.rocketmq.remoting.protocol.LanguageCode;
import org.apache.rocketmq.remoting.protocol.NamespaceUtil;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -115,7 +100,6 @@ import org.apache.rocketmq.remoting.protocol.body.BrokerMemberGroup;
import org.apache.rocketmq.remoting.protocol.body.BrokerReplicasInfo;
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
import org.apache.rocketmq.remoting.protocol.body.CheckClientRequestBody;
import org.apache.rocketmq.remoting.protocol.body.ClusterAclVersionInfo;
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
import org.apache.rocketmq.remoting.protocol.body.ConsumeStatsList;
@@ -154,12 +138,10 @@ import org.apache.rocketmq.remoting.protocol.header.CheckRocksdbCqWriteProgressR
import org.apache.rocketmq.remoting.protocol.header.CloneGroupOffsetRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.ConsumeMessageDirectlyResultRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.ConsumerSendMsgBackRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateAccessConfigRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateAclRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateTopicListRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateTopicRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.CreateUserRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.DeleteAccessConfigRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.DeleteAclRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.DeleteSubscriptionGroupRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.DeleteTopicRequestHeader;
@@ -169,7 +151,6 @@ import org.apache.rocketmq.remoting.protocol.header.ExportRocksDBConfigToJsonReq
import org.apache.rocketmq.remoting.protocol.header.ExtraInfoUtil;
import org.apache.rocketmq.remoting.protocol.header.GetAclRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.GetAllProducerInfoRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.GetBrokerAclConfigResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.GetConsumeStatsInBrokerHeader;
import org.apache.rocketmq.remoting.protocol.header.GetConsumeStatsRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.GetConsumerConnectionListRequestHeader;
@@ -221,7 +202,6 @@ import org.apache.rocketmq.remoting.protocol.header.UnlockBatchMqRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UnregisterClientRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UpdateAclRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UpdateConsumerOffsetRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UpdateGlobalWhiteAddrsConfigRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UpdateGroupForbiddenRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.UpdateUserRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.ViewBrokerStatsDataRequestHeader;
@@ -252,6 +232,20 @@ import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfi
import org.apache.rocketmq.remoting.rpchook.DynamicalExtFieldRPCHook;
import org.apache.rocketmq.remoting.rpchook.StreamTypeRPCHook;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import static org.apache.rocketmq.remoting.protocol.RemotingSysResponseCode.SUCCESS;
public class MQClientAPIImpl implements NameServerUpdateCallback, StartAndShutdown {
@@ -498,112 +492,6 @@ public class MQClientAPIImpl implements NameServerUpdateCallback, StartAndShutdo
throw new MQClientException(response.getCode(), response.getRemark());
}
public void createPlainAccessConfig(final String addr, final PlainAccessConfig plainAccessConfig,
final long timeoutMillis)
throws RemotingException, InterruptedException, MQClientException {
CreateAccessConfigRequestHeader requestHeader = new CreateAccessConfigRequestHeader();
requestHeader.setAccessKey(plainAccessConfig.getAccessKey());
requestHeader.setSecretKey(plainAccessConfig.getSecretKey());
requestHeader.setAdmin(plainAccessConfig.isAdmin());
requestHeader.setDefaultGroupPerm(plainAccessConfig.getDefaultGroupPerm());
requestHeader.setDefaultTopicPerm(plainAccessConfig.getDefaultTopicPerm());
requestHeader.setWhiteRemoteAddress(plainAccessConfig.getWhiteRemoteAddress());
requestHeader.setTopicPerms(UtilAll.join(plainAccessConfig.getTopicPerms(), ","));
requestHeader.setGroupPerms(UtilAll.join(plainAccessConfig.getGroupPerms(), ","));
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_AND_CREATE_ACL_CONFIG, requestHeader);
RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr),
request, timeoutMillis);
assert response != null;
switch (response.getCode()) {
case ResponseCode.SUCCESS: {
return;
}
default:
break;
}
throw new MQClientException(response.getCode(), response.getRemark());
}
public void deleteAccessConfig(final String addr, final String accessKey, final long timeoutMillis)
throws RemotingException, InterruptedException, MQClientException {
DeleteAccessConfigRequestHeader requestHeader = new DeleteAccessConfigRequestHeader();
requestHeader.setAccessKey(accessKey);
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.DELETE_ACL_CONFIG, requestHeader);
RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr),
request, timeoutMillis);
assert response != null;
switch (response.getCode()) {
case ResponseCode.SUCCESS: {
return;
}
default:
break;
}
throw new MQClientException(response.getCode(), response.getRemark());
}
public void updateGlobalWhiteAddrsConfig(final String addr, final String globalWhiteAddrs, String aclFileFullPath,
final long timeoutMillis)
throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
UpdateGlobalWhiteAddrsConfigRequestHeader requestHeader = new UpdateGlobalWhiteAddrsConfigRequestHeader();
requestHeader.setGlobalWhiteAddrs(globalWhiteAddrs);
requestHeader.setAclFileFullPath(aclFileFullPath);
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.UPDATE_GLOBAL_WHITE_ADDRS_CONFIG, requestHeader);
RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr),
request, timeoutMillis);
assert response != null;
switch (response.getCode()) {
case ResponseCode.SUCCESS: {
return;
}
default:
break;
}
throw new MQClientException(response.getCode(), response.getRemark());
}
public ClusterAclVersionInfo getBrokerClusterAclInfo(final String addr,
final long timeoutMillis) throws RemotingCommandException, InterruptedException, RemotingTimeoutException,
RemotingSendRequestException, RemotingConnectException, MQBrokerException {
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_BROKER_CLUSTER_ACL_INFO, null);
RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr), request, timeoutMillis);
assert response != null;
switch (response.getCode()) {
case ResponseCode.SUCCESS: {
GetBrokerAclConfigResponseHeader responseHeader =
(GetBrokerAclConfigResponseHeader) response.decodeCommandCustomHeader(GetBrokerAclConfigResponseHeader.class);
ClusterAclVersionInfo clusterAclVersionInfo = new ClusterAclVersionInfo();
clusterAclVersionInfo.setClusterName(responseHeader.getClusterName());
clusterAclVersionInfo.setBrokerName(responseHeader.getBrokerName());
clusterAclVersionInfo.setBrokerAddr(responseHeader.getBrokerAddr());
clusterAclVersionInfo.setAclConfigDataVersion(DataVersion.fromJson(responseHeader.getVersion(), DataVersion.class));
HashMap<String, Object> dataVersionMap = JSON.parseObject(responseHeader.getAllAclFileVersion(), HashMap.class);
Map<String, DataVersion> allAclConfigDataVersion = new HashMap<>(dataVersionMap.size(), 1);
for (Map.Entry<String, Object> entry : dataVersionMap.entrySet()) {
allAclConfigDataVersion.put(entry.getKey(), DataVersion.fromJson(JSON.toJSONString(entry.getValue()), DataVersion.class));
}
clusterAclVersionInfo.setAllAclConfigDataVersion(allAclConfigDataVersion);
return clusterAclVersionInfo;
}
default:
break;
}
throw new MQBrokerException(response.getCode(), response.getRemark(), addr);
}
public SendResult sendMessage(
final String addr,
final String brokerName,
@@ -17,10 +17,6 @@
package org.apache.rocketmq.acl.common;
import java.lang.reflect.Field;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.remoting.CommandCustomHeader;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
@@ -29,6 +25,11 @@ import org.apache.rocketmq.remoting.protocol.RequestType;
import org.apache.rocketmq.remoting.protocol.header.PullMessageRequestHeader;
import org.junit.Test;
import java.lang.reflect.Field;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import static org.apache.rocketmq.acl.common.SessionCredentials.ACCESS_KEY;
import static org.apache.rocketmq.acl.common.SessionCredentials.SECURITY_TOKEN;
import static org.assertj.core.api.Assertions.assertThat;
@@ -18,8 +18,6 @@ package org.apache.rocketmq.acl.common;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.acl.plain.PlainAccessData;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.remoting.RPCHook;
import org.junit.Assert;
import org.junit.Test;
@@ -31,7 +29,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
@@ -206,16 +203,6 @@ public class AclUtilsTest {
Assert.assertEquals(AclUtils.expandIP("5::7:6", 6), "0005:0000:0000:0000:0007:0006");
}
@SuppressWarnings("unchecked")
@Test
public void testGetYamlDataObject() throws IOException {
try (InputStream is = AclUtilsTest.class.getClassLoader().getResourceAsStream("conf/plain_acl_correct.yml")) {
Map<String, Object> map = AclUtils.getYamlDataObject(is, Map.class);
Assert.assertNotNull(map);
Assert.assertFalse(map.isEmpty());
}
}
private static String randomTmpFile() {
String tmpFileName = System.getProperty("java.io.tmpdir");
// https://rationalpi.wordpress.com/2007/01/26/javaiotmpdir-inconsitency/
@@ -226,67 +213,6 @@ public class AclUtilsTest {
return tmpFileName;
}
@Test
public void writeDataObject2YamlFileTest() throws IOException {
String targetFileName = randomTmpFile();
File transport = new File(targetFileName);
Assert.assertTrue(transport.createNewFile());
transport.deleteOnExit();
PlainAccessData aclYamlMap = new PlainAccessData();
// For globalWhiteRemoteAddrs element in acl yaml config file
List<String> globalWhiteRemoteAddrs = new ArrayList<>();
globalWhiteRemoteAddrs.add("10.10.103.*");
globalWhiteRemoteAddrs.add("192.168.0.*");
aclYamlMap.setGlobalWhiteRemoteAddresses(globalWhiteRemoteAddrs);
// For accounts element in acl yaml config file
List<PlainAccessConfig> accounts = new ArrayList<>();
PlainAccessConfig accountsMap = new PlainAccessConfig() {
{
setAccessKey("RocketMQ");
setSecretKey("12345678");
setWhiteRemoteAddress("whiteRemoteAddress");
setAdmin(true);
}
};
accounts.add(accountsMap);
aclYamlMap.setAccounts(accounts);
Assert.assertTrue(AclUtils.writeDataObject(targetFileName, aclYamlMap));
}
@Test
public void updateExistedYamlFileTest() throws IOException {
String targetFileName = randomTmpFile();
File transport = new File(targetFileName);
Assert.assertTrue(transport.createNewFile());
transport.deleteOnExit();
PlainAccessData aclYamlMap = new PlainAccessData();
// For globalWhiteRemoteAddrs element in acl yaml config file
List<String> globalWhiteRemoteAddrs = new ArrayList<>();
globalWhiteRemoteAddrs.add("10.10.103.*");
globalWhiteRemoteAddrs.add("192.168.0.*");
aclYamlMap.setGlobalWhiteRemoteAddresses(globalWhiteRemoteAddrs);
// Write file to yaml file
AclUtils.writeDataObject(targetFileName, aclYamlMap);
PlainAccessData updatedMap = AclUtils.getYamlDataObject(targetFileName, PlainAccessData.class);
List<String> globalWhiteRemoteAddrList = updatedMap.getGlobalWhiteRemoteAddresses();
globalWhiteRemoteAddrList.clear();
globalWhiteRemoteAddrList.add("192.168.1.2");
// Update file and flush to yaml file
AclUtils.writeDataObject(targetFileName, updatedMap);
PlainAccessData readableMap = AclUtils.getYamlDataObject(targetFileName, PlainAccessData.class);
List<String> updatedGlobalWhiteRemoteAddrs = readableMap.getGlobalWhiteRemoteAddresses();
Assert.assertEquals("192.168.1.2", updatedGlobalWhiteRemoteAddrs.get(0));
}
@Test
public void getYamlDataIgnoreFileNotFoundExceptionTest() {
@@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.acl.common;
import org.junit.Assert;
import org.junit.Test;
public class PermissionTest {
@Test
public void fromStringGetPermissionTest() {
byte perm = Permission.parsePermFromString("PUB");
Assert.assertEquals(perm, Permission.PUB);
perm = Permission.parsePermFromString("SUB");
Assert.assertEquals(perm, Permission.SUB);
perm = Permission.parsePermFromString("PUB|SUB");
Assert.assertEquals(perm, Permission.PUB | Permission.SUB);
perm = Permission.parsePermFromString("SUB|PUB");
Assert.assertEquals(perm, Permission.PUB | Permission.SUB);
perm = Permission.parsePermFromString("DENY");
Assert.assertEquals(perm, Permission.DENY);
perm = Permission.parsePermFromString("1");
Assert.assertEquals(perm, Permission.DENY);
perm = Permission.parsePermFromString(null);
Assert.assertEquals(perm, Permission.DENY);
}
@Test
public void AclExceptionTest() {
AclException aclException = new AclException("CAL_SIGNATURE_FAILED",10015);
AclException aclExceptionWithMessage = new AclException("CAL_SIGNATURE_FAILED",10015,"CAL_SIGNATURE_FAILED Exception");
Assert.assertEquals(aclException.getCode(),10015);
Assert.assertEquals(aclExceptionWithMessage.getStatus(),"CAL_SIGNATURE_FAILED");
aclException.setCode(10016);
Assert.assertEquals(aclException.getCode(),10016);
aclException.setStatus("netAddress examine scope Exception netAddress");
Assert.assertEquals(aclException.getStatus(),"netAddress examine scope Exception netAddress");
}
}
@@ -37,7 +37,6 @@ import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.ObjectCreator;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.PlainAccessConfig;
import org.apache.rocketmq.common.TopicConfig;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.Message;
@@ -74,7 +73,6 @@ import org.apache.rocketmq.remoting.protocol.body.BrokerMemberGroup;
import org.apache.rocketmq.remoting.protocol.body.BrokerReplicasInfo;
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsData;
import org.apache.rocketmq.remoting.protocol.body.BrokerStatsItem;
import org.apache.rocketmq.remoting.protocol.body.ClusterAclVersionInfo;
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
import org.apache.rocketmq.remoting.protocol.body.Connection;
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
@@ -108,7 +106,6 @@ import org.apache.rocketmq.remoting.protocol.header.ChangeInvisibleTimeRequestHe
import org.apache.rocketmq.remoting.protocol.header.ChangeInvisibleTimeResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.EndTransactionRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.ExtraInfoUtil;
import org.apache.rocketmq.remoting.protocol.header.GetBrokerAclConfigResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.GetConsumerListByGroupResponseBody;
import org.apache.rocketmq.remoting.protocol.header.GetConsumerListByGroupResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.GetEarliestMsgStoretimeResponseHeader;
@@ -364,68 +361,6 @@ public class MQClientAPIImplTest {
}, null, null, 0, sendMessageContext, defaultMQProducerImpl);
}
@Test
public void testCreatePlainAccessConfig_Success() throws InterruptedException, RemotingException {
doAnswer(mock -> {
RemotingCommand request = mock.getArgument(1);
return createSuccessResponse4UpdateAclConfig(request);
}).when(remotingClient).invokeSync(anyString(), any(RemotingCommand.class), anyLong());
PlainAccessConfig config = createUpdateAclConfig();
try {
mqClientAPI.createPlainAccessConfig(brokerAddr, config, 3 * 1000);
} catch (MQClientException ignored) {
}
}
@Test
public void testCreatePlainAccessConfig_Exception() throws InterruptedException, RemotingException {
doAnswer(mock -> {
RemotingCommand request = mock.getArgument(1);
return createErrorResponse4UpdateAclConfig(request);
}).when(remotingClient).invokeSync(anyString(), any(RemotingCommand.class), anyLong());
PlainAccessConfig config = createUpdateAclConfig();
try {
mqClientAPI.createPlainAccessConfig(brokerAddr, config, 3 * 1000);
} catch (MQClientException ex) {
assertThat(ex.getResponseCode()).isEqualTo(209);
assertThat(ex.getErrorMessage()).isEqualTo("corresponding to accessConfig has been updated failed");
}
}
@Test
public void testDeleteAccessConfig_Success() throws InterruptedException, RemotingException {
doAnswer(mock -> {
RemotingCommand request = mock.getArgument(1);
return createSuccessResponse4DeleteAclConfig(request);
}).when(remotingClient).invokeSync(anyString(), any(RemotingCommand.class), anyLong());
String accessKey = "1234567";
try {
mqClientAPI.deleteAccessConfig(brokerAddr, accessKey, 3 * 1000);
} catch (MQClientException ignored) {
}
}
@Test
public void testDeleteAccessConfig_Exception() throws InterruptedException, RemotingException {
doAnswer(mock -> {
RemotingCommand request = mock.getArgument(1);
return createErrorResponse4DeleteAclConfig(request);
}).when(remotingClient).invokeSync(anyString(), any(RemotingCommand.class), anyLong());
try {
mqClientAPI.deleteAccessConfig(brokerAddr, "11111", 3 * 1000);
} catch (MQClientException ex) {
assertThat(ex.getResponseCode()).isEqualTo(210);
assertThat(ex.getErrorMessage()).isEqualTo("corresponding to accessConfig has been deleted failed");
}
}
@Test
public void testResumeCheckHalfMessage_WithException() throws RemotingException, InterruptedException {
doAnswer(mock -> {
@@ -1026,35 +961,6 @@ public class MQClientAPIImplTest {
return response;
}
private RemotingCommand createErrorResponse4UpdateAclConfig(RemotingCommand request) {
RemotingCommand response = RemotingCommand.createResponseCommand(null);
response.setCode(ResponseCode.UPDATE_AND_CREATE_ACL_CONFIG_FAILED);
response.setOpaque(request.getOpaque());
response.markResponseType();
response.setRemark("corresponding to accessConfig has been updated failed");
return response;
}
private RemotingCommand createErrorResponse4DeleteAclConfig(RemotingCommand request) {
RemotingCommand response = RemotingCommand.createResponseCommand(null);
response.setCode(ResponseCode.DELETE_ACL_CONFIG_FAILED);
response.setOpaque(request.getOpaque());
response.markResponseType();
response.setRemark("corresponding to accessConfig has been deleted failed");
return response;
}
private PlainAccessConfig createUpdateAclConfig() {
PlainAccessConfig config = new PlainAccessConfig();
config.setAccessKey("Rocketmq111");
config.setSecretKey("123456789");
config.setAdmin(true);
config.setWhiteRemoteAddress("127.0.0.1");
config.setDefaultTopicPerm("DENY");
config.setDefaultGroupPerm("SUB");
return config;
}
private SendMessageRequestHeader createSendMessageRequestHeader() {
SendMessageRequestHeader requestHeader = new SendMessageRequestHeader();
requestHeader.setBornTimestamp(System.currentTimeMillis());
@@ -1117,29 +1023,6 @@ public class MQClientAPIImplTest {
assertEquals(defaultNsAddr, mqClientAPI.onNameServerAddressChange(defaultNsAddr));
}
@Test(expected = AssertionError.class)
public void testUpdateGlobalWhiteAddrsConfig() throws MQBrokerException, RemotingException, InterruptedException, MQClientException {
mqClientAPI.updateGlobalWhiteAddrsConfig(defaultNsAddr, "", "", defaultTimeout);
}
@Test
public void assertGetBrokerClusterAclInfo() throws MQBrokerException, RemotingException, InterruptedException {
mockInvokeSync();
GetBrokerAclConfigResponseHeader responseHeader = mock(GetBrokerAclConfigResponseHeader.class);
when(responseHeader.getBrokerName()).thenReturn(brokerName);
when(responseHeader.getBrokerAddr()).thenReturn(defaultBrokerAddr);
when(responseHeader.getClusterName()).thenReturn(clusterName);
when(responseHeader.getAllAclFileVersion()).thenReturn("{\"key\":{\"stateVersion\":1}}");
setResponseHeader(responseHeader);
ClusterAclVersionInfo actual = mqClientAPI.getBrokerClusterAclInfo(defaultNsAddr, defaultTimeout);
assertNotNull(actual);
assertEquals(brokerName, actual.getBrokerName());
assertEquals(defaultBrokerAddr, actual.getBrokerAddr());
assertEquals(clusterName, actual.getClusterName());
assertEquals(1, actual.getAllAclConfigDataVersion().size());
assertNull(actual.getAclConfigDataVersion());
}
@Test
public void assertPullMessage() throws MQBrokerException, RemotingException, InterruptedException {
PullMessageRequestHeader requestHeader = mock(PullMessageRequestHeader.class);
@@ -16,7 +16,7 @@
## suggested format
- accessKey: rocketmq2
secretKey:
secretKey:
whiteRemoteAddress: 192.168.1.*
# if it is admin, it could access all resources
admin: true
+1
View File
@@ -57,6 +57,7 @@ java_library(
"@maven//:com_google_guava_guava",
"@maven//:com_alibaba_fastjson",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:commons_codec_commons_codec",
"@maven//:io_netty_netty_all",
"@maven//:io_opentelemetry_opentelemetry_api",
"@maven//:io_opentelemetry_opentelemetry_context",
@@ -1289,10 +1289,6 @@ public class BrokerConfig extends BrokerIdentity {
this.traceTopicEnable = traceTopicEnable;
}
public boolean isAclEnable() {
return aclEnable;
}
public void setAclEnable(boolean aclEnable) {
this.aclEnable = aclEnable;
}
@@ -1,107 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.common;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class AclConfigTest {
@Test
public void testGetGlobalWhiteAddrsWhenNull() {
AclConfig aclConfig = new AclConfig();
Assert.assertNull("The globalWhiteAddrs should return null", aclConfig.getGlobalWhiteAddrs());
}
@Test
public void testGetGlobalWhiteAddrsWhenEmpty() {
AclConfig aclConfig = new AclConfig();
List<String> globalWhiteAddrs = new ArrayList<>();
aclConfig.setGlobalWhiteAddrs(globalWhiteAddrs);
assertNotNull("The globalWhiteAddrs should never return null", aclConfig.getGlobalWhiteAddrs());
assertEquals("The globalWhiteAddrs list should be empty", 0, aclConfig.getGlobalWhiteAddrs().size());
}
@Test
public void testGetGlobalWhiteAddrs() {
AclConfig aclConfig = new AclConfig();
List<String> expected = Arrays.asList("192.168.1.1", "192.168.1.2");
aclConfig.setGlobalWhiteAddrs(expected);
assertEquals("Global white addresses should match", expected, aclConfig.getGlobalWhiteAddrs());
assertEquals("The globalWhiteAddrs list should be equal to 2", 2, aclConfig.getGlobalWhiteAddrs().size());
}
@Test
public void testGetPlainAccessConfigsWhenNull() {
AclConfig aclConfig = new AclConfig();
Assert.assertNull("The plainAccessConfigs should return null", aclConfig.getPlainAccessConfigs());
}
@Test
public void testGetPlainAccessConfigsWhenEmpty() {
AclConfig aclConfig = new AclConfig();
List<PlainAccessConfig> plainAccessConfigs = new ArrayList<>();
aclConfig.setPlainAccessConfigs(plainAccessConfigs);
assertNotNull("The plainAccessConfigs should never return null", aclConfig.getPlainAccessConfigs());
assertEquals("The plainAccessConfigs list should be empty", 0, aclConfig.getPlainAccessConfigs().size());
}
@Test
public void testGetPlainAccessConfigs() {
AclConfig aclConfig = new AclConfig();
List<PlainAccessConfig> expected = Arrays.asList(new PlainAccessConfig(), new PlainAccessConfig());
aclConfig.setPlainAccessConfigs(expected);
assertEquals("Plain access configs should match", expected, aclConfig.getPlainAccessConfigs());
assertEquals("The plainAccessConfigs list should be equal to 2", 2, aclConfig.getPlainAccessConfigs().size());
}
@Test
public void testToStringWithNullValues() {
AclConfig aclConfig = new AclConfig();
String result = aclConfig.toString();
assertNotNull("toString should not be null", result);
assertEquals("toString should match", "AclConfig{globalWhiteAddrs=null, plainAccessConfigs=null}", result);
}
@Test
public void testToStringWithEmptyGlobalWhiteAddrsAndPlainAccessConfigs() {
AclConfig aclConfig = new AclConfig();
aclConfig.setGlobalWhiteAddrs(Collections.emptyList());
aclConfig.setPlainAccessConfigs(Collections.emptyList());
String expected = "AclConfig{globalWhiteAddrs=[], plainAccessConfigs=[]}";
assertEquals(expected, aclConfig.toString());
}
@Test
public void testToStringWithNonEmptyGlobalWhiteAddrsAndPlainAccessConfigs() {
AclConfig aclConfig = new AclConfig();
List<String> globalWhiteAddrs = Collections.singletonList("192.168.1.1");
aclConfig.setGlobalWhiteAddrs(globalWhiteAddrs);
PlainAccessConfig plainAccessConfig = new PlainAccessConfig();
List<PlainAccessConfig> plainAccessConfigs = Collections.singletonList(plainAccessConfig);
aclConfig.setPlainAccessConfigs(plainAccessConfigs);
String expected = "AclConfig{globalWhiteAddrs=[192.168.1.1], plainAccessConfigs=[" + plainAccessConfig + "]}";
assertEquals("toString should match", expected, aclConfig.toString());
}
}
-42
View File
@@ -1,42 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress:
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
# the group should convert to retry topic
- groupA=DENY
- groupB=PUB|SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
# if it is admin, it could access all resources
admin: true
+1 -1
View File
@@ -54,7 +54,7 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-acl</artifactId>
<artifactId>rocketmq-auth</artifactId>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
-6
View File
@@ -193,7 +193,6 @@
<module>test</module>
<module>distribution</module>
<module>openmessaging</module>
<module>acl</module>
<module>auth</module>
<module>example</module>
<module>container</module>
@@ -545,11 +544,6 @@
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-acl</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-auth</artifactId>
-2
View File
@@ -21,7 +21,6 @@ java_library(
srcs = glob(["src/main/java/**/*.java"]),
visibility = ["//visibility:public"],
deps = [
"//acl",
"//auth",
"//broker",
"//client",
@@ -80,7 +79,6 @@ java_library(
],
visibility = ["//visibility:public"],
deps = [
"//acl",
"//auth",
":proxy",
"//:test_deps",
-4
View File
@@ -51,10 +51,6 @@
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-acl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-auth</artifactId>
@@ -20,27 +20,20 @@ package org.apache.rocketmq.proxy;
import com.google.common.collect.Lists;
import io.grpc.protobuf.services.ChannelzService;
import io.grpc.protobuf.services.ProtoReflectionService;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.acl.AccessValidator;
import org.apache.rocketmq.acl.plain.PlainAccessValidator;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.BrokerStartup;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.thread.ThreadPoolMonitor;
import org.apache.rocketmq.common.utils.ServiceProvider;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.common.utils.AbstractStartAndShutdown;
import org.apache.rocketmq.common.utils.StartAndShutdown;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.proxy.config.Configuration;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.config.ProxyConfig;
@@ -54,6 +47,11 @@ import org.apache.rocketmq.proxy.remoting.RemotingProtocolServer;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.srvutil.ServerUtil;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ProxyStartup {
private static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
private static final ProxyStartAndShutdown PROXY_START_AND_SHUTDOWN = new ProxyStartAndShutdown();
@@ -78,18 +76,17 @@ public class ProxyStartup {
MessagingProcessor messagingProcessor = createMessagingProcessor();
List<AccessValidator> accessValidators = loadAccessValidators();
// create grpcServer
GrpcServer grpcServer = GrpcServerBuilder.newBuilder(executor, ConfigurationManager.getProxyConfig().getGrpcServerPort())
.addService(createServiceProcessor(messagingProcessor))
.addService(ChannelzService.newInstance(100))
.addService(ProtoReflectionService.newInstance())
.configInterceptor(accessValidators)
.configInterceptor()
.shutdownTime(ConfigurationManager.getProxyConfig().getGrpcShutdownTimeSeconds(), TimeUnit.SECONDS)
.build();
PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(grpcServer);
RemotingProtocolServer remotingServer = new RemotingProtocolServer(messagingProcessor, accessValidators);
RemotingProtocolServer remotingServer = new RemotingProtocolServer(messagingProcessor);
PROXY_START_AND_SHUTDOWN.appendStartAndShutdown(remotingServer);
// start servers one by one.
@@ -114,15 +111,6 @@ public class ProxyStartup {
log.info(new Date() + " rocketmq-proxy startup successfully");
}
protected static List<AccessValidator> loadAccessValidators() {
List<AccessValidator> accessValidators = ServiceProvider.load(AccessValidator.class);
if (accessValidators.isEmpty()) {
log.info("ServiceProvider loaded no AccessValidator, using default org.apache.rocketmq.acl.plain.PlainAccessValidator");
accessValidators.add(new PlainAccessValidator());
}
return accessValidators;
}
protected static void initConfiguration(CommandLineArgument commandLineArgument) throws Exception {
if (StringUtils.isNotBlank(commandLineArgument.getProxyConfigPath())) {
System.setProperty(Configuration.CONFIG_PATH_PROPERTY, commandLineArgument.getProxyConfigPath());
@@ -17,16 +17,6 @@
package org.apache.rocketmq.proxy.config;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.Duration;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.constant.LoggerName;
@@ -38,6 +28,17 @@ import org.apache.rocketmq.proxy.ProxyMode;
import org.apache.rocketmq.proxy.common.ProxyException;
import org.apache.rocketmq.proxy.common.ProxyExceptionCode;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.Duration;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class ProxyConfig implements ConfigFile {
private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
public final static String DEFAULT_CONFIG_FILE_NAME = "rmq-proxy.json";
@@ -203,8 +204,6 @@ public class ProxyConfig implements ConfigFile {
private long renewMaxTimeMillis = TimeUnit.HOURS.toMillis(3);
private long renewSchedulePeriodMillis = TimeUnit.SECONDS.toMillis(5);
private boolean enableACL = false;
private boolean enableAclRpcHookForClusterMode = false;
private boolean useDelayLevel = false;
@@ -1046,14 +1045,6 @@ public class ProxyConfig implements ConfigFile {
this.longPollingReserveTimeInMillis = longPollingReserveTimeInMillis;
}
public boolean isEnableACL() {
return enableACL;
}
public void setEnableACL(boolean enableACL) {
this.enableACL = enableACL;
}
public boolean isEnableAclRpcHookForClusterMode() {
return enableAclRpcHookForClusterMode;
}
@@ -24,19 +24,17 @@ import io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup;
import io.grpc.netty.shaded.io.netty.channel.epoll.EpollServerSocketChannel;
import io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoopGroup;
import io.grpc.netty.shaded.io.netty.channel.socket.nio.NioServerSocketChannel;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.acl.AccessValidator;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.grpc.interceptor.AuthenticationInterceptor;
import org.apache.rocketmq.proxy.grpc.interceptor.ContextInterceptor;
import org.apache.rocketmq.proxy.grpc.interceptor.GlobalExceptionInterceptor;
import org.apache.rocketmq.proxy.grpc.interceptor.HeaderInterceptor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class GrpcServerBuilder {
private static final Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
protected NettyServerBuilder serverBuilder;
@@ -104,16 +102,11 @@ public class GrpcServerBuilder {
return new GrpcServer(this.serverBuilder.build(), time, unit);
}
public GrpcServerBuilder configInterceptor(List<AccessValidator> accessValidators) {
// grpc interceptors, including acl, logging etc.
this.serverBuilder
.intercept(new AuthenticationInterceptor(accessValidators));
public GrpcServerBuilder configInterceptor() {
this.serverBuilder
.intercept(new GlobalExceptionInterceptor())
.intercept(new ContextInterceptor())
.intercept(new HeaderInterceptor());
return this;
}
}
@@ -1,93 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.proxy.grpc.interceptor;
import com.google.protobuf.GeneratedMessageV3;
import io.grpc.Context;
import io.grpc.ForwardingServerCallListener;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import java.util.List;
import org.apache.rocketmq.acl.AccessResource;
import org.apache.rocketmq.acl.AccessValidator;
import org.apache.rocketmq.acl.common.AclException;
import org.apache.rocketmq.acl.common.AuthenticationHeader;
import org.apache.rocketmq.acl.plain.PlainAccessResource;
import org.apache.rocketmq.common.constant.GrpcConstants;
import org.apache.rocketmq.proxy.common.utils.GrpcUtils;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
public class AuthenticationInterceptor implements ServerInterceptor {
protected final List<AccessValidator> accessValidatorList;
public AuthenticationInterceptor(List<AccessValidator> accessValidatorList) {
this.accessValidatorList = accessValidatorList;
}
@Override
public <R, W> ServerCall.Listener<R> interceptCall(ServerCall<R, W> call, Metadata headers,
ServerCallHandler<R, W> next) {
return new ForwardingServerCallListener.SimpleForwardingServerCallListener<R>(next.startCall(call, headers)) {
@Override
public void onMessage(R message) {
GeneratedMessageV3 messageV3 = (GeneratedMessageV3) message;
GrpcUtils.putHeaderIfNotExist(headers, GrpcConstants.RPC_NAME, messageV3.getDescriptorForType().getFullName());
GrpcUtils.putHeaderIfNotExist(headers, GrpcConstants.SIMPLE_RPC_NAME, messageV3.getDescriptorForType().getName());
if (ConfigurationManager.getProxyConfig().isEnableACL()) {
try {
AuthenticationHeader authenticationHeader = AuthenticationHeader.builder()
.remoteAddress(GrpcConstants.METADATA.get(Context.current()).get(GrpcConstants.REMOTE_ADDRESS))
.namespace(GrpcConstants.METADATA.get(Context.current()).get(GrpcConstants.NAMESPACE_ID))
.authorization(GrpcConstants.METADATA.get(Context.current()).get(GrpcConstants.AUTHORIZATION))
.datetime(GrpcConstants.METADATA.get(Context.current()).get(GrpcConstants.DATE_TIME))
.sessionToken(GrpcConstants.METADATA.get(Context.current()).get(GrpcConstants.SESSION_TOKEN))
.requestId(GrpcConstants.METADATA.get(Context.current()).get(GrpcConstants.REQUEST_ID))
.language(GrpcConstants.METADATA.get(Context.current()).get(GrpcConstants.LANGUAGE))
.clientVersion(GrpcConstants.METADATA.get(Context.current()).get(GrpcConstants.CLIENT_VERSION))
.protocol(GrpcConstants.METADATA.get(Context.current()).get(GrpcConstants.PROTOCOL_VERSION))
.requestCode(RequestMapping.map(messageV3.getDescriptorForType().getFullName()))
.build();
validate(authenticationHeader, headers, messageV3);
super.onMessage(message);
} catch (AclException aclException) {
throw new StatusRuntimeException(Status.PERMISSION_DENIED, headers);
}
} else {
super.onMessage(message);
}
}
};
}
protected void validate(AuthenticationHeader authenticationHeader, Metadata headers, GeneratedMessageV3 messageV3) {
for (AccessValidator accessValidator : accessValidatorList) {
AccessResource accessResource = accessValidator.parse(messageV3, authenticationHeader);
accessValidator.validate(accessResource);
if (accessResource instanceof PlainAccessResource) {
PlainAccessResource plainAccessResource = (PlainAccessResource) accessResource;
GrpcUtils.putHeaderIfNotExist(headers, GrpcConstants.AUTHORIZATION_AK, plainAccessResource.getAccessKey());
}
}
}
}
@@ -19,13 +19,6 @@ package org.apache.rocketmq.proxy.remoting;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import io.netty.channel.Channel;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.acl.AccessValidator;
import org.apache.rocketmq.auth.config.AuthConfig;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.future.FutureTaskExt;
@@ -65,6 +58,12 @@ import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.remoting.protocol.RequestCode;
import org.apache.rocketmq.remoting.protocol.ResponseCode;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class RemotingProtocolServer implements StartAndShutdown, RemotingProxyOutClient {
private final static Logger log = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
@@ -90,11 +89,11 @@ public class RemotingProtocolServer implements StartAndShutdown, RemotingProxyOu
protected final ThreadPoolExecutor defaultExecutor;
protected final ScheduledExecutorService timerExecutor;
public RemotingProtocolServer(MessagingProcessor messagingProcessor, List<AccessValidator> accessValidators) {
public RemotingProtocolServer(MessagingProcessor messagingProcessor) {
this.messagingProcessor = messagingProcessor;
this.remotingChannelManager = new RemotingChannelManager(this, messagingProcessor.getProxyRelayService());
RequestPipeline pipeline = createRequestPipeline(accessValidators, messagingProcessor);
RequestPipeline pipeline = createRequestPipeline(messagingProcessor);
this.getTopicRouteActivity = new GetTopicRouteActivity(pipeline, messagingProcessor);
this.clientManagerActivity = new ClientManagerActivity(pipeline, messagingProcessor, remotingChannelManager);
this.consumerManagerActivity = new ConsumerManagerActivity(pipeline, messagingProcessor);
@@ -269,8 +268,7 @@ public class RemotingProtocolServer implements StartAndShutdown, RemotingProxyOu
return future;
}
protected RequestPipeline createRequestPipeline(List<AccessValidator> accessValidators,
MessagingProcessor messagingProcessor) {
protected RequestPipeline createRequestPipeline(MessagingProcessor messagingProcessor) {
RequestPipeline pipeline = (ctx, request, context) -> {
};
// add pipeline
@@ -278,7 +276,7 @@ public class RemotingProtocolServer implements StartAndShutdown, RemotingProxyOu
AuthConfig authConfig = ConfigurationManager.getAuthConfig();
if (authConfig != null) {
pipeline = pipeline.pipe(new AuthorizationPipeline(authConfig, messagingProcessor))
.pipe(new AuthenticationPipeline(accessValidators, authConfig, messagingProcessor));
.pipe(new AuthenticationPipeline(authConfig, messagingProcessor));
}
return pipeline.pipe(new ContextInitPipeline());
}
@@ -18,9 +18,6 @@
package org.apache.rocketmq.proxy.remoting.pipeline;
import io.netty.channel.ChannelHandlerContext;
import java.util.List;
import org.apache.rocketmq.acl.AccessResource;
import org.apache.rocketmq.acl.AccessValidator;
import org.apache.rocketmq.auth.authentication.AuthenticationEvaluator;
import org.apache.rocketmq.auth.authentication.context.AuthenticationContext;
import org.apache.rocketmq.auth.authentication.exception.AuthenticationException;
@@ -30,33 +27,21 @@ import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.proxy.common.ProxyContext;
import org.apache.rocketmq.proxy.config.ConfigurationManager;
import org.apache.rocketmq.proxy.config.ProxyConfig;
import org.apache.rocketmq.proxy.processor.MessagingProcessor;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
public class AuthenticationPipeline implements RequestPipeline {
private static final Logger LOGGER = LoggerFactory.getLogger(LoggerName.PROXY_LOGGER_NAME);
private final List<AccessValidator> accessValidatorList;
private final AuthConfig authConfig;
private final AuthenticationEvaluator authenticationEvaluator;
public AuthenticationPipeline(List<AccessValidator> accessValidatorList, AuthConfig authConfig, MessagingProcessor messagingProcessor) {
this.accessValidatorList = accessValidatorList;
public AuthenticationPipeline(AuthConfig authConfig, MessagingProcessor messagingProcessor) {
this.authConfig = authConfig;
this.authenticationEvaluator = AuthenticationFactory.getEvaluator(authConfig, messagingProcessor::getMetadataService);
}
@Override
public void execute(ChannelHandlerContext ctx, RemotingCommand request, ProxyContext context) throws Exception {
ProxyConfig config = ConfigurationManager.getProxyConfig();
if (config.isEnableACL()) {
for (AccessValidator accessValidator : accessValidatorList) {
AccessResource accessResource = accessValidator.parse(request, context.getRemoteAddress());
accessValidator.validate(accessResource);
}
}
if (!authConfig.isAuthenticationEnabled()) {
return;
}
@@ -73,17 +73,6 @@ public class RequestCode {
public static final int GET_CLIENT_CONFIG = 47;
public static final int UPDATE_AND_CREATE_ACL_CONFIG = 50;
public static final int DELETE_ACL_CONFIG = 51;
public static final int GET_BROKER_CLUSTER_ACL_INFO = 52;
public static final int UPDATE_GLOBAL_WHITE_ADDRS_CONFIG = 53;
@Deprecated
public static final int GET_BROKER_CLUSTER_ACL_CONFIG = 54;
public static final int GET_TIMER_CHECK_POINT = 60;
public static final int GET_TIMER_METRICS = 61;
@@ -74,12 +74,6 @@ public class ResponseCode extends RemotingSysResponseCode {
public static final int NO_MESSAGE = 208;
public static final int UPDATE_AND_CREATE_ACL_CONFIG_FAILED = 209;
public static final int DELETE_ACL_CONFIG_FAILED = 210;
public static final int UPDATE_GLOBAL_WHITE_ADDRS_CONFIG_FAILED = 211;
public static final int POLLING_FULL = 209;
public static final int POLLING_TIMEOUT = 210;
@@ -1,76 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.remoting.protocol.body;
import java.util.Map;
import org.apache.rocketmq.remoting.protocol.DataVersion;
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
public class ClusterAclVersionInfo extends RemotingSerializable {
private String brokerName;
private String brokerAddr;
@Deprecated
private DataVersion aclConfigDataVersion;
private Map<String, DataVersion> allAclConfigDataVersion;
private String clusterName;
public String getBrokerName() {
return brokerName;
}
public void setBrokerName(String brokerName) {
this.brokerName = brokerName;
}
public String getBrokerAddr() {
return brokerAddr;
}
public void setBrokerAddr(String brokerAddr) {
this.brokerAddr = brokerAddr;
}
public String getClusterName() {
return clusterName;
}
public void setClusterName(String clusterName) {
this.clusterName = clusterName;
}
public DataVersion getAclConfigDataVersion() {
return aclConfigDataVersion;
}
public void setAclConfigDataVersion(DataVersion aclConfigDataVersion) {
this.aclConfigDataVersion = aclConfigDataVersion;
}
public Map<String, DataVersion> getAllAclConfigDataVersion() {
return allAclConfigDataVersion;
}
public void setAllAclConfigDataVersion(
Map<String, DataVersion> allAclConfigDataVersion) {
this.allAclConfigDataVersion = allAclConfigDataVersion;
}
}
@@ -1,134 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.remoting.protocol.header;
import com.google.common.base.MoreObjects;
import org.apache.rocketmq.common.action.Action;
import org.apache.rocketmq.common.action.RocketMQAction;
import org.apache.rocketmq.common.resource.ResourceType;
import org.apache.rocketmq.remoting.CommandCustomHeader;
import org.apache.rocketmq.remoting.annotation.CFNotNull;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.protocol.RequestCode;
@RocketMQAction(value = RequestCode.UPDATE_AND_CREATE_ACL_CONFIG, resource = ResourceType.CLUSTER, action = Action.UPDATE)
public class CreateAccessConfigRequestHeader implements CommandCustomHeader {
@CFNotNull
private String accessKey;
private String secretKey;
private String whiteRemoteAddress;
private boolean admin;
private String defaultTopicPerm;
private String defaultGroupPerm;
// list string,eg: topicA=DENY,topicD=SUB
private String topicPerms;
// list string,eg: groupD=DENY,groupD=SUB
private String groupPerms;
@Override
public void checkFields() throws RemotingCommandException {
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getWhiteRemoteAddress() {
return whiteRemoteAddress;
}
public void setWhiteRemoteAddress(String whiteRemoteAddress) {
this.whiteRemoteAddress = whiteRemoteAddress;
}
public boolean isAdmin() {
return admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
public String getDefaultTopicPerm() {
return defaultTopicPerm;
}
public void setDefaultTopicPerm(String defaultTopicPerm) {
this.defaultTopicPerm = defaultTopicPerm;
}
public String getDefaultGroupPerm() {
return defaultGroupPerm;
}
public void setDefaultGroupPerm(String defaultGroupPerm) {
this.defaultGroupPerm = defaultGroupPerm;
}
public String getTopicPerms() {
return topicPerms;
}
public void setTopicPerms(String topicPerms) {
this.topicPerms = topicPerms;
}
public String getGroupPerms() {
return groupPerms;
}
public void setGroupPerms(String groupPerms) {
this.groupPerms = groupPerms;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("accessKey", accessKey)
.add("secretKey", secretKey)
.add("whiteRemoteAddress", whiteRemoteAddress)
.add("admin", admin)
.add("defaultTopicPerm", defaultTopicPerm)
.add("defaultGroupPerm", defaultGroupPerm)
.add("topicPerms", topicPerms)
.add("groupPerms", groupPerms)
.toString();
}
}
@@ -1,46 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.remoting.protocol.header;
import org.apache.rocketmq.common.action.Action;
import org.apache.rocketmq.common.action.RocketMQAction;
import org.apache.rocketmq.common.resource.ResourceType;
import org.apache.rocketmq.remoting.CommandCustomHeader;
import org.apache.rocketmq.remoting.annotation.CFNotNull;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.protocol.RequestCode;
@RocketMQAction(value = RequestCode.DELETE_ACL_CONFIG, resource = ResourceType.CLUSTER, action = Action.UPDATE)
public class DeleteAccessConfigRequestHeader implements CommandCustomHeader {
@CFNotNull
private String accessKey;
@Override
public void checkFields() throws RemotingCommandException {
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
}
@@ -1,89 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.remoting.protocol.header;
import org.apache.rocketmq.common.action.Action;
import org.apache.rocketmq.common.action.RocketMQAction;
import org.apache.rocketmq.common.resource.ResourceType;
import org.apache.rocketmq.common.resource.RocketMQResource;
import org.apache.rocketmq.remoting.CommandCustomHeader;
import org.apache.rocketmq.remoting.annotation.CFNotNull;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.protocol.RequestCode;
@RocketMQAction(value = RequestCode.GET_BROKER_CLUSTER_ACL_INFO, resource = ResourceType.CLUSTER, action = Action.GET)
public class GetBrokerAclConfigResponseHeader implements CommandCustomHeader {
@CFNotNull
private String version;
private String allAclFileVersion;
@CFNotNull
private String brokerName;
@CFNotNull
private String brokerAddr;
@CFNotNull
@RocketMQResource(ResourceType.CLUSTER)
private String clusterName;
@Override
public void checkFields() throws RemotingCommandException {
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getBrokerName() {
return brokerName;
}
public void setBrokerName(String brokerName) {
this.brokerName = brokerName;
}
public String getBrokerAddr() {
return brokerAddr;
}
public void setBrokerAddr(String brokerAddr) {
this.brokerAddr = brokerAddr;
}
public String getClusterName() {
return clusterName;
}
public void setClusterName(String clusterName) {
this.clusterName = clusterName;
}
public String getAllAclFileVersion() {
return allAclFileVersion;
}
public void setAllAclFileVersion(String allAclFileVersion) {
this.allAclFileVersion = allAclFileVersion;
}
}
@@ -1,55 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.remoting.protocol.header;
import org.apache.rocketmq.common.action.Action;
import org.apache.rocketmq.common.action.RocketMQAction;
import org.apache.rocketmq.common.resource.ResourceType;
import org.apache.rocketmq.remoting.CommandCustomHeader;
import org.apache.rocketmq.remoting.annotation.CFNotNull;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.protocol.RequestCode;
@RocketMQAction(value = RequestCode.UPDATE_GLOBAL_WHITE_ADDRS_CONFIG, resource = ResourceType.CLUSTER, action = Action.UPDATE)
public class UpdateGlobalWhiteAddrsConfigRequestHeader implements CommandCustomHeader {
@CFNotNull
private String globalWhiteAddrs;
@CFNotNull
private String aclFileFullPath;
@Override
public void checkFields() throws RemotingCommandException {
}
public String getGlobalWhiteAddrs() {
return globalWhiteAddrs;
}
public void setGlobalWhiteAddrs(String globalWhiteAddrs) {
this.globalWhiteAddrs = globalWhiteAddrs;
}
public String getAclFileFullPath() {
return aclFileFullPath;
}
public void setAclFileFullPath(String aclFileFullPath) {
this.aclFileFullPath = aclFileFullPath;
}
}
@@ -1,162 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.srvutil;
import java.util.ArrayList;
import java.util.List;
import org.apache.rocketmq.common.ServiceThread;
import org.apache.rocketmq.common.UtilAll;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
public class AclFileWatchService extends ServiceThread {
private static final Logger log = LoggerFactory.getLogger(LoggerName.COMMON_LOGGER_NAME);
private final String aclPath;
private int aclFilesNum;
@Deprecated
private final Map<String, String> fileCurrentHash;
private Map<String, Long> fileLastModifiedTime;
private List<String/**absolute pathname **/> fileList = new ArrayList<>();
private final AclFileWatchService.Listener listener;
private static final int WATCH_INTERVAL = 5000;
private MessageDigest md = MessageDigest.getInstance("MD5");
private String defaultAclFile;
public AclFileWatchService(String path, String defaultAclFile, final AclFileWatchService.Listener listener) throws Exception {
this.aclPath = path;
this.defaultAclFile = defaultAclFile;
this.fileCurrentHash = new HashMap<>();
this.fileLastModifiedTime = new HashMap<>();
this.listener = listener;
getAllAclFiles(path);
if (new File(this.defaultAclFile).exists() && !fileList.contains(this.defaultAclFile)) {
fileList.add(this.defaultAclFile);
}
this.aclFilesNum = fileList.size();
for (int i = 0; i < aclFilesNum; i++) {
String fileAbsolutePath = fileList.get(i);
this.fileLastModifiedTime.put(fileAbsolutePath, new File(fileAbsolutePath).lastModified());
}
}
public void getAllAclFiles(String path) {
File file = new File(path);
if (!file.exists()) {
log.info("The default acl dir {} is not exist", path);
return;
}
File[] files = file.listFiles();
for (int i = 0; files != null && i < files.length; i++) {
String fileName = files[i].getAbsolutePath();
File f = new File(fileName);
if (fileName.equals(aclPath + File.separator + "tools.yml")) {
continue;
} else if (fileName.endsWith(".yml") || fileName.endsWith(".yaml")) {
fileList.add(fileName);
} else if (f.isDirectory()) {
getAllAclFiles(fileName);
}
}
}
@Override
public String getServiceName() {
return "AclFileWatchService";
}
@Override
public void run() {
log.info(this.getServiceName() + " service started");
while (!this.isStopped()) {
try {
this.waitForRunning(WATCH_INTERVAL);
if (fileList.size() > 0) {
fileList.clear();
}
getAllAclFiles(aclPath);
if (new File(defaultAclFile).exists() && !fileList.contains(defaultAclFile)) {
fileList.add(defaultAclFile);
}
int realAclFilesNum = fileList.size();
if (aclFilesNum != realAclFilesNum) {
log.info("aclFilesNum: " + aclFilesNum + " realAclFilesNum: " + realAclFilesNum);
aclFilesNum = realAclFilesNum;
log.info("aclFilesNum: " + aclFilesNum + " realAclFilesNum: " + realAclFilesNum);
Map<String, Long> fileLastModifiedTime = new HashMap<>(realAclFilesNum);
for (int i = 0; i < realAclFilesNum; i++) {
String fileAbsolutePath = fileList.get(i);
fileLastModifiedTime.put(fileAbsolutePath, new File(fileAbsolutePath).lastModified());
}
this.fileLastModifiedTime = fileLastModifiedTime;
listener.onFileNumChanged(aclPath);
} else {
for (int i = 0; i < aclFilesNum; i++) {
String fileName = fileList.get(i);
Long newLastModifiedTime = new File(fileName).lastModified();
if (!newLastModifiedTime.equals(fileLastModifiedTime.get(fileName))) {
fileLastModifiedTime.put(fileName, newLastModifiedTime);
listener.onFileChanged(fileName);
}
}
}
} catch (Exception e) {
log.warn(this.getServiceName() + " service has exception. ", e);
}
}
log.info(this.getServiceName() + " service end");
}
@Deprecated
private String hash(String filePath) throws IOException {
Path path = Paths.get(filePath);
md.update(Files.readAllBytes(path));
byte[] hash = md.digest();
return UtilAll.bytes2string(hash);
}
public interface Listener {
/**
* Will be called when the target file is changed
*
* @param aclFileName the changed file absolute path
*/
void onFileChanged(String aclFileName);
/**
* Will be called when the number of the acl file is changed
*
* @param path the path of the acl dir
*/
void onFileNumChanged(String path);
}
}
+1
View File
@@ -24,6 +24,7 @@ java_library(
"//common",
"//remoting",
"@maven//:com_alibaba_fastjson",
"@maven//:com_alibaba_fastjson2_fastjson2",
"@maven//:com_conversantmedia_disruptor",
"@maven//:com_google_guava_guava",
"@maven//:commons_collections_commons_collections",
@@ -51,7 +51,7 @@ Method cloneGroupOffset(boolean,java.lang.String,java.lang.String,java.lang.Stri
Method consumeMessageDirectly(java.lang.String,java.lang.String,java.lang.String) : public throws (org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult)
Method consumeMessageDirectly(java.lang.String,java.lang.String,java.lang.String,java.lang.String) : public throws (org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult)
Method createAndUpdateKvConfig(java.lang.String,java.lang.String,java.lang.String) : public throws (void)
Method createAndUpdatePlainAccessConfig(java.lang.String,org.apache.rocketmq.common.PlainAccessConfig) : public throws (void)
Method createAndUpdatePlainAccessConfig(java.lang.String,org.apache.rocketmq.auth.migration.plain.PlainAccessConfig) : public throws (void)
Method createAndUpdateSubscriptionGroupConfig(java.lang.String,org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig) : public throws (void)
Method createAndUpdateTopicConfig(java.lang.String,org.apache.rocketmq.common.TopicConfig) : public throws (void)
Method createOrUpdateOrderConf(boolean,java.lang.String,java.lang.String) : public throws (void)
@@ -66,7 +66,7 @@ Method deleteSubscriptionGroup(java.lang.String,java.lang.String) : public throw
Method deleteTopicInBroker(java.lang.String,java.util.Set) : public throws (void)
Method deleteTopicInNameServer(java.lang.String,java.lang.String,java.util.Set) : public throws (void)
Method earliestMsgStoreTime(org.apache.rocketmq.common.message.MessageQueue) : public throws (long)
Method examineBrokerClusterAclConfig(java.lang.String) : public throws (org.apache.rocketmq.common.AclConfig)
Method examineBrokerClusterAclConfig(java.lang.String) : public throws (org.apache.rocketmq.auth.migration.plain.AclConfig)
Method examineBrokerClusterAclVersionInfo(java.lang.String) : public throws (org.apache.rocketmq.remoting.protocol.body.ClusterAclVersionInfo)
Method examineBrokerClusterInfo() : public throws (org.apache.rocketmq.remoting.protocol.body.ClusterInfo)
Method examineConsumeStats(java.lang.String) : public throws (org.apache.rocketmq.remoting.protocol.admin.ConsumeStats)

Some files were not shown because too many files have changed in this diff Show More