Skip to content

Commit

Permalink
feat: use latest cockpit connector
Browse files Browse the repository at this point in the history
  • Loading branch information
guillaumelamirand committed Mar 20, 2024
1 parent e3256c3 commit e78b619
Show file tree
Hide file tree
Showing 50 changed files with 1,809 additions and 1,683 deletions.
Expand Up @@ -43,11 +43,15 @@
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.interfaces.RSAPublicKey;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -170,21 +174,37 @@ public Response tokenExchange(@QueryParam(value = "token") final String token, @
}
}

private Key getPublicKey() throws Exception {
private Key getPublicKey() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException {
final KeyStore trustStore = loadTrustStore();
final Certificate cert = trustStore.getCertificate(environment.getProperty("cockpit.keystore.key.alias", "cockpit-client"));
final Certificate cert = trustStore.getCertificate(
getProperty("cockpit.connector.ws.ssl.keystore.key.alias", "cockpit.keystore.key.alias", "cockpit-client")
);

return cert.getPublicKey();
}

private KeyStore loadTrustStore() throws Exception {
final KeyStore keystore = KeyStore.getInstance(environment.getProperty("cockpit.keystore.type"));

try (InputStream is = new File(environment.getProperty("cockpit.keystore.path")).toURI().toURL().openStream()) {
final String password = environment.getProperty("cockpit.keystore.password");
private KeyStore loadTrustStore() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
final KeyStore keystore = KeyStore.getInstance(
getProperty("cockpit.connector.ws.ssl.keystore.type", "cockpit.keystore.type", null)
);

try (
InputStream is = new File(getProperty("cockpit.connector.ws.ssl.keystore.path", "cockpit.keystore.path", null))
.toURI()
.toURL()
.openStream()
) {
final String password = getProperty("cockpit.connector.ws.ssl.keystore.password", "cockpit.keystore.password", null);
keystore.load(is, null == password ? null : password.toCharArray());
}

return keystore;
}

private String getProperty(final String property, final String fallback, final String defaultValue) {
String value = environment.getProperty(property);
if (value == null) {
value = environment.getProperty(fallback);
}
return value != null ? value : defaultValue;
}
}
Expand Up @@ -15,13 +15,9 @@
*/
package io.gravitee.rest.api.service.cockpit.command;

import io.gravitee.cockpit.api.command.Command;
import io.gravitee.cockpit.api.command.Payload;
import io.gravitee.cockpit.api.command.Reply;
import io.gravitee.cockpit.api.command.bridge.BridgeCommand;
import io.gravitee.cockpit.api.command.bridge.BridgeReply;
import io.gravitee.cockpit.api.command.v1.bridge.BridgeCommand;
import io.gravitee.cockpit.api.command.v1.bridge.BridgeReply;

public interface CockpitCommandService {
BridgeReply send(BridgeCommand command);
<T extends Payload> Reply send(Command<T> command);
}
Expand Up @@ -16,14 +16,8 @@
package io.gravitee.rest.api.service.cockpit.command;

import io.gravitee.cockpit.api.CockpitConnector;
import io.gravitee.cockpit.api.command.Command;
import io.gravitee.cockpit.api.command.CommandStatus;
import io.gravitee.cockpit.api.command.Payload;
import io.gravitee.cockpit.api.command.Reply;
import io.gravitee.cockpit.api.command.bridge.BridgeCommand;
import io.gravitee.cockpit.api.command.bridge.BridgePayload;
import io.gravitee.cockpit.api.command.bridge.BridgeReply;
import io.gravitee.cockpit.api.command.bridge.BridgeSimpleReply;
import io.gravitee.cockpit.api.command.v1.bridge.BridgeCommand;
import io.gravitee.cockpit.api.command.v1.bridge.BridgeReply;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

Expand All @@ -41,20 +35,10 @@ public CockpitCommandServiceImpl(

@Override
public BridgeReply send(BridgeCommand command) {
return (BridgeReply) send((Command<BridgePayload>) command);
}

@Override
public <T extends Payload> Reply send(Command<T> command) {
return cockpitConnector
.sendCommand(command)
.onErrorReturn(error ->
new BridgeSimpleReply(
command.getId(),
CommandStatus.ERROR,
error.getMessage() != null ? error.getMessage() : error.toString()
)
)
.onErrorReturn(error -> new BridgeReply(command.getId(), error.getMessage() != null ? error.getMessage() : error.toString()))
.cast(BridgeReply.class)
.blockingGet();
}
}
@@ -0,0 +1,64 @@
/*
* Copyright © 2015 The Gravitee team (http://gravitee.io)
*
* Licensed 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 io.gravitee.rest.api.service.cockpit.command;

import io.gravitee.exchange.api.command.Command;
import io.gravitee.exchange.api.command.CommandAdapter;
import io.gravitee.exchange.api.command.CommandHandler;
import io.gravitee.exchange.api.command.Reply;
import io.gravitee.exchange.api.command.ReplyAdapter;
import io.gravitee.exchange.api.connector.ConnectorCommandContext;
import io.gravitee.exchange.api.connector.ConnectorCommandHandlersFactory;
import io.gravitee.exchange.api.websocket.protocol.ProtocolVersion;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

/**
* @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com)
* @author GraviteeSource Team
*/
@Component("cockpitConnectorCommandHandlersFactory")
@RequiredArgsConstructor
public class CockpitConnectorCommandHandlersFactory implements ConnectorCommandHandlersFactory {

private final List<CommandHandler<? extends Command<?>, ? extends Reply<?>>> commandHandlers;
private final List<CommandAdapter<? extends Command<?>, ? extends Command<?>, ? extends Reply<?>>> commandAdapters;
private final List<ReplyAdapter<? extends Reply<?>, ? extends Reply<?>>> replyAdapters;

@Override
public List<CommandHandler<? extends Command<?>, ? extends Reply<?>>> buildCommandHandlers(
final ConnectorCommandContext connectorCommandContext
) {
return commandHandlers;
}

@Override
public List<CommandAdapter<? extends Command<?>, ? extends Command<?>, ? extends Reply<?>>> buildCommandAdapters(
final ConnectorCommandContext connectorCommandContext,
final ProtocolVersion protocolVersion
) {
return commandAdapters;
}

@Override
public List<ReplyAdapter<? extends Reply<?>, ? extends Reply<?>>> buildReplyAdapters(
final ConnectorCommandContext connectorCommandContext,
final ProtocolVersion protocolVersion
) {
return replyAdapters;
}
}
@@ -0,0 +1,158 @@
/*
* Copyright © 2015 The Gravitee team (http://gravitee.io)
*
* Licensed 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 io.gravitee.rest.api.service.cockpit.command.adapter;

import io.gravitee.apim.core.cockpit.query_service.CockpitAccessService;
import io.gravitee.apim.core.installation.domain_service.InstallationTypeDomainService;
import io.gravitee.apim.core.installation.model.InstallationType;
import io.gravitee.cockpit.api.CockpitConnector;
import io.gravitee.cockpit.api.command.model.accesspoint.AccessPoint;
import io.gravitee.cockpit.api.command.v1.CockpitCommandType;
import io.gravitee.cockpit.api.command.v1.hello.HelloCommand;
import io.gravitee.cockpit.api.command.v1.hello.HelloCommandPayload;
import io.gravitee.cockpit.api.command.v1.hello.HelloReply;
import io.gravitee.cockpit.api.command.v1.installation.AdditionalInfoConstants;
import io.gravitee.common.util.Version;
import io.gravitee.exchange.api.command.CommandAdapter;
import io.gravitee.node.api.Node;
import io.gravitee.plugin.core.api.PluginRegistry;
import io.gravitee.rest.api.service.InstallationService;
import io.gravitee.rest.api.service.common.GraviteeContext;
import io.reactivex.rxjava3.core.Single;
import jakarta.annotation.PostConstruct;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

/**
* @author Florent CHAMFROY (florent.chamfroy at graviteesource.com)
* @author GraviteeSource Team
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class HelloCommandAdapter implements CommandAdapter<io.gravitee.exchange.api.command.hello.HelloCommand, HelloCommand, HelloReply> {

private static final String PATH_SUFFIX = "/";

@Value("${installation.api.url:http://localhost:8083}")
private String apiURL;

@Value("${installation.api.proxyPath.management:${http.api.management.entrypoint:${http.api.entrypoint:/}management}}")
private String managementProxyPath;

@Value("${cockpit.auth.path:/auth/cockpit?token={token}}")
private String authPath;

@Value("${cockpit.trial:false}")
private boolean cockpitTrial;

private final Node node;
private final InstallationService installationService;
private final InstallationTypeDomainService installationTypeDomainService;
private final CockpitAccessService cockpitAccessService;
private final PluginRegistry pluginRegistry;
private String buildAuthPath;

@PostConstruct
public void afterPropertiesSet() {
StringBuilder authPathBuilder = new StringBuilder(managementProxyPath);
if (managementProxyPath.endsWith(PATH_SUFFIX) && authPath.startsWith(PATH_SUFFIX)) {
authPathBuilder.append(authPath.substring(1));
} else if (
(managementProxyPath.endsWith(PATH_SUFFIX) && !authPath.startsWith(PATH_SUFFIX)) ||
(!managementProxyPath.endsWith(PATH_SUFFIX) && authPath.startsWith(PATH_SUFFIX))
) {
authPathBuilder.append(authPath);
} else if (!managementProxyPath.endsWith(PATH_SUFFIX) && !authPath.startsWith(PATH_SUFFIX)) {
authPathBuilder.append(managementProxyPath).append(PATH_SUFFIX).append(authPath);
}
this.buildAuthPath = authPathBuilder.toString();
}

@Override
public String supportType() {
return CockpitCommandType.HELLO.name();
}

@Override
public Single<HelloCommand> adapt(final io.gravitee.exchange.api.command.hello.HelloCommand command) {
return Single
.fromCallable(installationService::getOrInitialize)
.map(installation -> {
InstallationType installationType = installationTypeDomainService.get();

HelloCommandPayload.HelloCommandPayloadBuilder<?, ?> payloadBuilder = HelloCommandPayload
.builder()
.node(
io.gravitee.cockpit.api.command.model.Node
.builder()
.application(node.application())
.installationId(installation.getId())
.hostname(node.hostname())
.version(Version.RUNTIME_VERSION.MAJOR_VERSION)
.connectorVersion(connectorVersion())
.build()
)
.installationType(installationType.getLabel())
.trial(cockpitTrial)
.defaultOrganizationId(GraviteeContext.getDefaultOrganization())
.defaultEnvironmentId(GraviteeContext.getDefaultEnvironment());
Map<String, String> additionalInformation = new HashMap<>(installation.getAdditionalInformation());
additionalInformation.put(AdditionalInfoConstants.AUTH_PATH, buildAuthPath);
if (installationType == InstallationType.MULTI_TENANT) {
Map<AccessPoint.Type, List<AccessPoint>> accessPointTemplates = new EnumMap<>(AccessPoint.Type.class);
cockpitAccessService
.getAccessPointsTemplate()
.forEach((type, accessPoints) ->
accessPointTemplates.put(
AccessPoint.Type.valueOf(type.name()),
accessPoints
.stream()
.map(accessPoint ->
AccessPoint
.builder()
.host(accessPoint.getHost())
.secured(accessPoint.isSecured())
.target(AccessPoint.Target.valueOf(accessPoint.getTarget().name()))
.build()
)
.toList()
)
);
payloadBuilder.accessPointsTemplate(accessPointTemplates);
} else {
additionalInformation.put(AdditionalInfoConstants.AUTH_BASE_URL, apiURL);
}
payloadBuilder.additionalInformation(additionalInformation);
return new HelloCommand(payloadBuilder.build());
});
}

private String connectorVersion() {
try {
return this.pluginRegistry.get("cockpit", "cockpit-connectors-ws").manifest().version();
} catch (Exception e) {
return "unknown";
}
}
}

0 comments on commit e78b619

Please sign in to comment.