Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion modules/web-console/web-agent/bin/ignite-web-agent.bat
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ if %ERRORLEVEL% equ 0 (
if "%JVM_OPTS%" == "" set JVM_OPTS=-Xms1g -Xmx1g -server -XX:MaxMetaspaceSize=256m
)

set JVM_OPTS=%JVM_OPTS% -Djava.net.useSystemProxies=true
:: https://confluence.atlassian.com/kb/basic-authentication-fails-for-outgoing-proxy-in-java-8u111-909643110.html
set JVM_OPTS=%JVM_OPTS% -Djava.net.useSystemProxies=true -Djdk.http.auth.tunneling.disabledSchemes=

::
:: Final JVM_OPTS for Java 9+ compatibility
Expand Down
3 changes: 2 additions & 1 deletion modules/web-console/web-agent/bin/ignite-web-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ if [ -z "$JVM_OPTS" ] ; then
fi
fi

JVM_OPTS="${JVM_OPTS} -Djava.net.useSystemProxies=true"
# https://confluence.atlassian.com/kb/basic-authentication-fails-for-outgoing-proxy-in-java-8u111-909643110.html
JVM_OPTS="${JVM_OPTS} -Djava.net.useSystemProxies=true -Djdk.http.auth.tunneling.disabledSchemes="

#
# Final JVM_OPTS for Java 9+ compatibility
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@
import java.util.concurrent.CountDownLatch;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
import io.socket.client.Ack;
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
import org.apache.ignite.console.agent.handlers.ClusterListener;
import org.apache.ignite.console.agent.handlers.DatabaseListener;
Expand Down Expand Up @@ -111,36 +111,26 @@ public class AgentLauncher {

ConnectException ce = X.cause(e, ConnectException.class);

if (ce != null)
log.error("Failed to establish connection to server (connection refused).");
if (ce != null) {
log.error("Failed to establish connection to server or missing proxy settings (connection refused).");
log.error("Documentation for proxy configuration can be found here: https://apacheignite-tools.readme.io/docs/getting-started#section-proxy-configuration");
}
else {
Exception ignore = X.cause(e, SSLHandshakeException.class);

if (ignore != null) {
if (X.hasCause(e, SSLHandshakeException.class)) {
log.error("Failed to establish SSL connection to server, due to errors with SSL handshake:", e);
log.error("Add to environment variable JVM_OPTS parameter \"-Dtrust.all=true\" to skip certificate validation in case of using self-signed certificate.");

System.exit(1);
}

ignore = X.cause(e, UnknownHostException.class);

if (ignore != null) {
if (X.hasCause(e, UnknownHostException.class)) {
log.error("Failed to establish connection to server, due to errors with DNS or missing proxy settings.", e);
log.error("Documentation for proxy configuration can be found here: http://apacheignite.readme.io/docs/web-agent#section-proxy-configuration");
log.error("Documentation for proxy configuration can be found here: https://apacheignite-tools.readme.io/docs/getting-started#section-proxy-configuration");

System.exit(1);
}

ignore = X.cause(e, IOException.class);

if (ignore != null && "404".equals(ignore.getMessage())) {
log.error("Failed to receive response from server (connection refused).");

return;
}

if (ignore != null && "407".equals(ignore.getMessage())) {
if (X.hasCause(e, ProxyAuthException.class)) {
log.error("Failed to establish connection to server, due to proxy requires authentication.");

String userName = System.getProperty("https.proxyUsername", System.getProperty("http.proxyUsername"));
Expand All @@ -163,6 +153,14 @@ public class AgentLauncher {
return;
}

IOException ignore = X.cause(e, IOException.class);

if (ignore != null && "404".equals(ignore.getMessage())) {
log.error("Failed to receive response from server (connection refused).");

return;
}

log.error("Connection error.", e);
}
};
Expand Down Expand Up @@ -345,13 +343,14 @@ public static void main(String[] args) throws Exception {

List<String> cipherSuites = cfg.cipherSuites();

OkHttpClient.Builder builder = new OkHttpClient.Builder()
.proxyAuthenticator(new ProxyAuthenticator());

if (
serverTrustAll ||
hasServerTrustStore ||
cfg.serverKeyStore() != null
) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();

X509TrustManager serverTrustMgr = trustManager(
serverTrustAll,
cfg.serverTrustStore(),
Expand All @@ -375,13 +374,14 @@ public static void main(String[] args) throws Exception {
builder.connectionSpecs(sslConnectionSpec(cipherSuites));
}

OkHttpClient sslFactory = builder.build();

opts.callFactory = sslFactory;
opts.webSocketFactory = sslFactory;
opts.secure = true;
}

OkHttpClient okHttpClient = builder.build();

opts.callFactory = okHttpClient;
opts.webSocketFactory = okHttpClient;

final Socket client = IO.socket(uri, opts);

try (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,11 @@ public class AgentUtils {
}

/** */
private static final Ack NOOP_CB = new Ack() {
@Override public void call(Object... args) {
if (args != null && args.length > 0 && args[0] instanceof Throwable)
log.error("Failed to execute request on agent.", (Throwable)args[0]);
else
log.info("Request on agent successfully executed " + Arrays.toString(args));
}
private static final Ack NOOP_CB = args -> {
if (args != null && args.length > 0 && args[0] instanceof Throwable)
log.error("Failed to execute request on agent.", (Throwable)args[0]);
else
log.info("Request on agent successfully executed " + Arrays.toString(args));
};

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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.ignite.console.agent;

import java.io.IOException;

/**
* This class extends {@link IOException} and represents an authentication failure to the proxy.
*/
public class ProxyAuthException extends IOException {
/** */
private static final long serialVersionUID = 0L;

/**
* {@inheritDoc}
*/
public ProxyAuthException(String msg) {
super(msg);
}

/**
* {@inheritDoc}
*/
public ProxyAuthException(String msg, Throwable ex) {
super(msg, ex);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* 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.ignite.console.agent;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.util.List;
import okhttp3.Authenticator;
import okhttp3.Challenge;
import okhttp3.Credentials;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;

import static java.net.Authenticator.RequestorType.PROXY;

/**
* Request interactive proxy credentials.
*
* Configure OkHttp to use {@link OkHttpClient.Builder#proxyAuthenticator(Authenticator)}.
*/
public class ProxyAuthenticator implements Authenticator {
/** Latest credential hash code. */
private int latestCredHashCode = 0;

/** {@inheritDoc} */
@Override public Request authenticate(Route route, Response res) throws IOException {
List<Challenge> challenges = res.challenges();

for (Challenge challenge : challenges) {
if (!"Basic".equalsIgnoreCase(challenge.scheme()))
continue;

Request req = res.request();
HttpUrl url = req.url();
Proxy proxy = route.proxy();

InetSocketAddress proxyAddr = (InetSocketAddress)proxy.address();

PasswordAuthentication auth = java.net.Authenticator.requestPasswordAuthentication(
proxyAddr.getHostName(), proxyAddr.getAddress(), proxyAddr.getPort(),
url.scheme(), challenge.realm(), challenge.scheme(), url.url(), PROXY);

if (auth != null) {
String cred = Credentials.basic(auth.getUserName(), new String(auth.getPassword()), challenge.charset());

if (latestCredHashCode == cred.hashCode()) {
latestCredHashCode = 0;

throw new ProxyAuthException("Failed to authenticate with proxy");
}

latestCredHashCode = cred.hashCode();

return req.newBuilder()
.header("Proxy-Authorization", cred)
.build();
}
}

return null; // No challenges were satisfied!
}
}