This is an automated email from the ASF dual-hosted git repository. marat pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
The following commit(s) were added to refs/heads/main by this push: new e338af36 Fix #938, Fix #807 e338af36 is described below commit e338af369ab6f4f2628680c9ee3d6e244b4ca637 Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Wed Nov 29 14:17:56 2023 -0500 Fix #938, Fix #807 --- .../org/apache/camel/karavan/api/AuthResource.java | 8 ++--- .../camel/karavan/api/ComponentResources.java | 3 +- .../camel/karavan/api/InfrastructureResource.java | 6 ++-- .../apache/camel/karavan/api/KameletResources.java | 12 +++---- .../camel/karavan/docker/DockerForGitea.java | 4 --- .../camel/karavan/docker/DockerForKaravan.java | 2 +- .../apache/camel/karavan/docker/DockerService.java | 26 +++++++++----- .../apache/camel/karavan/service/AuthService.java | 6 +++- .../camel/karavan/service/KaravanService.java | 4 +-- .../src/main/resources/application.properties | 15 +++++--- .../karavan-app/src/main/webui/package-lock.json | 25 ++++++++----- .../karavan-app/src/main/webui/package.json | 2 +- .../src/main/webui/src/api/KaravanApi.tsx | 41 ++++++---------------- .../karavan-app/src/main/webui/src/api/SsoApi.tsx | 5 +-- 14 files changed, 80 insertions(+), 79 deletions(-) diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java index ed067a60..2c2ca0f7 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/AuthResource.java @@ -16,18 +16,16 @@ */ package org.apache.camel.karavan.api; -import org.apache.camel.karavan.infinispan.InfinispanService; -import org.apache.camel.karavan.kubernetes.KubernetesService; -import org.apache.camel.karavan.service.AuthService; - import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import org.apache.camel.karavan.infinispan.InfinispanService; +import org.apache.camel.karavan.kubernetes.KubernetesService; +import org.apache.camel.karavan.service.AuthService; import org.apache.camel.karavan.service.ProjectService; -import org.apache.camel.karavan.shared.Configuration; import org.eclipse.microprofile.health.HealthCheckResponse; import java.util.List; diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ComponentResources.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ComponentResources.java index a42d1354..4388b4e4 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ComponentResources.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ComponentResources.java @@ -16,13 +16,12 @@ */ package org.apache.camel.karavan.api; -import org.apache.camel.karavan.code.CodeService; - import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; +import org.apache.camel.karavan.code.CodeService; @Path("/api/component") public class ComponentResources { diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java index 1385c384..0f3c2143 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java @@ -64,9 +64,9 @@ public class InfrastructureResource { @Path("/deployment/{env}") public List<DeploymentStatus> getDeploymentStatusesByEnv(@PathParam("env") String env) throws Exception { if (infinispanService.isReady()) { - return infinispanService.getDeploymentStatuses(env).stream() - .sorted(Comparator.comparing(DeploymentStatus::getProjectId)) - .collect(Collectors.toList()); + return infinispanService.getDeploymentStatuses(env).stream() + .sorted(Comparator.comparing(DeploymentStatus::getProjectId)) + .collect(Collectors.toList()); } else { return List.of(); } diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java index 6c419e88..6ae78b87 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/KameletResources.java @@ -16,17 +16,17 @@ */ package org.apache.camel.karavan.api; -import org.apache.camel.karavan.infinispan.InfinispanService; -import org.apache.camel.karavan.infinispan.model.Project; -import org.apache.camel.karavan.infinispan.model.ProjectFile; -import org.apache.camel.karavan.code.CodeService; -import org.yaml.snakeyaml.Yaml; - import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; +import org.apache.camel.karavan.code.CodeService; +import org.apache.camel.karavan.infinispan.InfinispanService; +import org.apache.camel.karavan.infinispan.model.Project; +import org.apache.camel.karavan.infinispan.model.ProjectFile; +import org.yaml.snakeyaml.Yaml; + import java.util.List; import java.util.stream.Collectors; diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java index 407e0baa..1e640240 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForGitea.java @@ -22,7 +22,6 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import org.apache.camel.karavan.code.CodeService; import org.apache.camel.karavan.git.GitService; -import org.apache.camel.karavan.git.GiteaService; import org.apache.camel.karavan.git.model.GitConfig; import org.apache.camel.karavan.infinispan.model.ContainerStatus; import org.jboss.logging.Logger; @@ -37,9 +36,6 @@ public class DockerForGitea { @Inject DockerService dockerService; - @Inject - GiteaService giteaService; - @Inject GitService gitService; diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java index 5808c119..54c31973 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java @@ -55,7 +55,7 @@ public class DockerForKaravan { Map<String, String> volumes = getMavenVolumes(); Container c = createDevmodeContainer(projectId, jBangOptions, ports, volumes); dockerService.runContainer(projectId); - dockerService.copyFiles(c.getId(), "/karavan/code", files); + dockerService.copyFiles(c.getId(), "/karavan/code", files, true); } protected Container createDevmodeContainer(String projectId, String jBangOptions, Map<Integer, Integer> ports, Map<String, String> volumes) throws InterruptedException { diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java index 38a554aa..00389096 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java @@ -154,13 +154,21 @@ public class DockerService extends DockerServiceUtils { return stats; } - public Container createContainerFromCompose(DockerComposeService compose, ContainerStatus.ContainerType type) throws InterruptedException { + public Container createContainerFromCompose(DockerComposeService compose, ContainerStatus.ContainerType type, String... command) throws InterruptedException { + return createContainerFromCompose(compose, type, Map.of(), command); + } + + public Container createContainerFromCompose(DockerComposeService compose, ContainerStatus.ContainerType type, Map<String, String> volumes, String... command) throws InterruptedException { Map<String,String> labels = new HashMap<>(); labels.put(LABEL_TYPE, type.name()); - return createContainerFromCompose(compose, labels); + return createContainerFromCompose(compose, labels, volumes, command); + } + + public Container createContainerFromCompose(DockerComposeService compose, Map<String, String> labels, String... command) throws InterruptedException { + return createContainerFromCompose(compose, labels, Map.of(), command); } - public Container createContainerFromCompose(DockerComposeService compose, Map<String, String> labels) throws InterruptedException { + public Container createContainerFromCompose(DockerComposeService compose, Map<String, String> labels, Map<String, String> volumes, String... command) throws InterruptedException { List<Container> containers = findContainer(compose.getContainer_name()); if (containers.isEmpty()) { HealthCheck healthCheck = getHealthCheck(compose.getHealthcheck()); @@ -176,7 +184,7 @@ public class DockerService extends DockerServiceUtils { } return createContainer(compose.getContainer_name(), compose.getImage(), - env, compose.getPortsMap(), healthCheck, labels, Map.of(), networkName, restartPolicy); + env, compose.getPortsMap(), healthCheck, labels, volumes, networkName, restartPolicy, command); } else { LOGGER.info("Compose Service already exists: " + containers.get(0).getId()); @@ -215,7 +223,7 @@ public class DockerService extends DockerServiceUtils { mounts.add(new Mount().withType(MountType.BIND).withSource("/var/run/docker.sock").withTarget("/var/run/docker.sock")); } createContainerCmd.withHostConfig(new HostConfig() - .withRestartPolicy(restartPolicy) + .withRestartPolicy(restartPolicy) .withPortBindings(portBindings) .withMounts(mounts) .withNetworkMode(network != null ? network : networkName)); @@ -246,7 +254,9 @@ public class DockerService extends DockerServiceUtils { } public void execCommandInContainer(Container container, String... cmd) { - getDockerClient().execCreateCmd(container.getId()).withCmd(cmd).exec(); + ExecCreateCmdResponse res = getDockerClient().execCreateCmd(container.getId()) + .withAttachStdout(true) + .withAttachStdout(true).withCmd(cmd).exec(); } public List<Container> listContainers(Boolean showAll) { @@ -280,10 +290,10 @@ public class DockerService extends DockerServiceUtils { dockerClient.execStartCmd(id).exec(callBack).awaitCompletion(); } - public void copyFiles(String containerId, String containerPath, Map<String, String> files) throws IOException { + public void copyFiles(String containerId, String containerPath, Map<String, String> files, boolean dirChildrenOnly) throws IOException { String temp = codeService.saveProjectFilesInTemp(files); dockerClient.copyArchiveToContainerCmd(containerId).withRemotePath(containerPath) - .withDirChildrenOnly(true).withHostResource(temp).exec(); + .withDirChildrenOnly(dirChildrenOnly).withHostResource(temp).exec(); } public void copyExecFile(String containerId, String containerPath, String filename, String script) { diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java index 099c2571..de6c3285 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/AuthService.java @@ -33,6 +33,10 @@ public class AuthService { } public Map<String, String> getSsoConfig() throws MalformedURLException { - return Map.of("url", ConfigProvider.getConfig().getValue("karavan.frontend.auth-server-url", String.class)); + return Map.of( + "url", ConfigProvider.getConfig().getValue("karavan.keycloak.url", String.class), + "realm", ConfigProvider.getConfig().getValue("karavan.keycloak.realm", String.class), + "clientId", ConfigProvider.getConfig().getValue("karavan.keycloak.frontend.clientId", String.class) + ); } } diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java index 3748e4d3..d799806d 100644 --- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java +++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java @@ -80,8 +80,8 @@ public class KaravanService implements HealthCheck { @Inject ProjectService projectService; - private static final String START_KUBERNETES_SERVICES = "START_KUBERNETES_LISTENERS"; - private static final String START_INTERNAL_DOCKER_SERVICES = "START_INTERNAL_DOCKER_SERVICES"; + public static final String START_KUBERNETES_SERVICES = "START_KUBERNETES_LISTENERS"; + public static final String START_INTERNAL_DOCKER_SERVICES = "START_INTERNAL_DOCKER_SERVICES"; public static final String START_SERVICES = "START_SERVICES"; @Override diff --git a/karavan-web/karavan-app/src/main/resources/application.properties b/karavan-web/karavan-app/src/main/resources/application.properties index a221ddb5..eaef7a99 100644 --- a/karavan-web/karavan-app/src/main/resources/application.properties +++ b/karavan-web/karavan-app/src/main/resources/application.properties @@ -31,6 +31,13 @@ karavan.maven.cache= karavan.docker.network=karavan +# Keycloak configuration +karavan.keycloak.url=http://localhost:8079 +karavan.keycloak.realm=karavan +karavan.keycloak.frontend.clientId=frontend +karavan.keycloak.backend.clientId=backend +karavan.keycloak.backend.secret=backend + # Git repository Configuration karavan.git-repository=http://gitea:3000/karavan/karavan.git karavan.git-username=karavan @@ -96,11 +103,9 @@ quarkus.http.auth.permission.public.methods=GET,HEAD,POST %oidc.karavan.auth=oidc %oidc.quarkus.oidc.enabled=true %oidc.quarkus.http.auth.basic=false -%oidc.quarkus.security.users.embedded.enabled=false -%oidc.karavan.frontend.auth-server-url=${oidc-frontend-url} -%oidc.quarkus.oidc.auth-server-url=${oidc-server-url} -%oidc.quarkus.oidc.client-id=karavan-backend -%oidc.quarkus.oidc.credentials.secret=${oidc-secret} +%oidc.quarkus.oidc.auth-server-url=${karavan.keycloak.url}/realms/${karavan.keycloak.realm} +%oidc.quarkus.oidc.client-id=${karavan.keycloak.backend.clientId} +%oidc.quarkus.oidc.credentials.secret=${karavan.keycloak.backend.secret} %oidc.quarkus.oidc.application-type=service %oidc.quarkus.oidc.tls.verification=none %oidc.quarkus.oidc.roles.source=accesstoken diff --git a/karavan-web/karavan-app/src/main/webui/package-lock.json b/karavan-web/karavan-app/src/main/webui/package-lock.json index 3dc04419..74480976 100644 --- a/karavan-web/karavan-app/src/main/webui/package-lock.json +++ b/karavan-web/karavan-app/src/main/webui/package-lock.json @@ -25,7 +25,7 @@ "file-saver": "2.0.5", "html-to-image": "1.11.11", "karavan-core": "file:../../../../../karavan-core", - "keycloak-js": "22.0.4", + "keycloak-js": "23.0.1", "react": "18.2.0", "react-dom": "18.2.0", "react-router-dom": "^6.15.0", @@ -13320,9 +13320,9 @@ } }, "node_modules/js-sha256": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", - "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.10.1.tgz", + "integrity": "sha512-5obBtsz9301ULlsgggLg542s/jqtddfOpV5KJc4hajc9JV8GeY2gZHSVpYBn4nWqAUTJ9v+xwtbJ1mIBgIH5Vw==" }, "node_modules/js-tokens": { "version": "4.0.0", @@ -13520,17 +13520,26 @@ "node": ">=4.0" } }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "engines": { + "node": ">=18" + } + }, "node_modules/karavan-core": { "resolved": "../../../../../karavan-core", "link": true }, "node_modules/keycloak-js": { - "version": "22.0.4", - "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-22.0.4.tgz", - "integrity": "sha512-PLEQSkEtv+CBcrfnL8/IqKDrWMAHdehCWzohORg7+lR7xpBkQOwpOh82+U/PXE44i9ZEXdRsvcKE9e4dqFUErA==", + "version": "23.0.1", + "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-23.0.1.tgz", + "integrity": "sha512-n7bF7GGrxmzB6mveXYhVoKDZv96PEtrn89/2qSNSCreBKovW/bGcrB6WFBiUOzdWoRW03mDYcU8sUfvELiBPPw==", "dependencies": { "base64-js": "^1.5.1", - "js-sha256": "^0.9.0" + "js-sha256": "^0.10.1", + "jwt-decode": "^4.0.0" } }, "node_modules/keyv": { diff --git a/karavan-web/karavan-app/src/main/webui/package.json b/karavan-web/karavan-app/src/main/webui/package.json index 20d51ef4..f997f606 100644 --- a/karavan-web/karavan-app/src/main/webui/package.json +++ b/karavan-web/karavan-app/src/main/webui/package.json @@ -46,7 +46,7 @@ "file-saver": "2.0.5", "html-to-image": "1.11.11", "karavan-core": "file:../../../../../karavan-core", - "keycloak-js": "22.0.4", + "keycloak-js": "23.0.1", "react": "18.2.0", "react-dom": "18.2.0", "react-router-dom": "^6.15.0", diff --git a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx index 09de0530..4452b2ca 100644 --- a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx @@ -36,10 +36,13 @@ const instance = axios.create(); export class KaravanApi { static me?: any; - static basicToken: string = ''; static authType?: string = undefined; static isAuthorized: boolean = false; + static getInstance() { + return instance; + } + static setAuthType(authType: string) { KaravanApi.authType = authType; switch (authType){ @@ -51,24 +54,12 @@ export class KaravanApi { KaravanApi.setOidcAuthentication(); break; } - case "basic": { - KaravanApi.setBasicAuthentication(); - break; - } } } static setPublicAuthentication() { } - static setBasicAuthentication() { - instance.interceptors.request.use(async config => { - config.headers.Authorization = 'Basic ' + KaravanApi.basicToken; - return config; - }, - error => { - Promise.reject(error) - }); - } + static setOidcAuthentication() { instance.interceptors.request.use(async config => { config.headers.Authorization = 'Bearer ' + SsoApi.keycloak?.token; @@ -137,20 +128,6 @@ export class KaravanApi { }); } - static async auth(username: string, password: string, after: (res: any) => void) { - KaravanApi.basicToken = Buffer.from(username + ":" + password).toString('base64'); - instance.get('/api/users/me') - .then(res => { - if (res.status === 200) { - KaravanApi.isAuthorized = true; - KaravanApi.me = res.data; - after(res); - } - }).catch(err => { - console.log(err); - }); - } - static async getMe(after: (user: {}) => void) { instance.get('/api/users/me') .then(res => { @@ -640,11 +617,13 @@ export class KaravanApi { static async fetchData(type: 'container' | 'build' | 'none', podName: string, controller: AbortController) { const fetchData = async () => { + const headers: any = { Accept: "text/event-stream" }; + if (KaravanApi.authType === 'oidc') { + headers.Authorization = "Bearer " + SsoApi.keycloak?.token + } await fetchEventSource("/api/logwatch/" + type + "/" + podName, { method: "GET", - headers: { - Accept: "text/event-stream", - }, + headers: headers, signal: controller.signal, async onopen(response) { if (response.ok && response.headers.get('content-type') === EventStreamContentType) { diff --git a/karavan-web/karavan-app/src/main/webui/src/api/SsoApi.tsx b/karavan-web/karavan-app/src/main/webui/src/api/SsoApi.tsx index e5c82465..f9b816f8 100644 --- a/karavan-web/karavan-app/src/main/webui/src/api/SsoApi.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/api/SsoApi.tsx @@ -24,8 +24,9 @@ export class SsoApi { static auth(after: () => void) { KaravanApi.getConfig((config: any) => { - SsoApi.keycloak = new Keycloak({url: config.url, realm: 'karavan', clientId: 'karavan-frontend'}); - SsoApi.keycloak.init({onLoad: 'login-required', flow: 'hybrid'}).then(value => { + console.log(config) + SsoApi.keycloak = new Keycloak({url: config.url, realm: config.realm, clientId: config.clientId}); + SsoApi.keycloak.init({onLoad: 'login-required', flow: 'hybrid', checkLoginIframe: false}).then(value => { console.log('SsoApi', 'User is now authenticated.'); KaravanApi.isAuthorized = true; after();