Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance MySQL firewall public IP for local PC #5163

Merged
merged 22 commits into from
Apr 28, 2021
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9531cf7
upgrade azure-toolkit-libs to 0.7.0-SNAPSHOT
wangmingliang-ms Apr 23, 2021
1203aec
upgrade azure-toolkit-for-java to 3.53.0-SNAPSHOT
wangmingliang-ms Apr 23, 2021
d03e4d2
remove azure-auth-helper from Utils.
wangmingliang-ms Apr 23, 2021
ec646fd
Merge pull request #5148 from microsoft/startgame-s187
wangmingliang-ms Apr 23, 2021
bcd6db7
rename mysql related common utils.
shenqianjin Apr 27, 2021
8ab9374
get public IP by ping MySQL server for local PC
shenqianjin Apr 27, 2021
fbb072f
add NetUtils.
shenqianjin Apr 27, 2021
8989966
revert mysql related utils package.
shenqianjin Apr 27, 2021
cdb0031
updated firewallRule Service code location.
shenqianjin Apr 27, 2021
2849d9c
revert changes on MySQLConnectionUtils.
shenqianjin Apr 27, 2021
6477300
rename improper method name.
shenqianjin Apr 27, 2021
6f9e79c
extract getPublicIp method.
shenqianjin Apr 27, 2021
74eca28
fix compile issue.
shenqianjin Apr 27, 2021
a9d78a0
check firewall update result to update rule combox check status.
shenqianjin Apr 27, 2021
63a6686
expose getMac method for Azure MySQL firewall rule of local PC.
shenqianjin Apr 27, 2021
875e312
refactor getMac logic.
shenqianjin Apr 27, 2021
f89e506
add an alternative public IP getting approach by public URL.
shenqianjin Apr 27, 2021
a0bbd98
fix compile error.
shenqianjin Apr 27, 2021
3225434
Merge branch 'endgame-s186' into qianjin-bugfix-mysql
shenqianjin Apr 28, 2021
aeb858b
fixed compile issue.
shenqianjin Apr 28, 2021
9cc06d8
revert lib version to adopt endgame's
shenqianjin Apr 28, 2021
294de83
revert dependencies in util/pom.xml
shenqianjin Apr 28, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions PluginsAndFeatures/AddLibrary/AzureLibraries/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<parent>
<groupId>com.microsoft.azuretools</groupId>
<artifactId>utils</artifactId>
<version>3.52.0</version>
<version>3.53.0-SNAPSHOT</version>
</parent>
<groupId>com.microsoft.azuretools</groupId>
<artifactId>com.microsoft.azuretools.sdk.lib</artifactId>
Expand All @@ -38,7 +38,7 @@
<organization><name>Microsoft Corp.</name></organization>

<properties>
<azuretool.version>3.52.0</azuretool.version>
<azuretool.version>3.53.0-SNAPSHOT</azuretool.version>
<azuretool.sdk.version>3.25.0.qualifier</azuretool.sdk.version>
</properties>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ dependencies {
exclude group: "com.fasterxml.jackson", module: "jackson-bom"
}
compile project(':azure-intellij-plugin-lib')
compile "com.microsoft.azure:azure-toolkit-common-lib:0.6.0"
compile "com.microsoft.azure:azure-toolkit-common-lib:0.7.0-SNAPSHOT"

aspect "com.microsoft.azure:azure-toolkit-common-lib:0.6.0"
aspect "com.microsoft.azure:azure-toolkit-common-lib:0.7.0-SNAPSHOT"
}
12 changes: 6 additions & 6 deletions PluginsAndFeatures/azure-toolkit-for-intellij/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ subprojects {
compileOnly 'org.projectlombok:lombok:1.18.8'
annotationProcessor 'org.projectlombok:lombok:1.18.8'

compile "com.microsoft.azure:azure-toolkit-common-lib:0.6.0"
compile "com.microsoft.azure:azure-toolkit-common-lib:0.7.0-SNAPSHOT"
}
}

Expand Down Expand Up @@ -157,19 +157,19 @@ dependencies {
compile 'net.minidev:json-smart:2.3'
compile 'com.microsoft.azure:azure-client-runtime:1.7.5', { force = true }
compile 'com.microsoft.azure:azure-client-authentication:1.7.5', { force = true }
compile 'com.microsoft.azure:azure-toolkit-springcloud-lib:0.6.0', { force = true }
aspect "com.microsoft.azure:azure-toolkit-common-lib:0.6.0"
compile 'com.microsoft.azuretools:azuretools-core:3.52.0', {
compile 'com.microsoft.azure:azure-toolkit-springcloud-lib:0.7.0-SNAPSHOT', { force = true }
aspect "com.microsoft.azure:azure-toolkit-common-lib:0.7.0-SNAPSHOT"
compile 'com.microsoft.azuretools:azuretools-core:3.53.0-SNAPSHOT', {
exclude group: "com.microsoft.azure", module: "azure-client-authentication"
exclude group: "com.microsoft.azure", module: "azure-client-runtime"
exclude group: "javax.xml.bind", module: "jaxb-api"
}
compile 'com.microsoft.azuretools:azure-explorer-common:3.52.0', {
compile 'com.microsoft.azuretools:azure-explorer-common:3.53.0-SNAPSHOT', {
exclude group: "com.microsoft.azure", module: "azure-client-authentication"
exclude group: "com.microsoft.azure", module: "azure-client-runtime"
exclude group: "javax.xml.bind", module: "jaxb-api"
}
compile 'com.microsoft.azuretools:hdinsight-node-common:3.52.0', {
compile 'com.microsoft.azuretools:hdinsight-node-common:3.53.0-SNAPSHOT', {
exclude group: "com.microsoft.azure", module: "azure-client-authentication"
exclude group: "com.microsoft.azure", module: "azure-client-runtime"
exclude group: "javax.xml.bind", module: "jaxb-api"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
xmlns:xi="http://www.w3.org/2001/XInclude">
<id>com.microsoft.tooling.msservices.intellij.azure</id>
<name>Azure Toolkit for IntelliJ</name>
<version>3.52.0</version>
<version>3.53.0-SNAPSHOT</version>
<vendor email="[email protected]" url="http://www.microsoft.com">Microsoft</vendor>

<description><![CDATA[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ public static JdbcUrl mysql(String serverHost, String database) {
return new JdbcUrl(String.format("jdbc:mysql://%s:3306/%s?serverTimezone=UTC&useSSL=true&requireSSL=false", serverHost, database));
}

public static JdbcUrl mysql(String serverHost) {
return new JdbcUrl(String.format("jdbc:mysql://%s:3306?serverTimezone=UTC&useSSL=true&requireSSL=false", serverHost));
}

public int getPort() {
if (this.uri.getScheme().toLowerCase().startsWith("mysql")) {
return this.uri.getPort() < 1 ? 3306 : this.uri.getPort();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ public static ConnectResult connectWithPing(JdbcUrl url, String username, String
serverVersion = ((ConnectionImpl) connection).getServerVersion().toString();
} catch (final SQLException exception) {
errorCode = exception.getErrorCode();
errorMessage = exception.getErrorCode() == CONNECTION_ERROR_CODE ? String.format(CONNECTION_ISSUE_MESSAGE, exception.getMessage()) : exception.getMessage();
errorMessage = exception.getErrorCode() == CONNECTION_ERROR_CODE ? String.format(CONNECTION_ISSUE_MESSAGE, exception.getMessage())
: exception.getMessage();
} catch (final ClassNotFoundException | RuntimeException exception) {
errorCode = exception instanceof ClassNotFoundException ? CLASS_NOT_FOUND_ERROR_CODE : UNKNOWN_EXCEPTION_ERROR_CODE;
errorMessage = exception.getMessage();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
import com.microsoft.azure.toolkit.lib.common.task.AzureTask;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azure.toolkit.lib.mysql.AzureMySQLService;
import com.microsoft.azuretools.ActionConstants;
import com.microsoft.azuretools.azurecommons.util.Utils;
import com.microsoft.azuretools.core.mvp.model.AzureMvpModel;
Expand Down Expand Up @@ -154,7 +155,7 @@ private void onSaveButtonClicked(ActionEvent e) {
}
boolean allowAccessToLocal = connectionSecurity.getAllowAccessFromLocalMachineCheckBox().getModel().isSelected();
if (!originalAllowAccessToLocal.equals(allowAccessToLocal)) {
MySQLMvpModel.FirewallRuleMvpModel.updateAllowAccessToLocalMachine(subscriptionId, property.getServer(), allowAccessToLocal);
AzureMySQLService.FirewallRuleService.getInstance().updateAllowAccessToLocalMachine(subscriptionId, property.getServer(), allowAccessToLocal);
originalAllowAccessToLocal = allowAccessToLocal;
shenqianjin marked this conversation as resolved.
Show resolved Hide resolved
}
MySQLPropertyView.this.propertyActionPanel.getSaveButton().setText(originalText);
Expand Down Expand Up @@ -270,7 +271,7 @@ public void showProperty(MySQLProperty property) {
if (ServerState.READY.equals(server.userVisibleState())) {
originalAllowAccessToAzureServices = MySQLMvpModel.FirewallRuleMvpModel.isAllowAccessFromAzureServices(property.getFirewallRules());
connectionSecurity.getAllowAccessFromAzureServicesCheckBox().setSelected(originalAllowAccessToAzureServices);
originalAllowAccessToLocal = MySQLMvpModel.FirewallRuleMvpModel.isAllowAccessFromLocalMachine(property.getFirewallRules());
originalAllowAccessToLocal = AzureMySQLService.FirewallRuleService.getInstance().isAllowAccessFromLocalMachine(property.getFirewallRules());
connectionSecurity.getAllowAccessFromLocalMachineCheckBox().setSelected(originalAllowAccessToLocal);
} else {
connectionSecuritySeparator.collapse();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,25 @@
import com.microsoft.azure.management.Azure;
import com.microsoft.azure.management.mysql.v2020_01_01.Server;
import com.microsoft.azure.management.mysql.v2020_01_01.ServerPropertiesForDefaultCreate;
import com.microsoft.azure.management.mysql.v2020_01_01.implementation.FirewallRuleInner;
import com.microsoft.azure.management.mysql.v2020_01_01.implementation.MySQLManager;
import com.microsoft.azure.management.resources.ResourceGroup;
import com.microsoft.azure.toolkit.intellij.common.Draft;
import com.microsoft.azure.toolkit.intellij.connector.mysql.JdbcUrl;
import com.microsoft.azure.toolkit.intellij.connector.mysql.MySQLConnectionUtils;
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
import com.microsoft.azuretools.ActionConstants;
import com.microsoft.azuretools.authmanage.AuthMethodManager;
import com.microsoft.azuretools.core.mvp.model.mysql.MySQLMvpModel;
import com.microsoft.azuretools.telemetry.TelemetryConstants;
import com.microsoft.azuretools.telemetrywrapper.*;
import com.microsoft.azuretools.utils.NetUtils;

import java.util.Collections;
import java.util.Map;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AzureMySQLService {
private static final AzureMySQLService instance = new AzureMySQLService();
Expand Down Expand Up @@ -56,7 +64,7 @@ public Server createMySQL(final AzureMySQLConfig config) {
// update access from azure services
MySQLMvpModel.FirewallRuleMvpModel.updateAllowAccessFromAzureServices(subscriptionId, server, config.isAllowAccessFromAzureServices());
// update access from local machine
MySQLMvpModel.FirewallRuleMvpModel.updateAllowAccessToLocalMachine(subscriptionId, server, config.isAllowAccessFromLocalMachine());
AzureMySQLService.FirewallRuleService.getInstance().updateAllowAccessToLocalMachine(subscriptionId, server, config.isAllowAccessFromLocalMachine());
return server;
} catch (final RuntimeException e) {
EventUtil.logError(operation, ErrorType.systemError, e, null, null);
Expand All @@ -66,4 +74,74 @@ public Server createMySQL(final AzureMySQLConfig config) {
}
}

public static class FirewallRuleService {

private static final String NAME_PREFIX_ALLOW_ACCESS_TO_LOCAL = "ClientIPAddress_";
private static final Pattern IPADDRESS_PATTERN = Pattern.compile("\\d{1,3}.\\d{1,3}.\\d{1,3}.\\d{1,3}");

private static final FirewallRuleService instance = new FirewallRuleService();

public static FirewallRuleService getInstance() {
return FirewallRuleService.instance;
}

public boolean isAllowAccessFromLocalMachine(final String subscriptionId, final Server server) {
final List<FirewallRuleInner> firewallRules = MySQLMvpModel.FirewallRuleMvpModel.listFirewallRules(subscriptionId, server);
return isAllowAccessFromLocalMachine(firewallRules);
}

public boolean isAllowAccessFromLocalMachine(final List<FirewallRuleInner> firewallRules) {
final String ruleName = getAllAccessFromLocalRuleName();
return firewallRules.stream().filter(e -> StringUtils.equals(e.name(), ruleName)).count() > 0L;
}

public boolean updateAllowAccessToLocalMachine(final String subscriptionId, final Server server, final boolean enable) {
if (enable) {
return enableAllowAccessFromLocalMachine(subscriptionId, server);
} else {
return disableAllowAccessFromLocalMachine(subscriptionId, server);
}
}

public boolean enableAllowAccessFromLocalMachine(final String subscriptionId, final Server server) {
if (isAllowAccessFromLocalMachine(subscriptionId, server)) {
return true;
}
MySQLConnectionUtils.ConnectResult connectResult = MySQLConnectionUtils.connectWithPing(JdbcUrl.mysql(server.fullyQualifiedDomainName()),
server.administratorLogin() + "@" + server.name(), StringUtils.EMPTY);
if (StringUtils.isNotBlank(connectResult.getMessage())) {
Matcher matcher = IPADDRESS_PATTERN.matcher(connectResult.getMessage());
if (matcher.find()) {
final String publicIp = matcher.group();
final String ruleName = getAllAccessFromLocalRuleName();
final FirewallRuleInner firewallRule = new FirewallRuleInner();
firewallRule.withStartIpAddress(publicIp);
firewallRule.withEndIpAddress(publicIp);
final MySQLManager mySQLManager = AuthMethodManager.getInstance().getMySQLManager(subscriptionId);
mySQLManager.firewallRules().inner().createOrUpdate(server.resourceGroupName(), server.name(), ruleName, firewallRule);
return true;
}
}
return false;
}

public boolean disableAllowAccessFromLocalMachine(final String subscriptionId, final Server server) {
if (!isAllowAccessFromLocalMachine(subscriptionId, server)) {
return true;
}
final String ruleName = getAllAccessFromLocalRuleName();
final MySQLManager mySQLManager = AuthMethodManager.getInstance().getMySQLManager(subscriptionId);
mySQLManager.firewallRules().inner().delete(server.resourceGroupName(), server.name(), ruleName);
return true;
}

private String getAllAccessFromLocalRuleName() {
final String hostname = com.intellij.util.net.NetUtils.getLocalHostString();
final String macAddress = NetUtils.getMacAddressString();
final String ruleName = NAME_PREFIX_ALLOW_ACCESS_TO_LOCAL + hostname + macAddress;
return ruleName;
}

}

}
2 changes: 1 addition & 1 deletion Utils/azure-explorer-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<relativePath>../pom.xml</relativePath>
<groupId>com.microsoft.azuretools</groupId>
<artifactId>utils</artifactId>
<version>3.52.0</version>
<version>3.53.0-SNAPSHOT</version>
</parent>
<artifactId>azure-explorer-common</artifactId>
<properties>
Expand Down
2 changes: 1 addition & 1 deletion Utils/azuretools-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<relativePath>../pom.xml</relativePath>
<groupId>com.microsoft.azuretools</groupId>
<artifactId>utils</artifactId>
<version>3.52.0</version>
<version>3.53.0-SNAPSHOT</version>
</parent>
<artifactId>azuretools-core</artifactId>
<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,10 @@
import com.microsoft.azure.management.resources.fluentcore.arm.Region;
import com.microsoft.azuretools.authmanage.AuthMethodManager;
import com.microsoft.azuretools.core.mvp.model.AzureMvpModel;
import lombok.Lombok;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
Expand All @@ -42,7 +36,6 @@ public class MySQLMvpModel {
private static final String NAME_AVAILABILITY_CHECK_TYPE = "Microsoft.DBforMySQL/servers";
private static final String NAME_ALLOW_ACCESS_TO_AZURE_SERVICES = "AllowAllWindowsAzureIps";
private static final String IP_ALLOW_ACCESS_TO_AZURE_SERVICES = "0.0.0.0";
private static final String NAME_PREFIX_ALLOW_ACCESS_TO_LOCAL = "ClientIPAddress_";
private static final List<String> MYSQL_SUPPORTED_REGIONS = Arrays.asList(
"australiacentral", "australiacentral2", "australiaeast", "australiasoutheast", "brazilsouth", "canadacentral", "canadaeast", "centralindia",
"centralus", "eastasia", "eastus2", "eastus", "francecentral", "francesouth", "germanywestcentral", "japaneast", "japanwest", "koreacentral",
Expand Down Expand Up @@ -207,82 +200,6 @@ public static boolean disableAllowAccessFromAzureServices(final String subscript
return true;
}

public static boolean isAllowAccessFromLocalMachine(final String subscriptionId, final Server server) {
final List<FirewallRuleInner> firewallRules = MySQLMvpModel.FirewallRuleMvpModel.listFirewallRules(subscriptionId, server);
return MySQLMvpModel.FirewallRuleMvpModel.isAllowAccessFromLocalMachine(firewallRules);
}

public static boolean isAllowAccessFromLocalMachine(final List<FirewallRuleInner> firewallRules) {
final List<FirewallRuleInner> localFirewallRules = MySQLMvpModel.FirewallRuleMvpModel.getLocalFirewallRules(firewallRules);
return CollectionUtils.isNotEmpty(localFirewallRules);
}

public static boolean updateAllowAccessToLocalMachine(final String subscriptionId, final Server server, final boolean enable) {
if (enable) {
return MySQLMvpModel.FirewallRuleMvpModel.enableAllowAccessFromLocalMachine(subscriptionId, server);
} else {
return MySQLMvpModel.FirewallRuleMvpModel.disableAllowAccessFromLocalMachine(subscriptionId, server);
}
}

public static boolean enableAllowAccessFromLocalMachine(final String subscriptionId, final Server server) {
if (MySQLMvpModel.FirewallRuleMvpModel.isAllowAccessFromLocalMachine(subscriptionId, server)) {
return true;
}
try {
final String publicIp = MySQLMvpModel.FirewallRuleMvpModel.getPublicIp();
final String ruleName = NAME_PREFIX_ALLOW_ACCESS_TO_LOCAL + publicIp.replaceAll("\\.", "-");
final FirewallRuleInner firewallRule = new FirewallRuleInner();
firewallRule.withStartIpAddress(publicIp);
firewallRule.withEndIpAddress(publicIp);
final MySQLManager mySQLManager = AuthMethodManager.getInstance().getMySQLManager(subscriptionId);
mySQLManager.firewallRules().inner().createOrUpdate(server.resourceGroupName(), server.name(), ruleName, firewallRule);
} catch (IOException e) {
Lombok.sneakyThrow(e);
}
return true;
}

public static boolean disableAllowAccessFromLocalMachine(final String subscriptionId, final Server server) {
if (!MySQLMvpModel.FirewallRuleMvpModel.isAllowAccessFromLocalMachine(subscriptionId, server)) {
return true;
}
final MySQLManager mySQLManager = AuthMethodManager.getInstance().getMySQLManager(subscriptionId);
final List<FirewallRuleInner> firewallRules = MySQLMvpModel.FirewallRuleMvpModel.listFirewallRules(subscriptionId, server);
final List<FirewallRuleInner> localFirewallRules = MySQLMvpModel.FirewallRuleMvpModel.getLocalFirewallRules(firewallRules);
localFirewallRules.stream().forEach(e -> {
mySQLManager.firewallRules().inner().delete(server.resourceGroupName(), server.name(), e.name());
});
return true;
}

private static List<FirewallRuleInner> getLocalFirewallRules(final List<FirewallRuleInner> firewallRules) {
try {
final String publicIp = getPublicIp();
if (StringUtils.isBlank(publicIp)) {
return new ArrayList<>();
}
return firewallRules.stream().filter(e -> StringUtils.equals(publicIp, e.startIpAddress()) && StringUtils.equals(publicIp, e.endIpAddress()))
.collect(Collectors.toList());
} catch (IOException e) {
Lombok.sneakyThrow(e);
}
return new ArrayList<>();
}

private static String getPublicIp() throws IOException {
final URL url = new URL("https://ipecho.net/plain");
final HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
String ip;
try (BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), StandardCharsets.UTF_8))) {
while ((ip = in.readLine()) != null) {
if (StringUtils.isNotBlank(ip)) {
break;
}
}
}
return ip;
}
}

private static List<Server> listMySQLServersBySubscriptionId(final String subscriptionId) throws IOException {
Expand Down
Loading