Skip to content

Commit

Permalink
feat: implement secret ref finder for native API
Browse files Browse the repository at this point in the history
  • Loading branch information
benoitgravitee authored and phiz71 committed Jan 14, 2025
1 parent b8256b2 commit 0aeef76
Show file tree
Hide file tree
Showing 5 changed files with 522 additions and 88 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* 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.gateway.reactive.reactor.v4.secrets;

import static io.gravitee.secrets.api.discovery.SecretRefsLocation.PLUGIN_KIND;

import io.gravitee.definition.model.v4.endpointgroup.AbstractEndpoint;
import io.gravitee.definition.model.v4.endpointgroup.AbstractEndpointGroup;
import io.gravitee.definition.model.v4.flow.step.Step;
import io.gravitee.definition.model.v4.listener.entrypoint.AbstractEntrypoint;
import io.gravitee.definition.model.v4.plan.AbstractPlan;
import io.gravitee.definition.model.v4.resource.Resource;
import io.gravitee.definition.model.v4.service.Service;
import io.gravitee.secrets.api.discovery.DefinitionSecretRefsFinder;
import io.gravitee.secrets.api.discovery.DefinitionSecretRefsListener;
import io.gravitee.secrets.api.discovery.SecretRefsLocation;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

/**
* @author Benoit BORDIGONI (benoit.bordigoni at graviteesource.com)
* @author GraviteeSource Team
*/
public abstract class AbstractV4APISecretRefFinder<D> implements DefinitionSecretRefsFinder<D> {

protected <T> List<T> safeList(List<T> col) {
return col == null ? List.of() : col;
}

protected <T> Stream<T> safeStream(Collection<T> col) {
return col == null ? Stream.empty() : col.stream();
}

protected boolean canHandle(Object definition, Class<D> clazz) {
return definition != null && clazz.isAssignableFrom(definition.getClass());
}

protected void processEntrypoint(DefinitionSecretRefsListener listener, AbstractEntrypoint entrypoint) {
listener.onCandidate(
entrypoint.getConfiguration(),
new SecretRefsLocation(PLUGIN_KIND, entrypoint.getType()),
entrypoint::setConfiguration
);
}

protected void processPlanConfiguration(DefinitionSecretRefsListener listener, AbstractPlan plan) {
Optional
.ofNullable(plan.getSecurity())
.ifPresent(security ->
listener.onCandidate(
security.getConfiguration(),
new SecretRefsLocation(PLUGIN_KIND, security.getType()),
security::setConfiguration
)
);
}

protected void processStep(DefinitionSecretRefsListener listener, Step step) {
listener.onCandidate(step.getConfiguration(), new SecretRefsLocation(PLUGIN_KIND, step.getPolicy()), step::setConfiguration);
}

protected <T extends AbstractEndpoint> Stream<T> processEndpointGroup(
DefinitionSecretRefsListener listener,
AbstractEndpointGroup<T> endpointGroup
) {
Optional
.ofNullable(endpointGroup.getSharedConfiguration())
.ifPresent(payload ->
listener.onCandidate(
payload,
new SecretRefsLocation(PLUGIN_KIND, endpointGroup.getType()),
endpointGroup::setSharedConfiguration
)
);
return safeStream(endpointGroup.getEndpoints());
}

protected static void processResource(DefinitionSecretRefsListener listener, Resource resource) {
listener.onCandidate(
resource.getConfiguration(),
new SecretRefsLocation(PLUGIN_KIND, resource.getType()),
resource::setConfiguration
);
}

protected void processEndpoint(DefinitionSecretRefsListener listener, AbstractEndpoint endpoint) {
listener.onCandidate(
endpoint.getConfiguration(),
new SecretRefsLocation(PLUGIN_KIND, endpoint.getType()),
endpoint::setConfiguration
);
listener.onCandidate(
endpoint.getSharedConfigurationOverride(),
new SecretRefsLocation(PLUGIN_KIND, endpoint.getType()),
endpoint::setSharedConfigurationOverride
);
}

protected void processService(DefinitionSecretRefsListener listener, Service service) {
listener.onCandidate(service.getConfiguration(), new SecretRefsLocation(PLUGIN_KIND, service.getType()), service::setConfiguration);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*/
package io.gravitee.gateway.reactive.reactor.v4.secrets;

import static io.gravitee.secrets.api.discovery.SecretRefsLocation.PLUGIN_KIND;

import io.gravitee.definition.model.ResponseTemplate;
import io.gravitee.definition.model.v4.Api;
import io.gravitee.definition.model.v4.endpointgroup.service.EndpointGroupServices;
Expand All @@ -27,11 +25,9 @@
import io.gravitee.secrets.api.discovery.Definition;
import io.gravitee.secrets.api.discovery.DefinitionDescriptor;
import io.gravitee.secrets.api.discovery.DefinitionMetadata;
import io.gravitee.secrets.api.discovery.DefinitionSecretRefsFinder;
import io.gravitee.secrets.api.discovery.DefinitionSecretRefsListener;
import io.gravitee.secrets.api.discovery.SecretRefsLocation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -42,13 +38,13 @@
* @author Benoit BORDIGONI (benoit.bordigoni at graviteesource.com)
* @author GraviteeSource Team
*/
public class ApiV4DefinitionSecretRefsFinder implements DefinitionSecretRefsFinder<Api> {
public class ApiV4DefinitionSecretRefsFinder extends AbstractV4APISecretRefFinder<Api> {

public static final String RESPONSE_TEMPLATES_KIND = "response-templates";

@Override
public boolean canHandle(Object definition) {
return definition != null && Api.class.isAssignableFrom(definition.getClass());
return canHandle(definition, Api.class);
}

@Override
Expand All @@ -61,23 +57,10 @@ public void findSecretRefs(Api definition, DefinitionSecretRefsListener listener
// listeners
safeStream(definition.getListeners())
.flatMap(l -> safeStream(l.getEntrypoints()))
.forEach(entrypoint ->
listener.onCandidate(
entrypoint.getConfiguration(),
new SecretRefsLocation(PLUGIN_KIND, entrypoint.getType()),
entrypoint::setConfiguration
)
);
.forEach(entrypoint -> processEntrypoint(listener, entrypoint));

// resources
safeStream(definition.getResources())
.forEach(resource ->
listener.onCandidate(
resource.getConfiguration(),
new SecretRefsLocation(PLUGIN_KIND, resource.getType()),
resource::setConfiguration
)
);
safeStream(definition.getResources()).forEach(resource -> processResource(listener, resource));

// flows api and plan
List<Flow> flows = safeList(definition.getPlans())
Expand All @@ -96,22 +79,9 @@ public void findSecretRefs(Api definition, DefinitionSecretRefsListener listener
flows.stream().flatMap(flow -> safeStream(flow.getSubscribe()))
)
)
.forEach(step ->
listener.onCandidate(step.getConfiguration(), new SecretRefsLocation(PLUGIN_KIND, step.getPolicy()), step::setConfiguration)
);
.forEach(step -> processStep(listener, step));

safeStream(definition.getPlans())
.forEach(plan ->
Optional
.ofNullable(plan.getSecurity())
.ifPresent(security ->
listener.onCandidate(
security.getConfiguration(),
new SecretRefsLocation(PLUGIN_KIND, security.getType()),
security::setConfiguration
)
)
);
safeStream(definition.getPlans()).forEach(plan -> processPlanConfiguration(listener, plan));

// endpoint groups
safeStream(definition.getEndpointGroups())
Expand All @@ -124,62 +94,23 @@ public void findSecretRefs(Api definition, DefinitionSecretRefsListener listener
if (services.getHealthCheck() != null) {
list.add(services.getHealthCheck());
}
list
.stream()
.filter(Service::isEnabled)
.forEach(service ->
listener.onCandidate(
service.getConfiguration(),
new SecretRefsLocation(PLUGIN_KIND, service.getType()),
service::setConfiguration
)
);
Optional
.ofNullable(endpointGroup.getSharedConfiguration())
.ifPresent(payload ->
listener.onCandidate(
payload,
new SecretRefsLocation(PLUGIN_KIND, endpointGroup.getType()),
endpointGroup::setSharedConfiguration
)
);
return safeStream(endpointGroup.getEndpoints());
list.stream().filter(Service::isEnabled).forEach(service -> processService(listener, service));
return processEndpointGroup(listener, endpointGroup);
})
.forEach(endpoint -> {
Optional
.ofNullable(endpoint.getServices())
.map(EndpointServices::getHealthCheck)
.filter(Service::isEnabled)
.ifPresent(service ->
listener.onCandidate(
service.getConfiguration(),
new SecretRefsLocation(PLUGIN_KIND, service.getType()),
service::setConfiguration
)
);
listener.onCandidate(
endpoint.getConfiguration(),
new SecretRefsLocation(PLUGIN_KIND, endpoint.getType()),
endpoint::setConfiguration
);
listener.onCandidate(
endpoint.getSharedConfigurationOverride(),
new SecretRefsLocation(PLUGIN_KIND, endpoint.getType()),
endpoint::setSharedConfigurationOverride
);
.ifPresent(service -> processService(listener, service));
processEndpoint(listener, endpoint);
});

// services
Optional
.ofNullable(definition.getServices())
.map(ApiServices::getDynamicProperty)
.ifPresent(dynamicProperty ->
listener.onCandidate(
dynamicProperty.getConfiguration(),
new SecretRefsLocation(PLUGIN_KIND, dynamicProperty.getType()),
dynamicProperty::setConfiguration
)
);
.ifPresent(dynamicProperty -> processService(listener, dynamicProperty));

// response templates
Map<String, Map<String, ResponseTemplate>> responseTemplates = definition.getResponseTemplates();
Expand All @@ -205,14 +136,6 @@ public void findSecretRefs(Api definition, DefinitionSecretRefsListener listener
);
}

private <T> List<T> safeList(List<T> col) {
return col == null ? List.of() : col;
}

public <T> Stream<T> safeStream(Collection<T> col) {
return col == null ? Stream.empty() : col.stream();
}

public <K, V> Stream<K> safeKeySetStream(Map<K, V> map) {
return map == null ? Stream.empty() : map.keySet().stream();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* 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.gateway.reactive.reactor.v4.secrets;

import io.gravitee.definition.model.v4.nativeapi.NativeApi;
import io.gravitee.definition.model.v4.nativeapi.NativeApiServices;
import io.gravitee.definition.model.v4.nativeapi.NativeFlow;
import io.gravitee.secrets.api.discovery.Definition;
import io.gravitee.secrets.api.discovery.DefinitionDescriptor;
import io.gravitee.secrets.api.discovery.DefinitionMetadata;
import io.gravitee.secrets.api.discovery.DefinitionSecretRefsListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* @author Benoit BORDIGONI (benoit.bordigoni at graviteesource.com)
* @author GraviteeSource Team
*/
public class NativeApiV4DefinitionSecretRefsFinder extends AbstractV4APISecretRefFinder<NativeApi> {

@Override
public boolean canHandle(Object definition) {
return canHandle(definition, NativeApi.class);
}

@Override
public DefinitionDescriptor toDefinitionDescriptor(NativeApi definition, DefinitionMetadata metadata) {
return new DefinitionDescriptor(new Definition("native-api-v4", definition.getId()), Optional.ofNullable(metadata.revision()));
}

@Override
public void findSecretRefs(NativeApi definition, DefinitionSecretRefsListener listener) {
// listeners
safeStream(definition.getListeners())
.flatMap(l -> safeStream(l.getEntrypoints()))
.forEach(entrypoint -> processEntrypoint(listener, entrypoint));

// resources
safeStream(definition.getResources()).forEach(resource -> processResource(listener, resource));

// flows api and plan
List<NativeFlow> flows = safeList(definition.getPlans())
.stream()
.flatMap(p -> safeStream(p.getFlows()))
.collect(Collectors.toCollection(ArrayList::new));
flows.addAll(safeList(definition.getFlows()));
Stream
.concat(
Stream.concat(
flows.stream().flatMap(flow -> safeStream(flow.getPublish())),
flows.stream().flatMap(flow -> safeStream(flow.getSubscribe()))
),
Stream.concat(
flows.stream().flatMap(flow -> safeStream(flow.getConnect())),
flows.stream().flatMap(flow -> safeStream(flow.getInteract()))
)
)
.forEach(step -> processStep(listener, step));

safeStream(definition.getPlans()).forEach(plan -> processPlanConfiguration(listener, plan));

// endpoint groups
safeStream(definition.getEndpointGroups())
.flatMap(endpointGroup -> processEndpointGroup(listener, endpointGroup))
.forEach(endpoint -> processEndpoint(listener, endpoint));

// services
Optional
.ofNullable(definition.getServices())
.map(NativeApiServices::getDynamicProperty)
.ifPresent(dynamicProperty -> processService(listener, dynamicProperty));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import io.gravitee.gateway.reactive.reactor.v4.reactor.ReactorFactory;
import io.gravitee.gateway.reactive.reactor.v4.reactor.ReactorFactoryManager;
import io.gravitee.gateway.reactive.reactor.v4.secrets.ApiV4DefinitionSecretRefsFinder;
import io.gravitee.gateway.reactive.reactor.v4.secrets.NativeApiV4DefinitionSecretRefsFinder;
import io.gravitee.gateway.reactor.Reactor;
import io.gravitee.gateway.reactor.handler.AcceptorResolver;
import io.gravitee.gateway.reactor.handler.ReactorEventListener;
Expand Down Expand Up @@ -266,4 +267,9 @@ public NodeTemplateVariableProvider nodeTemplateVariableProvider(Node node, Gate
public DefinitionSecretRefsFinder<?> v4ApiDefinitionSecretRefsFinder() {
return new ApiV4DefinitionSecretRefsFinder();
}

@Bean
public DefinitionSecretRefsFinder<?> nativeV4ApiDefinitionSecretRefsFinder() {
return new NativeApiV4DefinitionSecretRefsFinder();
}
}
Loading

0 comments on commit 0aeef76

Please sign in to comment.