Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI config now primarily pulled from backend endpoint #4273

Merged
merged 6 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
package io.apicurio.registry.rest.v3;

import java.util.HashMap;
import java.util.Map;

import io.apicurio.common.apps.core.System;
import io.apicurio.common.apps.logging.Logged;
import io.apicurio.registry.auth.AuthConfig;
import io.apicurio.registry.auth.Authorized;
import io.apicurio.registry.auth.AuthorizedLevel;
import io.apicurio.registry.auth.AuthorizedStyle;
import io.apicurio.registry.limits.RegistryLimitsConfiguration;
import io.apicurio.registry.metrics.health.liveness.ResponseErrorLivenessCheck;
import io.apicurio.registry.metrics.health.readiness.ResponseTimeoutReadinessCheck;
import io.apicurio.registry.limits.RegistryLimitsConfiguration;
import io.apicurio.registry.rest.v3.beans.Limits;
import io.apicurio.registry.rest.v3.beans.SystemInfo;

import io.apicurio.registry.rest.v3.beans.UserInterfaceConfig;
import io.apicurio.registry.rest.v3.beans.UserInterfaceConfigAuth;
import io.apicurio.registry.rest.v3.beans.UserInterfaceConfigFeatures;
import io.apicurio.registry.rest.v3.beans.UserInterfaceConfigUi;
import io.apicurio.registry.ui.UserInterfaceConfigProperties;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.interceptor.Interceptors;
Expand All @@ -22,6 +30,12 @@ public class SystemResourceImpl implements SystemResource {

@Inject
System system;

@Inject
AuthConfig authConfig;

@Inject
UserInterfaceConfigProperties uiConfig;

@Inject
RegistryLimitsConfiguration registryLimitsConfiguration;
Expand All @@ -44,6 +58,7 @@ public SystemInfo getSystemInfo() {
* @see io.apicurio.registry.rest.v3.SystemResource#getResourceLimits()
*/
@Override
@Authorized(style=AuthorizedStyle.None, level=AuthorizedLevel.None)
public Limits getResourceLimits() {
var limitsConfig = registryLimitsConfiguration;
var limits = new Limits();
Expand All @@ -61,4 +76,41 @@ public Limits getResourceLimits() {
limits.setMaxRequestsPerSecondCount(limitsConfig.getMaxRequestsPerSecondCount());
return limits;
}

/**
* @see io.apicurio.registry.rest.v3.SystemResource#getUIConfig()
*/
@Override
@Authorized(style=AuthorizedStyle.None, level=AuthorizedLevel.None)
public UserInterfaceConfig getUIConfig() {
return UserInterfaceConfig.builder()
.ui(UserInterfaceConfigUi.builder()
.contextPath(uiConfig.contextPath)
.navPrefixPath(uiConfig.navPrefixPath)
.oaiDocsUrl(uiConfig.docsUrl)
.build())
.auth(uiAuthConfig())
.features(UserInterfaceConfigFeatures.builder()
.readOnly("true".equals(uiConfig.featureReadOnly))
.breadcrumbs("true".equals(uiConfig.featureBreadcrumbs))
.roleManagement(authConfig.isRbacEnabled())
.settings("true".equals(uiConfig.featureSettings))
.build())
.build();
}

private UserInterfaceConfigAuth uiAuthConfig() {
UserInterfaceConfigAuth rval = new UserInterfaceConfigAuth();
rval.setObacEnabled(authConfig.isObacEnabled());
rval.setRbacEnabled(authConfig.isRbacEnabled());
rval.setType(authConfig.isAuthEnabled() ? UserInterfaceConfigAuth.Type.oidc : UserInterfaceConfigAuth.Type.none);
if (authConfig.isAuthEnabled()) {
Map<String, String> options = new HashMap<>();
options.put("url", uiConfig.authOidcUrl);
options.put("redirectUri", uiConfig.authOidcRedirectUri);
options.put("clientId", uiConfig.authOidcClientId);
rval.setOptions(options);
}
return rval;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.apicurio.registry.ui;

import org.eclipse.microprofile.config.inject.ConfigProperty;

import io.apicurio.common.apps.config.Info;
import jakarta.inject.Singleton;

@Singleton
public class UserInterfaceConfigProperties {

@ConfigProperty(name = "registry.ui.contextPath", defaultValue = "/")
@Info(category = "ui", description = "Context path of the UI", availableSince = "3.0.0")
public String contextPath;
@ConfigProperty(name = "registry.ui.navPrefixPath", defaultValue = "/")
@Info(category = "ui", description = "Navigation prefix for all UI paths", availableSince = "3.0.0")
public String navPrefixPath;
@ConfigProperty(name = "registry.ui.docsUrl", defaultValue = "/docs/")
@Info(category = "ui", description = "URL of the Documentation component", availableSince = "3.0.0")
public String docsUrl;


@ConfigProperty(name = "registry.auth.url.configured")
public String authOidcUrl;
@ConfigProperty(name = "registry.ui.auth.oidc.redirectUri", defaultValue = "/")
@Info(category = "ui", description = "The OIDC redirectUri", availableSince = "3.0.0")
public String authOidcRedirectUri;
@ConfigProperty(name = "registry.ui.auth.oidc.clientId", defaultValue = "apicurio-registry-ui")
@Info(category = "ui", description = "The OIDC clientId", availableSince = "3.0.0")
public String authOidcClientId;


@ConfigProperty(name = "registry.ui.features.readOnly", defaultValue = "false")
@Info(category = "ui", description = "Enabled to set the UI to read-only mode", availableSince = "3.0.0")
public String featureReadOnly;
@ConfigProperty(name = "registry.ui.features.breadcrumbs", defaultValue = "true")
@Info(category = "ui", description = "Enabled to show breadcrumbs in the UI", availableSince = "3.0.0")
public String featureBreadcrumbs;
@ConfigProperty(name = "registry.ui.features.settings", defaultValue = "true")
@Info(category = "ui", description = "Enabled to show the Settings tab in the UI", availableSince = "3.0.0")
public String featureSettings;

}
202 changes: 202 additions & 0 deletions common/src/main/resources/META-INF/openapi.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{

Check warning on line 1 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-api-servers

Check warning on line 1 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

rhoas-servers-config
"openapi": "3.0.3",
"info": {
"title": "Apicurio Registry API [v3]",
Expand All @@ -14,7 +14,7 @@
"url": "https://www.apache.org/licenses/LICENSE-2.0"
}
},
"paths": {

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-media-example "value" property type must be string

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "version" property type must be string

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "example" property must be equal to one of the allowed values: "OUTBOUND", "INBOUND". Did you mean "INBOUND"?

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "example" property must have required property "group"

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "example" property must match pattern "^[a-zA-Z0-9._\-+]{1,256}$"

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "example" property must have required property "state"

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "example" property must have required property "groupId"

Check warning on line 17 in common/src/main/resources/META-INF/openapi.json

View workflow job for this annotation

GitHub Actions / Validate

oas3-valid-schema-example "createdOn" property must match format "date-time"
"/ids/globalIds/{globalId}": {
"summary": "Access artifact content utilizing an artifact version's globally unique identifier.",
"get": {
Expand Down Expand Up @@ -3380,6 +3380,33 @@
}
]
},
"/system/uiConfig": {
"summary": "Get UI configuration",
"description": "This endpoint is used by the user interface to retrieve UI specific configuration\nin a JSON payload. This allows the UI and the backend to be configured in the \nsame place (the backend process/pod). When the UI loads, it will make an API call\nto this endpoint to determine what UI features and options are configured.",
"get": {
"tags": [
"System"
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserInterfaceConfig"
}
}
},
"description": "The UI config."
},
"500": {
"$ref": "#/components/responses/ServerError"
}
},
"operationId": "getUIConfig",
"summary": "Get UI config",
"description": "Returns the UI configuration properties for this server. The registry UI can be\nconnected to a backend using just a URL. The rest of the UI configuration can then\nbe fetched from the backend using this operation. This allows UI and backend to\nboth be configured in the same place.\n\nThis operation may fail for one of the following reasons:\n\n* A server error occurred (HTTP error `500`)\n"
}
},
"x-codegen-contextRoot": "/apis/registry/v3"
},
"components": {
Expand Down Expand Up @@ -4711,6 +4738,181 @@
}
]
}
},
"UserInterfaceConfig": {
"title": "Root Type for UserInterfaceConfig",
"description": "Defines the user interface configuration data type.",
"required": [
"auth"
],
"type": "object",
"properties": {
"ui": {
"$ref": "#/components/schemas/UserInterfaceConfigUi",
"properties": {
"contextPath": {
"type": "string"
},
"navPrefixPath": {
"type": "string"
},
"oaiDocsUrl": {
"type": "string"
}
}
},
"auth": {
"$ref": "#/components/schemas/UserInterfaceConfigAuth",
"properties": {
"type": {
"type": "string"
},
"rbacEnabled": {
"type": "boolean"
},
"obacEnabled": {
"type": "boolean"
},
"options": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"redirectUri": {
"type": "string"
},
"clientId": {
"type": "string"
}
}
}
}
},
"features": {
"$ref": "#/components/schemas/UserInterfaceConfigFeatures",
"properties": {
"readOnly": {
"type": "boolean"
},
"breadcrumbs": {
"type": "boolean"
},
"roleManagement": {
"type": "boolean"
},
"settings": {
"type": "boolean"
}
}
}
},
"example": {
"ui": {
"contextPath": "/",
"navPrefixPath": "/",
"oaiDocsUrl": "https://registry.apicur.io/docs"
},
"auth": {
"type": "oidc",
"rbacEnabled": true,
"obacEnabled": false,
"options": {
"url": "https://auth.apicur.io/realms/apicurio",
"redirectUri": "http://registry.apicur.io",
"clientId": "apicurio-registry-ui"
}
},
"features": {
"readOnly": false,
"breadcrumbs": true,
"roleManagement": false,
"settings": true
}
}
},
"UserInterfaceConfigAuth": {
"title": "Root Type for UserInterfaceConfigAuth",
"description": "",
"required": [
"obacEnabled",
"rbacEnabled"
],
"type": "object",
"properties": {
"type": {
"enum": [
"none",
"oidc"
],
"type": "string"
},
"rbacEnabled": {
"type": "boolean"
},
"obacEnabled": {
"type": "boolean"
},
"options": {
"$ref": "#/components/schemas/Properties"
}
},
"example": {
"type": "oidc",
"rbacEnabled": true,
"obacEnabled": false,
"options": {
"url": "https://auth.apicur.io/realms/apicurio",
"redirectUri": "https://registry.apicur.io",
"clientId": "registry-ui"
}
}
},
"UserInterfaceConfigFeatures": {
"title": "Root Type for UserInterfaceConfigFeatures",
"description": "",
"type": "object",
"properties": {
"readOnly": {
"type": "boolean"
},
"breadcrumbs": {
"type": "boolean"
},
"roleManagement": {
"type": "boolean"
},
"settings": {
"type": "boolean"
}
},
"example": {
"readOnly": false,
"breadcrumbs": true,
"roleManagement": false,
"settings": true
}
},
"UserInterfaceConfigUi": {
"title": "Root Type for UserInterfaceConfigUi",
"description": "",
"type": "object",
"properties": {
"contextPath": {
"type": "string"
},
"navPrefixPath": {
"type": "string"
},
"oaiDocsUrl": {
"type": "string"
}
},
"example": {
"contextPath": "/",
"navPrefixPath": "/",
"oaiDocsUrl": "https://registry.apicur.io/docs"
}
}
},
"responses": {
Expand Down
4 changes: 4 additions & 0 deletions docs/generateAllConfigPartial.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
public class generateAllConfigPartial {

private static Map<String, Option> allConfiguration = new HashMap();
private static Set<String> skipProperties = Set.of("registry.auth.url.configured");
EricWittmann marked this conversation as resolved.
Show resolved Hide resolved

static class Option {
final String name;
Expand Down Expand Up @@ -152,6 +153,9 @@ public static Map<String, Option> extractConfigurations(String jarFile, Map<Stri
if (allConfiguration.containsKey(configName)) {
continue;
}
if (skipProperties.contains(configName)) {
continue;
}
switch (annotation.target().kind()) {
case FIELD:
configName = configName.replace("app.authn.", "registry.auth.");
Expand Down
Loading
Loading