Skip to content

Commit 27e1739

Browse files
authored
Merge pull request #2612 from digma-ai/jaeger-auth-support
Jaeger auth support
2 parents c1697b5 + 4d3640e commit 27e1739

File tree

10 files changed

+277
-83
lines changed

10 files changed

+277
-83
lines changed

src/main/java/org/digma/intellij/plugin/jaegerui/JaegerUIConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ public interface JaegerUIConstants {
55
String JAEGER_UI_DOMAIN_NAME = "jaegerui";
66
String JAEGER_UI_SCHEMA = "http";
77
String JAEGER_UI_URL = JAEGER_UI_SCHEMA + "://" + JAEGER_UI_DOMAIN_NAME + "/index.html";
8+
String JAEGER_API_URL = JAEGER_UI_SCHEMA + "://" + JAEGER_UI_DOMAIN_NAME;
89
String JAEGER_UI_RESOURCE_FOLDER_NAME = "/webview/jaegerui";
910
String JAEGER_UI_INDEX_TEMPLATE_NAME = "jaegeruitemplate.ftl";
1011

src/main/java/org/digma/intellij/plugin/jaegerui/JaegerUiIndexTemplateBuilder.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111

1212
public class JaegerUiIndexTemplateBuilder extends BaseIndexTemplateBuilder {
1313

14-
private static final String JAEGER_URL_PARAM_NAME = "jaeger_url";
14+
private static final String JAEGER_URL_FOR_LINK_PARAM_NAME = "BASE_URL_STRING_TO_OPEN_LINKS";
15+
private static final String JAEGER_URL_FOR_API_PARAM_NAME = "BASE_URL_STRING_TO_FORWARD_API_CALLS";
1516
private static final String JAEGER_QUERY_URL_CHANGED_FROM_DEFAULT_PARAM_NAME = "isUserChangedJaegerQueryUrl";
1617
private static final String INITIAL_ROUTE_PARAM_NAME = "initial_route";
1718

@@ -27,7 +28,8 @@ public JaegerUiIndexTemplateBuilder(JaegerUIVirtualFile file) {
2728
public void addAppSpecificEnvVariable(@NotNull Project project, @NotNull Map<String, Object> data) {
2829

2930
var didUserChangeJaegerQueryUrl = !(SettingsState.DEFAULT_JAEGER_QUERY_URL.equalsIgnoreCase(SettingsState.getInstance().getJaegerQueryUrl()));
30-
data.put(JAEGER_URL_PARAM_NAME, jaegerUIVirtualFile.getJaegerBaseUrl());
31+
data.put(JAEGER_URL_FOR_LINK_PARAM_NAME, jaegerUIVirtualFile.getJaegerBaseUrl());
32+
data.put(JAEGER_URL_FOR_API_PARAM_NAME, JaegerUIConstants.JAEGER_API_URL);
3133
data.put(JAEGER_QUERY_URL_CHANGED_FROM_DEFAULT_PARAM_NAME, String.valueOf(didUserChangeJaegerQueryUrl));
3234

3335

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package org.digma.intellij.plugin.jaegerui;
2+
3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.intellij.openapi.diagnostic.Logger;
5+
import com.posthog.java.shaded.okhttp3.*;
6+
import org.cef.callback.CefCallback;
7+
import org.cef.handler.CefResourceHandler;
8+
import org.cef.misc.*;
9+
import org.cef.network.*;
10+
import org.digma.intellij.plugin.auth.account.CredentialsHolder;
11+
import org.digma.intellij.plugin.common.JsonUtilsKt;
12+
import org.digma.intellij.plugin.log.Log;
13+
import org.digma.intellij.plugin.ui.jcef.JCefException;
14+
import org.jetbrains.annotations.*;
15+
16+
import java.net.*;
17+
import java.util.*;
18+
import java.util.stream.Collectors;
19+
20+
public class JaegerUiProxyResourceHandler implements CefResourceHandler {
21+
22+
private static final Logger LOGGER = Logger.getInstance(JaegerUiProxyResourceHandler.class);
23+
private final OkHttpClient okHttpClient;
24+
private final URL jaegerQueryUrl;
25+
private Response okHttp3Response;
26+
27+
public JaegerUiProxyResourceHandler(URL jaegerQueryUrl){
28+
this.jaegerQueryUrl = jaegerQueryUrl;
29+
okHttpClient = new OkHttpClient.Builder().build();
30+
}
31+
32+
public static boolean isJaegerQueryCall(URL url) {
33+
return url.getPath().startsWith("/api/");
34+
}
35+
36+
@Override
37+
public boolean processRequest(CefRequest cefRequest, CefCallback callback) {
38+
try {
39+
var apiUrl = getApiUrl(cefRequest);
40+
var headers = getHeaders(cefRequest);
41+
var body = getBody(cefRequest, headers);
42+
var okHttp3Request = new Request.Builder()
43+
.method(cefRequest.getMethod(), body)
44+
.headers(Headers.of(headers))
45+
.url(apiUrl)
46+
.build();
47+
okHttp3Response = okHttpClient.newCall(okHttp3Request).execute();
48+
var authFailureReason = getAuthFailureReason(okHttp3Response);
49+
if (authFailureReason != null && !authFailureReason.isBlank()) {
50+
okHttp3Response = buildAuthFailureResponse(okHttp3Request, okHttp3Response, authFailureReason);
51+
}
52+
callback.Continue();
53+
return true;
54+
} catch (Exception e) {
55+
Log.warnWithException(LOGGER, e, "processRequest failed");
56+
callback.cancel();
57+
return false;
58+
}
59+
}
60+
61+
@Nullable
62+
private static String getAuthFailureReason(Response response){
63+
final var headerName = "X-Auth-Fail-Reason";
64+
var reason = response.header(headerName);
65+
if(reason == null && response.priorResponse() != null)
66+
reason = response.priorResponse().header(headerName);
67+
return reason;
68+
}
69+
70+
private static Response buildAuthFailureResponse(Request okHttp3Request, Response response, String authFailureReason) {
71+
return new Response(
72+
okHttp3Request,
73+
response.protocol(),
74+
"Authentication failed", 401,
75+
response.handshake(),
76+
Headers.of(),
77+
ResponseBody.create(
78+
"Authentication failed: " + authFailureReason,
79+
MediaType.parse("text/html")
80+
),
81+
null, null, null,
82+
0, 0, null);
83+
}
84+
85+
@NotNull
86+
private URL getApiUrl(CefRequest cefRequest) throws MalformedURLException {
87+
var requestUrl = new URL(cefRequest.getURL());
88+
return new URL(jaegerQueryUrl.getProtocol(), jaegerQueryUrl.getHost(), jaegerQueryUrl.getPort(),
89+
requestUrl.getPath() + "?" + requestUrl.getQuery());
90+
}
91+
92+
@NotNull
93+
private static HashMap<String, String> getHeaders(CefRequest cefRequest) throws JsonProcessingException {
94+
var headers = new HashMap<String, String>();
95+
cefRequest.getHeaderMap(headers);
96+
var digmaCredentials = CredentialsHolder.INSTANCE.getDigmaCredentials();
97+
if (digmaCredentials != null){
98+
var digmaCredentialsJson = JsonUtilsKt.objectToJson(digmaCredentials);
99+
headers.put("Cookie", "auth_token="+digmaCredentialsJson);
100+
}
101+
return headers;
102+
}
103+
104+
@Nullable
105+
private static RequestBody getBody(CefRequest cefRequest, HashMap<String, String> headers) {
106+
return cefRequest.getPostData() != null
107+
? RequestBody.create(cefRequest.getPostData().toString(), MediaType.parse(headers.get("Content-Type")))
108+
: null;
109+
}
110+
111+
@Override
112+
public void getResponseHeaders(CefResponse cefResponse, IntRef responseLength, StringRef redirectUrl) {
113+
if (okHttp3Response == null)
114+
return;
115+
116+
cefResponse.setStatus(okHttp3Response.code());
117+
var headersMap = okHttp3Response.headers().names().stream().collect(Collectors.toMap(s -> s, okHttp3Response::header));
118+
cefResponse.setHeaderMap(headersMap);
119+
120+
var body = okHttp3Response.body();
121+
if (body != null){
122+
cefResponse.setMimeType(body.contentType().toString());
123+
responseLength.set((int)body.contentLength());
124+
}
125+
}
126+
127+
@Override
128+
public boolean readResponse(byte[] dataOut, int bytesToRead, IntRef bytesRead, CefCallback cefCallback) {
129+
try{
130+
var inputStream = okHttp3Response.body().byteStream();
131+
var read = inputStream.read(dataOut, 0, bytesToRead);
132+
if (read == -1) {
133+
bytesRead.set(0);
134+
inputStream.close();
135+
return false;
136+
}
137+
bytesRead.set(read);
138+
return true;
139+
} catch (Exception e) {
140+
Log.warnWithException(LOGGER, e, "exception readResponse");
141+
throw new JCefException(e);
142+
}
143+
}
144+
145+
@Override
146+
public void cancel() {
147+
okHttp3Response.close();
148+
}
149+
}

src/main/java/org/digma/intellij/plugin/jaegerui/JaegerUiSchemeHandlerFactory.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
11
package org.digma.intellij.plugin.jaegerui;
22

3+
import com.intellij.openapi.diagnostic.Logger;
4+
import com.intellij.openapi.project.Project;
35
import org.cef.browser.CefBrowser;
46
import org.cef.handler.CefResourceHandler;
7+
import org.digma.intellij.plugin.log.Log;
8+
import org.digma.intellij.plugin.settings.SettingsState;
59
import org.digma.intellij.plugin.ui.jcef.BaseSchemeHandlerFactory;
6-
import org.jetbrains.annotations.NotNull;
10+
import org.jetbrains.annotations.*;
11+
12+
import java.net.*;
713

814
import static org.digma.intellij.plugin.jaegerui.JaegerUIConstants.JAEGER_UI_SCHEMA;
915

1016
public class JaegerUiSchemeHandlerFactory extends BaseSchemeHandlerFactory {
1117

18+
private static final Logger LOGGER = Logger.getInstance(JaegerUiSchemeHandlerFactory.class);
19+
20+
@Nullable
21+
@Override
22+
public CefResourceHandler createProxyHandler(@NotNull Project project, @NotNull URL url) {
23+
var jaegerQueryUrl = GetJaegerQueryUrlOrNull();
24+
if (jaegerQueryUrl != null &&
25+
JaegerUiProxyResourceHandler.isJaegerQueryCall(url)) {
26+
return new JaegerUiProxyResourceHandler(jaegerQueryUrl);
27+
}
28+
return null;
29+
}
1230

1331
@NotNull
1432
@Override
@@ -37,4 +55,17 @@ public String getDomain() {
3755
public String getResourceFolderName() {
3856
return JaegerUIConstants.JAEGER_UI_RESOURCE_FOLDER_NAME;
3957
}
58+
59+
private static URL GetJaegerQueryUrlOrNull(){
60+
var urlStr = SettingsState.getInstance().getJaegerQueryUrl();
61+
if(urlStr == null)
62+
return null;
63+
64+
try {
65+
return new URL(urlStr);
66+
} catch (MalformedURLException e) {
67+
Log.warnWithException(LOGGER, e, "JaegerQueryUrl parsing failed");
68+
}
69+
return null;
70+
}
4071
}

src/main/kotlin/org/digma/intellij/plugin/ui/jcef/BaseSchemeHandlerFactory.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.digma.intellij.plugin.ui.jcef
22

33
import com.intellij.openapi.diagnostic.Logger
4+
import com.intellij.openapi.project.Project
45
import org.cef.browser.CefBrowser
56
import org.cef.browser.CefFrame
67
import org.cef.callback.CefSchemeHandlerFactory
@@ -39,16 +40,14 @@ abstract class BaseSchemeHandlerFactory : CefSchemeHandlerFactory {
3940
val url = getUrl(request)
4041

4142
if (url != null) {
42-
4343
val host = url.host
4444
val file = url.file
4545

46-
47-
if (ApiProxyResourceHandler.isApiProxyCall(url)) {
48-
return ApiProxyResourceHandler(project)
46+
val proxyHandler = createProxyHandler(project, url)
47+
if (proxyHandler != null) {
48+
return proxyHandler
4949
}
5050

51-
5251
if (getDomain() == host && getSchema() == schemeName) {
5352
var resourceName = getResourceFolderName() + file
5453
var resource = javaClass.getResource(resourceName)
@@ -73,7 +72,9 @@ abstract class BaseSchemeHandlerFactory : CefSchemeHandlerFactory {
7372
}
7473
}
7574

76-
75+
protected open fun createProxyHandler(project: Project, url: URL): CefResourceHandler?{
76+
return null
77+
}
7778
abstract fun createResourceHandler(resourceName: String, resourceExists: Boolean, browser: CefBrowser): CefResourceHandler
7879
abstract fun getSchema(): String
7980
abstract fun getDomain(): String

src/main/kotlin/org/digma/intellij/plugin/ui/mainapp/MainAppSchemeHandlerFactory.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
package org.digma.intellij.plugin.ui.mainapp
22

3+
import com.intellij.openapi.project.Project
34
import org.cef.browser.CefBrowser
45
import org.cef.handler.CefResourceHandler
6+
import org.digma.intellij.plugin.ui.jcef.ApiProxyResourceHandler
57
import org.digma.intellij.plugin.ui.jcef.BaseSchemeHandlerFactory
8+
import java.net.URL
69

710
class MainAppSchemeHandlerFactory : BaseSchemeHandlerFactory() {
11+
override fun createProxyHandler(project: Project, url: URL): CefResourceHandler? {
12+
if (ApiProxyResourceHandler.isApiProxyCall(url)) {
13+
return ApiProxyResourceHandler(project)
14+
}
15+
return null
16+
}
817

918
override fun createResourceHandler(resourceName: String, resourceExists: Boolean, browser: CefBrowser): CefResourceHandler {
1019
return if (resourceExists) {

src/main/resources/webview/jaegerui/index.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
window.global = {};
4040
</script>
4141
<script>
42+
window.baseUrl;
4243
window.apiBaseUrl;
4344
window.initialRoutePath;
4445
window.embeddedMode;
@@ -48,7 +49,7 @@
4849
window.platform;
4950
window.isLoggingEnabled;
5051
</script>
51-
<script type="module" crossorigin src="./static/index-7d2ffb6b.js"></script>
52+
<script type="module" crossorigin src="./static/index-a01b010b.js"></script>
5253
<link rel="stylesheet" href="./static/index-3c425a02.css">
5354
<script type="module">import.meta.url;import("_").catch(()=>1);async function* g(){};window.__vite_is_modern_browser=true;</script>
5455
<script type="module">!function(){if(window.__vite_is_modern_browser)return;console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))},document.body.appendChild(n)}();</script>
@@ -63,6 +64,6 @@
6364

6465
<script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
6566
<script nomodule crossorigin id="vite-legacy-polyfill" src="./static/polyfills-legacy-9486af1f.js"></script>
66-
<script nomodule crossorigin id="vite-legacy-entry" data-src="./static/index-legacy-1ca9c6f5.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
67+
<script nomodule crossorigin id="vite-legacy-entry" data-src="./static/index-legacy-7a251ba3.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
6768
</body>
6869
</html>

src/main/resources/webview/jaegerui/jaegeruitemplate.ftl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@
4040
</script>
4141
<script>
4242
@GLOBAL_ENV_VARS@
43-
44-
window.apiBaseUrl = "${jaeger_url}";
43+
window.baseUrl = "${BASE_URL_STRING_TO_OPEN_LINKS}";
44+
window.apiBaseUrl = "${BASE_URL_STRING_TO_FORWARD_API_CALLS}";
4545
window.initialRoutePath = "${initial_route}";
4646
window.embeddedMode = true;
4747
window.isUserDefinedJaegerQueryURL = ${isUserChangedJaegerQueryUrl};
4848
window.staticPath;
4949
window.enableZoomControls = true;
5050
</script>
51-
<script type="module" crossorigin src="./static/index-7d2ffb6b.js"></script>
51+
<script type="module" crossorigin src="./static/index-a01b010b.js"></script>
5252
<link rel="stylesheet" href="./static/index-3c425a02.css">
5353
<script type="module">import.meta.url;import("_").catch(()=>1);async function* g(){};window.__vite_is_modern_browser=true;</script>
5454
<script type="module">!function(){if(window.__vite_is_modern_browser)return;console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))},document.body.appendChild(n)}();</script>
@@ -63,6 +63,6 @@
6363

6464
<script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
6565
<script nomodule crossorigin id="vite-legacy-polyfill" src="./static/polyfills-legacy-9486af1f.js"></script>
66-
<script nomodule crossorigin id="vite-legacy-entry" data-src="./static/index-legacy-1ca9c6f5.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
66+
<script nomodule crossorigin id="vite-legacy-entry" data-src="./static/index-legacy-7a251ba3.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
6767
</body>
6868
</html>

src/main/resources/webview/jaegerui/static/index-7d2ffb6b.js renamed to src/main/resources/webview/jaegerui/static/index-a01b010b.js

Lines changed: 60 additions & 60 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/resources/webview/jaegerui/static/index-legacy-1ca9c6f5.js renamed to src/main/resources/webview/jaegerui/static/index-legacy-7a251ba3.js

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)