Fix qos command remote check (#11506)
* Fix qos command remote check * update * Fix NPE
This commit is contained in:
parent
a1dea63969
commit
57c58de0ad
|
|
@ -16,10 +16,10 @@
|
|||
*/
|
||||
package org.apache.dubbo.qos.command;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import org.apache.dubbo.qos.permission.PermissionLevel;
|
||||
import org.apache.dubbo.qos.common.QosConfiguration;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
public class CommandContext {
|
||||
|
||||
private String commandName;
|
||||
|
|
@ -93,8 +93,8 @@ public class CommandContext {
|
|||
this.qosConfiguration = qosConfiguration;
|
||||
}
|
||||
|
||||
public boolean hasPermission(PermissionLevel cmdRequiredPermissionLevel) {
|
||||
return cmdRequiredPermissionLevel.getLevel() <= qosConfiguration.getAnonymousAccessPermissionLevel().getLevel();
|
||||
public QosConfiguration getQosConfiguration() {
|
||||
return qosConfiguration;
|
||||
}
|
||||
|
||||
public boolean isAllowAnonymousAccess(){
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@
|
|||
*/
|
||||
package org.apache.dubbo.qos.common;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.qos.permission.PermissionLevel;
|
||||
|
||||
public class QosConfiguration {
|
||||
|
|
@ -26,6 +32,8 @@ public class QosConfiguration {
|
|||
// support specific ip and an ip range from CIDR specification
|
||||
private String acceptForeignIpWhitelist;
|
||||
|
||||
private Predicate<String> acceptForeignIpWhitelistPredicate;
|
||||
|
||||
// this permission level for anonymous access, it will ignore the acceptForeignIp and acceptForeignIpWhitelist configurations
|
||||
// Access permission depends on the config anonymousAccessPermissionLevel and the cmd required permission level
|
||||
// the default value is Cmd.PermissionLevel.PUBLIC, can only access PUBLIC level cmd
|
||||
|
|
@ -39,6 +47,27 @@ public class QosConfiguration {
|
|||
this.acceptForeignIp = builder.isAcceptForeignIp();
|
||||
this.acceptForeignIpWhitelist = builder.getAcceptForeignIpWhitelist();
|
||||
this.anonymousAccessPermissionLevel = builder.getAnonymousAccessPermissionLevel();
|
||||
buildPredicate();
|
||||
}
|
||||
|
||||
private void buildPredicate() {
|
||||
if (StringUtils.isNotEmpty(acceptForeignIpWhitelist)) {
|
||||
this.acceptForeignIpWhitelistPredicate = Arrays.stream(acceptForeignIpWhitelist.split(","))
|
||||
.map(String::trim)
|
||||
.filter(StringUtils::isNotEmpty)
|
||||
.map(foreignIpPattern -> (Predicate<String>) foreignIp -> {
|
||||
try {
|
||||
// hard code port to -1
|
||||
return NetUtils.matchIpExpression(foreignIpPattern, foreignIp, -1);
|
||||
} catch (UnknownHostException ignore) {
|
||||
// ignore illegal CIDR specification
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.reduce(Predicate::or).orElse(s -> false);
|
||||
} else {
|
||||
this.acceptForeignIpWhitelistPredicate = foreignIp -> false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAllowAnonymousAccess() {
|
||||
|
|
@ -57,6 +86,10 @@ public class QosConfiguration {
|
|||
return acceptForeignIpWhitelist;
|
||||
}
|
||||
|
||||
public Predicate<String> getAcceptForeignIpWhitelistPredicate() {
|
||||
return acceptForeignIpWhitelistPredicate;
|
||||
}
|
||||
|
||||
public boolean isAcceptForeignIp() {
|
||||
return acceptForeignIp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,37 @@
|
|||
package org.apache.dubbo.qos.permission;
|
||||
|
||||
import org.apache.dubbo.qos.command.CommandContext;
|
||||
import org.apache.dubbo.qos.common.QosConfiguration;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Optional;
|
||||
|
||||
public class DefaultAnonymousAccessPermissionChecker implements PermissionChecker {
|
||||
public static final DefaultAnonymousAccessPermissionChecker INSTANCE = new DefaultAnonymousAccessPermissionChecker();
|
||||
|
||||
@Override
|
||||
public boolean access(CommandContext commandContext, PermissionLevel defaultCmdRequiredPermissionLevel) {
|
||||
return commandContext.hasPermission(defaultCmdRequiredPermissionLevel);
|
||||
final InetAddress inetAddress = Optional.ofNullable(commandContext.getRemote())
|
||||
.map(Channel::remoteAddress)
|
||||
.map(InetSocketAddress.class::cast)
|
||||
.map(InetSocketAddress::getAddress)
|
||||
.orElse(null);
|
||||
|
||||
QosConfiguration qosConfiguration = commandContext.getQosConfiguration();
|
||||
PermissionLevel currentLevel = qosConfiguration.getAnonymousAccessPermissionLevel();
|
||||
|
||||
// Local has private permission
|
||||
if (inetAddress != null && inetAddress.isLoopbackAddress()) {
|
||||
currentLevel = PermissionLevel.PRIVATE;
|
||||
} else if (inetAddress != null &&
|
||||
qosConfiguration.getAcceptForeignIpWhitelistPredicate()
|
||||
.test(inetAddress.getHostAddress())) {
|
||||
currentLevel = PermissionLevel.PROTECTED;
|
||||
}
|
||||
|
||||
return currentLevel.getLevel() >= defaultCmdRequiredPermissionLevel.getLevel();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,21 +16,19 @@
|
|||
*/
|
||||
package org.apache.dubbo.qos.server.handler;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.qos.common.QosConfiguration;
|
||||
import org.apache.dubbo.qos.common.QosConstants;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerAdapter;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.qos.common.QosConstants;
|
||||
import org.apache.dubbo.qos.common.QosConfiguration;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ForeignHostPermitHandler extends ChannelHandlerAdapter {
|
||||
|
||||
|
|
@ -40,7 +38,7 @@ public class ForeignHostPermitHandler extends ChannelHandlerAdapter {
|
|||
// the whitelist of foreign IP when acceptForeignIp = false, the delimiter is colon(,)
|
||||
// support specific ip and an ip range from CIDR specification
|
||||
private final String acceptForeignIpWhitelist;
|
||||
private Predicate<String> whitelistPredicate = foreignIp -> false;
|
||||
private Predicate<String> whitelistPredicate;
|
||||
|
||||
private final QosConfiguration qosConfiguration;
|
||||
|
||||
|
|
@ -48,21 +46,7 @@ public class ForeignHostPermitHandler extends ChannelHandlerAdapter {
|
|||
this.qosConfiguration = qosConfiguration;
|
||||
this.acceptForeignIp = qosConfiguration.isAcceptForeignIp();
|
||||
this.acceptForeignIpWhitelist = qosConfiguration.getAcceptForeignIpWhitelist();
|
||||
if (StringUtils.isNotEmpty(acceptForeignIpWhitelist)) {
|
||||
whitelistPredicate = Arrays.stream(acceptForeignIpWhitelist.split(","))
|
||||
.map(String::trim)
|
||||
.filter(StringUtils::isNotEmpty)
|
||||
.map(foreignIpPattern -> (Predicate<String>) foreignIp -> {
|
||||
try {
|
||||
// hard code port to -1
|
||||
return NetUtils.matchIpExpression(foreignIpPattern, foreignIp, -1);
|
||||
} catch (UnknownHostException ignore) {
|
||||
// ignore illegal CIDR specification
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.reduce(Predicate::or).orElse(s -> false);
|
||||
}
|
||||
this.whitelistPredicate = qosConfiguration.getAcceptForeignIpWhitelistPredicate();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.dubbo.qos.permission;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.apache.dubbo.qos.command.CommandContext;
|
||||
import org.apache.dubbo.qos.common.QosConfiguration;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
class DefaultAnonymousAccessPermissionCheckerTest {
|
||||
@Test
|
||||
void testPermission() throws UnknownHostException {
|
||||
InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
|
||||
|
||||
InetSocketAddress socketAddress = Mockito.mock(InetSocketAddress.class);
|
||||
Mockito.when(socketAddress.getAddress()).thenReturn(inetAddress);
|
||||
Channel channel = Mockito.mock(Channel.class);
|
||||
Mockito.when(channel.remoteAddress()).thenReturn(socketAddress);
|
||||
CommandContext commandContext = Mockito.mock(CommandContext.class);
|
||||
Mockito.when(commandContext.getRemote()).thenReturn(channel);
|
||||
|
||||
QosConfiguration qosConfiguration = Mockito.mock(QosConfiguration.class);
|
||||
Mockito.when(qosConfiguration.getAnonymousAccessPermissionLevel()).thenReturn(PermissionLevel.PUBLIC);
|
||||
Mockito.when(qosConfiguration.getAcceptForeignIpWhitelistPredicate()).thenReturn(ip -> false);
|
||||
|
||||
Mockito.when(commandContext.getQosConfiguration()).thenReturn(qosConfiguration);
|
||||
|
||||
DefaultAnonymousAccessPermissionChecker checker = new DefaultAnonymousAccessPermissionChecker();
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PUBLIC));
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PROTECTED));
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PRIVATE));
|
||||
|
||||
inetAddress = InetAddress.getByName("1.1.1.1");
|
||||
Mockito.when(socketAddress.getAddress()).thenReturn(inetAddress);
|
||||
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PUBLIC));
|
||||
Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PROTECTED));
|
||||
Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PRIVATE));
|
||||
|
||||
Mockito.when(qosConfiguration.getAnonymousAccessPermissionLevel()).thenReturn(PermissionLevel.PROTECTED);
|
||||
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PUBLIC));
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PROTECTED));
|
||||
Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PRIVATE));
|
||||
|
||||
Mockito.when(qosConfiguration.getAnonymousAccessPermissionLevel()).thenReturn(PermissionLevel.NONE);
|
||||
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));
|
||||
Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PUBLIC));
|
||||
Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PROTECTED));
|
||||
Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PRIVATE));
|
||||
|
||||
Mockito.when(qosConfiguration.getAcceptForeignIpWhitelistPredicate()).thenReturn(ip -> true);
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.NONE));
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PUBLIC));
|
||||
Assertions.assertTrue(checker.access(commandContext, PermissionLevel.PROTECTED));
|
||||
Assertions.assertFalse(checker.access(commandContext, PermissionLevel.PRIVATE));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue