mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Persist IP addresses related to VM access via CPVM (#9534)
This commit is contained in:
parent
c94d0abab4
commit
f75a194c09
@ -397,9 +397,8 @@ public class ConsoleProxyResource extends ServerResourceBase implements ServerRe
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String authenticateConsoleAccess(String host, String port, String vmId, String sid, String ticket,
|
public String authenticateConsoleAccess(String host, String port, String vmId, String sid, String ticket,
|
||||||
Boolean isReauthentication, String sessionToken) {
|
Boolean isReauthentication, String sessionToken, String clientAddress) {
|
||||||
|
ConsoleAccessAuthenticationCommand cmd = new ConsoleAccessAuthenticationCommand(host, port, vmId, sid, ticket, sessionToken, clientAddress);
|
||||||
ConsoleAccessAuthenticationCommand cmd = new ConsoleAccessAuthenticationCommand(host, port, vmId, sid, ticket, sessionToken);
|
|
||||||
cmd.setReauthenticating(isReauthentication);
|
cmd.setReauthenticating(isReauthentication);
|
||||||
|
|
||||||
ConsoleProxyAuthenticationResult result = new ConsoleProxyAuthenticationResult();
|
ConsoleProxyAuthenticationResult result = new ConsoleProxyAuthenticationResult();
|
||||||
|
|||||||
@ -44,7 +44,7 @@ public interface ConsoleAccessManager extends Manager, Configurable {
|
|||||||
|
|
||||||
void removeSessions(String[] sessionUuids);
|
void removeSessions(String[] sessionUuids);
|
||||||
|
|
||||||
void acquireSession(String sessionUuid);
|
void acquireSession(String sessionUuid, String clientAddress);
|
||||||
|
|
||||||
String genAccessTicket(String host, String port, String sid, String tag, String sessionUuid);
|
String genAccessTicket(String host, String port, String sid, String tag, String sessionUuid);
|
||||||
String genAccessTicket(String host, String port, String sid, String tag, Date normalizedHashTime, String sessionUuid);
|
String genAccessTicket(String host, String port, String sid, String tag, Date normalizedHashTime, String sessionUuid);
|
||||||
|
|||||||
@ -27,6 +27,7 @@ public class ConsoleAccessAuthenticationCommand extends AgentControlCommand {
|
|||||||
private String _sid;
|
private String _sid;
|
||||||
private String _ticket;
|
private String _ticket;
|
||||||
private String sessionUuid;
|
private String sessionUuid;
|
||||||
|
private String clientAddress;
|
||||||
|
|
||||||
private boolean _isReauthenticating;
|
private boolean _isReauthenticating;
|
||||||
|
|
||||||
@ -35,13 +36,14 @@ public class ConsoleAccessAuthenticationCommand extends AgentControlCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ConsoleAccessAuthenticationCommand(String host, String port, String vmId, String sid, String ticket,
|
public ConsoleAccessAuthenticationCommand(String host, String port, String vmId, String sid, String ticket,
|
||||||
String sessiontkn) {
|
String sessiontkn, String clientAddress) {
|
||||||
_host = host;
|
_host = host;
|
||||||
_port = port;
|
_port = port;
|
||||||
_vmId = vmId;
|
_vmId = vmId;
|
||||||
_sid = sid;
|
_sid = sid;
|
||||||
_ticket = ticket;
|
_ticket = ticket;
|
||||||
sessionUuid = sessiontkn;
|
sessionUuid = sessiontkn;
|
||||||
|
this.clientAddress = clientAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
@ -79,4 +81,12 @@ public class ConsoleAccessAuthenticationCommand extends AgentControlCommand {
|
|||||||
public void setSessionUuid(String sessionUuid) {
|
public void setSessionUuid(String sessionUuid) {
|
||||||
this.sessionUuid = sessionUuid;
|
this.sessionUuid = sessionUuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getClientAddress() {
|
||||||
|
return clientAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientAddress(String clientAddress) {
|
||||||
|
this.clientAddress = clientAddress;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,6 +89,7 @@ import com.cloud.upgrade.dao.Upgrade41810to41900;
|
|||||||
import com.cloud.upgrade.dao.Upgrade41900to41910;
|
import com.cloud.upgrade.dao.Upgrade41900to41910;
|
||||||
import com.cloud.upgrade.dao.Upgrade41910to42000;
|
import com.cloud.upgrade.dao.Upgrade41910to42000;
|
||||||
import com.cloud.upgrade.dao.Upgrade42000to42010;
|
import com.cloud.upgrade.dao.Upgrade42000to42010;
|
||||||
|
import com.cloud.upgrade.dao.Upgrade42010to42100;
|
||||||
import com.cloud.upgrade.dao.Upgrade420to421;
|
import com.cloud.upgrade.dao.Upgrade420to421;
|
||||||
import com.cloud.upgrade.dao.Upgrade421to430;
|
import com.cloud.upgrade.dao.Upgrade421to430;
|
||||||
import com.cloud.upgrade.dao.Upgrade430to440;
|
import com.cloud.upgrade.dao.Upgrade430to440;
|
||||||
@ -232,6 +233,7 @@ public class DatabaseUpgradeChecker implements SystemIntegrityChecker {
|
|||||||
.next("4.19.0.0", new Upgrade41900to41910())
|
.next("4.19.0.0", new Upgrade41900to41910())
|
||||||
.next("4.19.1.0", new Upgrade41910to42000())
|
.next("4.19.1.0", new Upgrade41910to42000())
|
||||||
.next("4.20.0.0", new Upgrade42000to42010())
|
.next("4.20.0.0", new Upgrade42000to42010())
|
||||||
|
.next("4.20.1.0", new Upgrade42010to42100())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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 com.cloud.upgrade.dao;
|
||||||
|
|
||||||
|
import com.cloud.upgrade.SystemVmTemplateRegistration;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.sql.Connection;
|
||||||
|
|
||||||
|
public class Upgrade42010to42100 extends DbUpgradeAbstractImpl implements DbUpgrade, DbUpgradeSystemVmTemplate {
|
||||||
|
private SystemVmTemplateRegistration systemVmTemplateRegistration;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getUpgradableVersionRange() {
|
||||||
|
return new String[] {"4.20.1.0", "4.21.0.0"};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUpgradedVersion() {
|
||||||
|
return "4.21.0.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRollingUpgrade() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream[] getPrepareScripts() {
|
||||||
|
final String scriptFile = "META-INF/db/schema-42010to42100.sql";
|
||||||
|
final InputStream script = Thread.currentThread().getContextClassLoader().getResourceAsStream(scriptFile);
|
||||||
|
if (script == null) {
|
||||||
|
throw new CloudRuntimeException("Unable to find " + scriptFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new InputStream[] {script};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void performDataMigration(Connection conn) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream[] getCleanupScripts() {
|
||||||
|
final String scriptFile = "META-INF/db/schema-42010to42100-cleanup.sql";
|
||||||
|
final InputStream script = Thread.currentThread().getContextClassLoader().getResourceAsStream(scriptFile);
|
||||||
|
if (script == null) {
|
||||||
|
throw new CloudRuntimeException("Unable to find " + scriptFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new InputStream[] {script};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initSystemVmTemplateRegistration() {
|
||||||
|
systemVmTemplateRegistration = new SystemVmTemplateRegistration("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateSystemVmTemplates(Connection conn) {
|
||||||
|
logger.debug("Updating System Vm template IDs");
|
||||||
|
initSystemVmTemplateRegistration();
|
||||||
|
try {
|
||||||
|
systemVmTemplateRegistration.updateSystemVmTemplates(conn);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CloudRuntimeException("Failed to find / register SystemVM template(s)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -64,6 +64,12 @@ public class ConsoleSessionVO {
|
|||||||
@Column(name = "removed")
|
@Column(name = "removed")
|
||||||
private Date removed;
|
private Date removed;
|
||||||
|
|
||||||
|
@Column(name = "console_endpoint_creator_address")
|
||||||
|
private String consoleEndpointCreatorAddress;
|
||||||
|
|
||||||
|
@Column(name = "client_address")
|
||||||
|
private String clientAddress;
|
||||||
|
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -135,4 +141,20 @@ public class ConsoleSessionVO {
|
|||||||
public void setAcquired(Date acquired) {
|
public void setAcquired(Date acquired) {
|
||||||
this.acquired = acquired;
|
this.acquired = acquired;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConsoleEndpointCreatorAddress() {
|
||||||
|
return consoleEndpointCreatorAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConsoleEndpointCreatorAddress(String consoleEndpointCreatorAddress) {
|
||||||
|
this.consoleEndpointCreatorAddress = consoleEndpointCreatorAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientAddress() {
|
||||||
|
return clientAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientAddress(String clientAddress) {
|
||||||
|
this.clientAddress = clientAddress;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ public interface ConsoleSessionDao extends GenericDao<ConsoleSessionVO, Long> {
|
|||||||
|
|
||||||
int expungeSessionsOlderThanDate(Date date);
|
int expungeSessionsOlderThanDate(Date date);
|
||||||
|
|
||||||
void acquireSession(String sessionUuid);
|
void acquireSession(String sessionUuid, String clientAddress);
|
||||||
|
|
||||||
int expungeByVmList(List<Long> vmIds, Long batchSize);
|
int expungeByVmList(List<Long> vmIds, Long batchSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,9 +62,10 @@ public class ConsoleSessionDaoImpl extends GenericDaoBase<ConsoleSessionVO, Long
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acquireSession(String sessionUuid) {
|
public void acquireSession(String sessionUuid, String clientAddress) {
|
||||||
ConsoleSessionVO consoleSessionVO = findByUuid(sessionUuid);
|
ConsoleSessionVO consoleSessionVO = findByUuid(sessionUuid);
|
||||||
consoleSessionVO.setAcquired(new Date());
|
consoleSessionVO.setAcquired(new Date());
|
||||||
|
consoleSessionVO.setClientAddress(clientAddress);
|
||||||
update(consoleSessionVO.getId(), consoleSessionVO);
|
update(consoleSessionVO.getId(), consoleSessionVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
-- 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.
|
||||||
|
|
||||||
|
--;
|
||||||
|
-- Schema upgrade cleanup from 4.20.1.0 to 4.21.0.0
|
||||||
|
--;
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
-- 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.
|
||||||
|
|
||||||
|
--;
|
||||||
|
-- Schema upgrade from 4.20.1.0 to 4.21.0.0
|
||||||
|
--;
|
||||||
|
|
||||||
|
-- Add console_endpoint_creator_address column to cloud.console_session table
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.console_session', 'console_endpoint_creator_address', 'VARCHAR(45)');
|
||||||
|
|
||||||
|
-- Add client_address column to cloud.console_session table
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.console_session', 'client_address', 'VARCHAR(45)');
|
||||||
@ -89,6 +89,7 @@ public abstract class AgentHookBase implements AgentHook {
|
|||||||
|
|
||||||
String ticketInUrl = cmd.getTicket();
|
String ticketInUrl = cmd.getTicket();
|
||||||
String sessionUuid = cmd.getSessionUuid();
|
String sessionUuid = cmd.getSessionUuid();
|
||||||
|
String clientAddress = cmd.getClientAddress();
|
||||||
|
|
||||||
if (ticketInUrl == null) {
|
if (ticketInUrl == null) {
|
||||||
logger.error("Access ticket could not be found, you could be running an old version of console proxy. vmId: " + cmd.getVmId());
|
logger.error("Access ticket could not be found, you could be running an old version of console proxy. vmId: " + cmd.getVmId());
|
||||||
@ -111,7 +112,7 @@ public abstract class AgentHookBase implements AgentHook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(String.format("Acquiring session [%s] as it was just used.", sessionUuid));
|
logger.debug(String.format("Acquiring session [%s] as it was just used.", sessionUuid));
|
||||||
consoleAccessManager.acquireSession(sessionUuid);
|
consoleAccessManager.acquireSession(sessionUuid, clientAddress);
|
||||||
|
|
||||||
if (!ticket.equals(ticketInUrl)) {
|
if (!ticket.equals(ticketInUrl)) {
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
|
|||||||
@ -248,8 +248,8 @@ public class ConsoleAccessManagerImpl extends ManagerBase implements ConsoleAcce
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acquireSession(String sessionUuid) {
|
public void acquireSession(String sessionUuid, String clientAddress) {
|
||||||
consoleSessionDao.acquireSession(sessionUuid);
|
consoleSessionDao.acquireSession(sessionUuid, clientAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean checkSessionPermission(VirtualMachine vm, Account account) {
|
protected boolean checkSessionPermission(VirtualMachine vm, Account account) {
|
||||||
@ -389,7 +389,7 @@ public class ConsoleAccessManagerImpl extends ManagerBase implements ConsoleAcce
|
|||||||
String url = generateConsoleAccessUrl(rootUrl, param, token, vncPort, vm, hostVo, details);
|
String url = generateConsoleAccessUrl(rootUrl, param, token, vncPort, vm, hostVo, details);
|
||||||
|
|
||||||
logger.debug("Adding allowed session: " + sessionUuid);
|
logger.debug("Adding allowed session: " + sessionUuid);
|
||||||
persistConsoleSession(sessionUuid, vm.getId(), hostVo.getId());
|
persistConsoleSession(sessionUuid, vm.getId(), hostVo.getId(), addr);
|
||||||
managementServer.setConsoleAccessForVm(vm.getId(), sessionUuid);
|
managementServer.setConsoleAccessForVm(vm.getId(), sessionUuid);
|
||||||
|
|
||||||
ConsoleEndpoint consoleEndpoint = new ConsoleEndpoint(true, url);
|
ConsoleEndpoint consoleEndpoint = new ConsoleEndpoint(true, url);
|
||||||
@ -403,13 +403,14 @@ public class ConsoleAccessManagerImpl extends ManagerBase implements ConsoleAcce
|
|||||||
return consoleEndpoint;
|
return consoleEndpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void persistConsoleSession(String sessionUuid, long instanceId, long hostId) {
|
protected void persistConsoleSession(String sessionUuid, long instanceId, long hostId, String consoleEndpointCreatorAddress) {
|
||||||
ConsoleSessionVO consoleSessionVo = new ConsoleSessionVO();
|
ConsoleSessionVO consoleSessionVo = new ConsoleSessionVO();
|
||||||
consoleSessionVo.setUuid(sessionUuid);
|
consoleSessionVo.setUuid(sessionUuid);
|
||||||
consoleSessionVo.setAccountId(CallContext.current().getCallingAccountId());
|
consoleSessionVo.setAccountId(CallContext.current().getCallingAccountId());
|
||||||
consoleSessionVo.setUserId(CallContext.current().getCallingUserId());
|
consoleSessionVo.setUserId(CallContext.current().getCallingUserId());
|
||||||
consoleSessionVo.setInstanceId(instanceId);
|
consoleSessionVo.setInstanceId(instanceId);
|
||||||
consoleSessionVo.setHostId(hostId);
|
consoleSessionVo.setHostId(hostId);
|
||||||
|
consoleSessionVo.setConsoleEndpointCreatorAddress(consoleEndpointCreatorAddress);
|
||||||
consoleSessionDao.persist(consoleSessionVo);
|
consoleSessionDao.persist(consoleSessionVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -183,7 +183,6 @@ public class ConsoleProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ConsoleProxyAuthenticationResult authenticateConsoleAccess(ConsoleProxyClientParam param, boolean reauthentication) {
|
public static ConsoleProxyAuthenticationResult authenticateConsoleAccess(ConsoleProxyClientParam param, boolean reauthentication) {
|
||||||
|
|
||||||
ConsoleProxyAuthenticationResult authResult = new ConsoleProxyAuthenticationResult();
|
ConsoleProxyAuthenticationResult authResult = new ConsoleProxyAuthenticationResult();
|
||||||
authResult.setSuccess(true);
|
authResult.setSuccess(true);
|
||||||
authResult.setReauthentication(reauthentication);
|
authResult.setReauthentication(reauthentication);
|
||||||
@ -227,7 +226,7 @@ public class ConsoleProxy {
|
|||||||
try {
|
try {
|
||||||
result =
|
result =
|
||||||
authMethod.invoke(ConsoleProxy.context, param.getClientHostAddress(), String.valueOf(param.getClientHostPort()), param.getClientTag(),
|
authMethod.invoke(ConsoleProxy.context, param.getClientHostAddress(), String.valueOf(param.getClientHostPort()), param.getClientTag(),
|
||||||
param.getClientHostPassword(), param.getTicket(), reauthentication, param.getSessionUuid());
|
param.getClientHostPassword(), param.getTicket(), reauthentication, param.getSessionUuid(), param.getClientIp());
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
LOGGER.error("Unable to invoke authenticateConsoleAccess due to IllegalAccessException" + " for vm: " + param.getClientTag(), e);
|
LOGGER.error("Unable to invoke authenticateConsoleAccess due to IllegalAccessException" + " for vm: " + param.getClientTag(), e);
|
||||||
authResult.setSuccess(false);
|
authResult.setSuccess(false);
|
||||||
@ -301,7 +300,7 @@ public class ConsoleProxy {
|
|||||||
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||||
Class<?> contextClazz = loader.loadClass("com.cloud.agent.resource.consoleproxy.ConsoleProxyResource");
|
Class<?> contextClazz = loader.loadClass("com.cloud.agent.resource.consoleproxy.ConsoleProxyResource");
|
||||||
authMethod = contextClazz.getDeclaredMethod("authenticateConsoleAccess", String.class, String.class,
|
authMethod = contextClazz.getDeclaredMethod("authenticateConsoleAccess", String.class, String.class,
|
||||||
String.class, String.class, String.class, Boolean.class, String.class);
|
String.class, String.class, String.class, Boolean.class, String.class, String.class);
|
||||||
reportMethod = contextClazz.getDeclaredMethod("reportLoadInfo", String.class);
|
reportMethod = contextClazz.getDeclaredMethod("reportLoadInfo", String.class);
|
||||||
ensureRouteMethod = contextClazz.getDeclaredMethod("ensureRoute", String.class);
|
ensureRouteMethod = contextClazz.getDeclaredMethod("ensureRoute", String.class);
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user