diff --git a/jans-config-api/docs/jans-config-api-swagger.yaml b/jans-config-api/docs/jans-config-api-swagger.yaml
index f95731d352c..d60e1364af3 100644
--- a/jans-config-api/docs/jans-config-api-swagger.yaml
+++ b/jans-config-api/docs/jans-config-api-swagger.yaml
@@ -7888,22 +7888,22 @@ components:
$ref: '#/components/schemas/AttributeValidation'
tooltip:
type: string
- selected:
- type: boolean
whitePagesCanView:
type: boolean
+ selected:
+ type: boolean
adminCanEdit:
type: boolean
+ adminCanView:
+ type: boolean
userCanView:
type: boolean
userCanEdit:
type: boolean
- adminCanView:
+ userCanAccess:
type: boolean
adminCanAccess:
type: boolean
- userCanAccess:
- type: boolean
baseDn:
type: string
PatchRequest:
@@ -8716,8 +8716,6 @@ components:
type: boolean
lockMessageConfig:
$ref: '#/components/schemas/LockMessageConfig'
- fapi:
- type: boolean
allResponseTypesSupported:
uniqueItems: true
type: array
@@ -8727,6 +8725,8 @@ components:
- code
- token
- id_token
+ fapi:
+ type: boolean
AuthenticationFilter:
required:
- baseDn
diff --git a/jans-config-api/plugins/docs/fido2-plugin-swagger.yaml b/jans-config-api/plugins/docs/fido2-plugin-swagger.yaml
index ce9edff7121..941e2813ac9 100644
--- a/jans-config-api/plugins/docs/fido2-plugin-swagger.yaml
+++ b/jans-config-api/plugins/docs/fido2-plugin-swagger.yaml
@@ -269,7 +269,8 @@ components:
challange:
type: string
challengeHash:
- type: string
+ type: integer
+ format: int32
creationDate:
type: string
format: date-time
diff --git a/jans-config-api/plugins/docs/kc-link-plugin-swagger.yaml b/jans-config-api/plugins/docs/kc-link-plugin-swagger.yaml
new file mode 100644
index 00000000000..7e5898c9f56
--- /dev/null
+++ b/jans-config-api/plugins/docs/kc-link-plugin-swagger.yaml
@@ -0,0 +1,274 @@
+openapi: 3.0.1
+info:
+ title: Jans Config API - Keycloak Link
+ contact:
+ name: Gluu Support
+ url: https://support.gluu.org
+ email: xxx@gluu.org
+ license:
+ name: Apache 2.0
+ url: https://github.com/JanssenProject/jans/blob/main/LICENSE
+ version: 1.0.0
+servers:
+- url: https://jans.io/
+ description: The Jans server
+tags:
+- name: Keycloak Link - Configuration
+paths:
+ /kc-link/kcLinkConfig:
+ get:
+ tags:
+ - KC Link - Configuration
+ summary: Gets KC Link configuration properties
+ description: Gets KC Link configuration properties
+ operationId: get-kc-link-properties
+ responses:
+ "200":
+ description: Ok
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AppConfiguration'
+ "401":
+ description: Unauthorized
+ "500":
+ description: InternalServerError
+ security:
+ - oauth2:
+ - https://jans.io/oauth/kc-link-config.readonly
+ put:
+ tags:
+ - KC Link - Configuration
+ summary: Update KC Link configuration properties
+ description: Update KC Link configuration properties
+ operationId: put-kc-link-properties
+ requestBody:
+ description: GluuAttribute object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AppConfiguration'
+ examples:
+ Request example:
+ description: Request example
+ value: ""
+ responses:
+ "200":
+ description: Ok
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AppConfiguration'
+ "401":
+ description: Unauthorized
+ "500":
+ description: InternalServerError
+ security:
+ - oauth2:
+ - https://jans.io/oauth/kc-link-config.write
+ patch:
+ tags:
+ - KC Link - Configuration
+ summary: Partially modifies KC Link configuration properties.
+ description: Partially modifies KC Link configuration properties.
+ operationId: patch-kc-link-properties
+ requestBody:
+ description: String representing patch-document.
+ content:
+ application/json-patch+json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/JsonPatch'
+ examples:
+ Request json example:
+ description: Request json example
+ value: ""
+ responses:
+ "200":
+ description: Ok
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AppConfiguration'
+ "401":
+ description: Unauthorized
+ "500":
+ description: InternalServerError
+ security:
+ - oauth2:
+ - https://jans.io/oauth/kc-link-config.write
+components:
+ schemas:
+ AppConfiguration:
+ type: object
+ properties:
+ sourceConfigs:
+ type: array
+ items:
+ $ref: '#/components/schemas/GluuLdapConfiguration'
+ inumConfig:
+ $ref: '#/components/schemas/GluuLdapConfiguration'
+ targetConfig:
+ $ref: '#/components/schemas/GluuLdapConfiguration'
+ ldapSearchSizeLimit:
+ type: integer
+ format: int32
+ keyAttributes:
+ type: array
+ items:
+ type: string
+ keyObjectClasses:
+ type: array
+ items:
+ type: string
+ sourceAttributes:
+ type: array
+ items:
+ type: string
+ customLdapFilter:
+ type: string
+ updateMethod:
+ type: string
+ defaultInumServer:
+ type: boolean
+ keepExternalPerson:
+ type: boolean
+ useSearchLimit:
+ type: boolean
+ attributeMapping:
+ type: array
+ items:
+ $ref: '#/components/schemas/CacheRefreshAttributeMapping'
+ snapshotFolder:
+ type: string
+ snapshotMaxCount:
+ type: integer
+ format: int32
+ keycloakConfiguration:
+ $ref: '#/components/schemas/KeycloakConfiguration'
+ baseDN:
+ type: string
+ personObjectClassTypes:
+ type: array
+ items:
+ type: string
+ personCustomObjectClass:
+ type: string
+ contactObjectClassTypes:
+ type: array
+ items:
+ type: string
+ allowPersonModification:
+ type: boolean
+ supportedUserStatus:
+ type: array
+ items:
+ type: string
+ loggingLevel:
+ type: string
+ loggingLayout:
+ type: string
+ externalLoggerConfiguration:
+ type: string
+ metricReporterInterval:
+ type: integer
+ format: int32
+ metricReporterKeepDataDays:
+ type: integer
+ format: int32
+ metricReporterEnabled:
+ type: boolean
+ disableJdkLogger:
+ type: boolean
+ cleanServiceInterval:
+ type: integer
+ format: int32
+ keycloakLinkEnabled:
+ type: boolean
+ keycloakLinkServerIpAddress:
+ type: string
+ keycloakLinkPollingInterval:
+ type: string
+ keycloakLinkLastUpdate:
+ type: string
+ format: date-time
+ keycloakLinkLastUpdateCount:
+ type: string
+ keycloakLinkProblemCount:
+ type: string
+ useLocalCache:
+ type: boolean
+ CacheRefreshAttributeMapping:
+ type: object
+ properties:
+ source:
+ type: string
+ destination:
+ type: string
+ GluuLdapConfiguration:
+ type: object
+ properties:
+ configId:
+ type: string
+ bindDN:
+ type: string
+ bindPassword:
+ type: string
+ servers:
+ type: array
+ items:
+ type: string
+ maxConnections:
+ type: integer
+ format: int32
+ useSSL:
+ type: boolean
+ baseDNs:
+ type: array
+ items:
+ type: string
+ primaryKey:
+ type: string
+ localPrimaryKey:
+ type: string
+ useAnonymousBind:
+ type: boolean
+ enabled:
+ type: boolean
+ version:
+ type: integer
+ format: int32
+ level:
+ type: integer
+ format: int32
+ KeycloakConfiguration:
+ type: object
+ properties:
+ serverUrl:
+ type: string
+ realm:
+ type: string
+ clientId:
+ type: string
+ clientSecret:
+ type: string
+ grantType:
+ type: string
+ username:
+ type: string
+ password:
+ type: string
+ JsonPatch:
+ type: object
+ securitySchemes:
+ oauth2:
+ type: oauth2
+ flows:
+ clientCredentials:
+ tokenUrl: "https://{op-hostname}/.../token"
+ scopes:
+ https://jans.io/oauth/kc-link-config.readonly: View Keycloak Link configuration
+ related information
+ https://jans.io/oauth/kc-link-config.write: Manage Keycloak Link configuration
+ related information
diff --git a/jans-config-api/plugins/docs/kc-saml-plugin-swagger.yaml b/jans-config-api/plugins/docs/kc-saml-plugin-swagger.yaml
index b1e6328bfc2..a668b352de6 100644
--- a/jans-config-api/plugins/docs/kc-saml-plugin-swagger.yaml
+++ b/jans-config-api/plugins/docs/kc-saml-plugin-swagger.yaml
@@ -1009,6 +1009,7 @@ components:
type: string
TrustRelationship:
required:
+ - clientId
- description
- displayName
- spMetaDataSourceType
@@ -1021,6 +1022,8 @@ components:
owner:
type: string
clientId:
+ maxLength: 60
+ minLength: 0
type: string
displayName:
maxLength: 60
@@ -1058,14 +1061,20 @@ components:
- federation
- manual
- mdq
- spMetaDataURL:
+ nameIDPolicyFormat:
type: string
- metaLocation:
+ entityId:
type: string
- jansEntityId:
+ singleLogoutServiceUrl:
+ type: string
+ redirectUris:
type: array
items:
type: string
+ spMetaDataURL:
+ type: string
+ metaLocation:
+ type: string
releasedAttributes:
type: array
items:
diff --git a/jans-config-api/plugins/kc-link-plugin/pom.xml b/jans-config-api/plugins/kc-link-plugin/pom.xml
new file mode 100644
index 00000000000..7398ae84043
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/pom.xml
@@ -0,0 +1,298 @@
+
+
+
+ plugins
+ io.jans.jans-config-api.plugins
+ 1.1.0-SNAPSHOT
+
+
+ 4.0.0
+ kc-link-plugin
+
+
+ 4.4.14
+ 4.5.13
+ ${project.version}
+
+
+
+
+
+
+
+ io.jans
+ jans-config-api-shared
+ ${jans.version}
+
+
+ io.jans
+ jans-config-api-server
+ ${jans.version}
+
+
+ io.jans
+ jans-orm-annotation
+ ${jans.version}
+
+
+ io.jans
+ jans-core-document-store
+ ${jans.version}
+
+
+ io.jans
+ jans-keycloak-link-model
+ ${jans.version}
+
+
+ io.jans
+ jans-link-model
+ ${jans.version}
+
+
+
+
+
+ org.quartz-scheduler
+ quartz
+
+
+
+ io.smallrye
+ smallrye-config
+ 1.5.0
+
+
+
+
+ commons-collections
+ commons-collections
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+ org.apache.httpcomponents
+ httpcore
+
+
+ org.apache.httpcomponents
+ httpcore-nio
+ ${httpcore.version}
+
+
+
+
+ jakarta.enterprise
+ jakarta.enterprise.cdi-api
+
+
+ jakarta.inject
+ jakarta.inject-api
+
+
+ jakarta.validation
+ jakarta.validation-api
+
+
+ jakarta.ws.rs
+ jakarta.ws.rs-api
+
+
+ org.jboss.resteasy
+ resteasy-multipart-provider
+ ${resteasy.version}
+
+
+
+
+ org.apache.james
+ apache-mime4j-dom
+
+
+ org.apache.james
+ apache-mime4j-storage
+
+
+ org.apache.james
+ apache-mime4j-core
+
+
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+ com.intuit.karate
+ karate-junit5
+ test
+
+
+ com.intuit.karate
+ karate-apache
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+ net.masterthought
+ cucumber-reporting
+ test
+
+
+
+
+ io.swagger.core.v3
+ swagger-core-jakarta
+
+
+
+
+
+
+
+
+ ../../profiles/${cfg}/config-build.properties
+ ../../profiles/${cfg}/config-api-test.properties
+
+
+
+
+ src/test/resources
+ true
+
+ karate.properties
+ karate_jenkins.properties
+ test.properties
+ *.*
+
+
+
+
+
+
+ src/main/resources
+ true
+
+ **/*.xml
+ **/*.properties
+ **/*.json
+ META-INF/services/*.*
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ package
+
+ single
+
+
+
+ src/main/assembly/assembly.xml
+
+
+
+
+
+
+
+ maven-surefire-plugin
+
+
+
+ integration
+
+ --tags ~@ignore
+
+
+
+
+ integration-tests
+ integration-test
+
+ test
+
+
+ false
+ !integration
+ integration
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+ deploy-to-local-folder
+ package
+
+ copy-resources
+
+
+ ../target/plugins
+
+
+ ${project.build.directory}
+ *-distribution.jar
+ false
+
+
+
+
+
+
+
+
+
+ io.swagger.core.v3
+ swagger-maven-plugin-jakarta
+ ${swagger-maven-plugin-jakarta}
+
+
+
+ true
+ kc-link-plugin-swagger
+ ${project.artifactId}
+ true
+
+ io.jans.configapi.plugin.kc.link.rest
+
+
+
+
+
+
+ io.swagger.core.v3
+ swagger-models-jakarta
+ ${swagger-models-jakarta}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/assembly/assembly.xml b/jans-config-api/plugins/kc-link-plugin/src/main/assembly/assembly.xml
new file mode 100644
index 00000000000..691b7c57b9f
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/assembly/assembly.xml
@@ -0,0 +1,31 @@
+
+
+ distribution
+
+ jar
+
+ false
+
+
+ true
+ /
+ false
+
+ io.jans:jans-keycloak-link-model
+ io.jans:jans-link-model
+
+ runtime
+
+
+
+
+ ${project.build.directory}/classes
+ /
+
+ **/*
+
+
+
+
\ No newline at end of file
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/extensions/KcLinkExtension.java b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/extensions/KcLinkExtension.java
new file mode 100644
index 00000000000..11973723678
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/extensions/KcLinkExtension.java
@@ -0,0 +1,6 @@
+package io.jans.configapi.plugin.kc.link.extensions;
+
+import jakarta.enterprise.inject.spi.Extension;
+
+public class KcLinkExtension implements Extension {
+}
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/model/config/KcLinkConfigSource.java b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/model/config/KcLinkConfigSource.java
new file mode 100644
index 00000000000..95d7f51b7ae
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/model/config/KcLinkConfigSource.java
@@ -0,0 +1,81 @@
+package io.jans.configapi.plugin.kc.link.model.config;
+
+import io.jans.exception.ConfigurationException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import jakarta.enterprise.context.ApplicationScoped;
+
+import org.eclipse.microprofile.config.spi.ConfigSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@ApplicationScoped
+public class KcLinkConfigSource implements ConfigSource {
+
+ private static Logger log = LoggerFactory.getLogger(KcLinkConfigSource.class);
+ private static final String FILE_CONFIG = "kc-link.properties";
+ private Properties properties = null;
+ Map propertiesMap = new HashMap<>();
+
+ public KcLinkConfigSource() {
+ this.loadProperties();
+ }
+
+ @Override
+ public Map getProperties() {
+ log.debug("Getting properties");
+ return propertiesMap;
+ }
+
+ @Override
+ public Set getPropertyNames() {
+ log.debug("Getting Property Names");
+ try {
+ return properties.stringPropertyNames();
+
+ } catch (Exception e) {
+ log.error("Unable to read properties from file: " + FILE_CONFIG, e);
+ }
+ return Collections.emptySet();
+ }
+
+ @Override
+ public int getOrdinal() {
+ return 800;
+ }
+
+ @Override
+ public String getValue(String name) {
+ log.debug("KcLinkConfigSource()::getValue() - name:{}", name);
+ try {
+ return properties.getProperty(name);
+ } catch (Exception e) {
+ log.error("Unable to read properties from file: " + FILE_CONFIG, e);
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return FILE_CONFIG;
+ }
+
+ private Properties loadProperties() {
+ // Load the properties file
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ try ( InputStream inputStream = loader.getResourceAsStream(FILE_CONFIG)) {
+ properties = new Properties();
+ properties.load(inputStream);
+ properties.stringPropertyNames().stream().forEach(key -> propertiesMap.put(key, properties.getProperty(key)));
+ return properties;
+ } catch (Exception e) {
+ throw new ConfigurationException("Failed to load configuration from "+ FILE_CONFIG, e);
+ }
+ }
+
+}
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/rest/ApiApplication.java b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/rest/ApiApplication.java
new file mode 100644
index 00000000000..66e709aecde
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/rest/ApiApplication.java
@@ -0,0 +1,39 @@
+package io.jans.configapi.plugin.kc.link.rest;
+
+import io.jans.configapi.plugin.kc.link.util.Constants;
+import io.swagger.v3.oas.annotations.OpenAPIDefinition;
+import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
+import io.swagger.v3.oas.annotations.info.*;
+import io.swagger.v3.oas.annotations.tags.*;
+import io.swagger.v3.oas.annotations.security.*;
+import io.swagger.v3.oas.annotations.servers.*;
+
+import jakarta.ws.rs.ApplicationPath;
+import jakarta.ws.rs.core.Application;
+import java.util.HashSet;
+import java.util.Set;
+
+@ApplicationPath("/kc-link")
+@OpenAPIDefinition(info = @Info(title = "Jans Config API - Keycloak Link", version = "1.0.0", contact = @Contact(name = "Gluu Support", url = "https://support.gluu.org", email = "xxx@gluu.org"),
+
+license = @License(name = "Apache 2.0", url = "https://github.com/JanssenProject/jans/blob/main/LICENSE")),
+
+tags = { @Tag(name = "Keycloak Link - Configuration")},
+
+servers = { @Server(url = "https://jans.io/", description = "The Jans server") })
+
+@SecurityScheme(name = "oauth2", type = SecuritySchemeType.OAUTH2, flows = @OAuthFlows(clientCredentials = @OAuthFlow(tokenUrl = "https://{op-hostname}/.../token", scopes = {
+@OAuthScope(name = Constants.KC_LINK_CONFIG_READ_ACCESS, description = "View Keycloak Link configuration related information"),
+@OAuthScope(name = Constants.KC_LINK_CONFIG_WRITE_ACCESS, description = "Manage Keycloak Link configuration related information")}
+)))
+public class ApiApplication extends Application {
+
+ @Override
+ public Set> getClasses() {
+ HashSet> classes = new HashSet<>();
+
+ classes.add(KcLinkConfigResource.class);
+
+ return classes;
+ }
+}
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/rest/KcLinkConfigResource.java b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/rest/KcLinkConfigResource.java
new file mode 100644
index 00000000000..0a7cdc947fc
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/rest/KcLinkConfigResource.java
@@ -0,0 +1,131 @@
+/*
+ * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
+ *
+ * Copyright (c) 2020, Janssen Project
+ */
+
+package io.jans.configapi.plugin.kc.link.rest;
+
+
+import io.jans.configapi.core.rest.BaseResource;
+import io.jans.configapi.core.rest.ProtectedApi;
+import io.jans.configapi.core.util.Jackson;
+import io.jans.keycloak.link.model.config.AppConfiguration;
+import io.jans.keycloak.link.model.config.Conf;
+import io.jans.configapi.plugin.kc.link.service.KcLinkConfigService;
+import io.jans.configapi.plugin.kc.link.util.Constants;
+import io.jans.configapi.util.ApiAccessConstants;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.security.*;
+
+import jakarta.inject.Inject;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotNull;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+import java.io.IOException;
+
+import org.slf4j.Logger;
+
+import com.github.fge.jsonpatch.JsonPatch;
+import com.github.fge.jsonpatch.JsonPatchException;
+
+@Path(Constants.KC_LINK_CONFIG)
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+public class KcLinkConfigResource extends BaseResource {
+
+ @Inject
+ Logger logger;
+
+ @Inject
+ KcLinkConfigService kcLinkConfigService;
+
+ @Operation(summary = "Gets KC Link configuration properties", description = "Gets KC Link configuration properties", operationId = "get-kc-link-properties", tags = {
+ "KC Link - Configuration" }, security = @SecurityRequirement(name = "oauth2", scopes = {
+ Constants.KC_LINK_CONFIG_READ_ACCESS }))
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AppConfiguration.class))),
+ @ApiResponse(responseCode = "401", description = "Unauthorized"),
+ @ApiResponse(responseCode = "500", description = "InternalServerError") })
+ @GET
+ @ProtectedApi(scopes = { Constants.KC_LINK_CONFIG_READ_ACCESS }, groupScopes = {
+ Constants.KC_LINK_CONFIG_WRITE_ACCESS }, superScopes = { ApiAccessConstants.SUPER_ADMIN_READ_ACCESS,
+ ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS })
+ public Response getkcLinkConf() {
+
+ AppConfiguration kcLinkConfiguration = kcLinkConfigService.find();
+ logger.info("KC Link details kcLinkConfiguration():{}", kcLinkConfiguration);
+ if(kcLinkConfiguration==null) {
+ throwInternalServerException("It seems Kc Link module is not setup, kindly check.");
+ }
+ return Response.ok(kcLinkConfiguration).build();
+
+ }
+
+ @Operation(summary = "Update KC Link configuration properties", description = "Update KC Link configuration properties", operationId = "put-kc-link-properties", tags = {
+ "KC Link - Configuration" }, security = @SecurityRequirement(name = "oauth2", scopes = {
+ Constants.KC_LINK_CONFIG_WRITE_ACCESS }))
+ @RequestBody(description = "GluuAttribute object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AppConfiguration.class), examples = @ExampleObject(name = "Request example", value = "example/kc-link/config/kc-link-put.json")))
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AppConfiguration.class))),
+ @ApiResponse(responseCode = "401", description = "Unauthorized"),
+ @ApiResponse(responseCode = "500", description = "InternalServerError") })
+ @PUT @ProtectedApi(scopes = { Constants.KC_LINK_CONFIG_WRITE_ACCESS }, groupScopes = {}, superScopes = {
+ ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS })
+ public Response updatekcLinkConf(@Valid AppConfiguration kcLinkAppConf) {
+ logger.info("Update KC Link conf details kcLinkAppConf():{}", kcLinkAppConf);
+ Conf conf = kcLinkConfigService.findKcLinkConf();
+ logger.info("KC Link conf:{} ", conf);
+ if(conf==null) {
+ throwInternalServerException("It seems Kc Link module is not setup, kindly check.");
+ }
+
+ conf.setDynamic(kcLinkAppConf);
+ kcLinkConfigService.mergeKcLinkConfig(conf);
+ kcLinkAppConf = kcLinkConfigService.find();
+ logger.info("KC Link conf, post update - kcLinkAppConf:{}", kcLinkAppConf);
+ return Response.ok(kcLinkAppConf).build();
+
+ }
+
+ @Operation(summary = "Partially modifies KC Link configuration properties.", description = "Partially modifies KC Link configuration properties.", operationId = "patch-kc-link-properties", tags = {
+ "KC Link - Configuration" }, security = @SecurityRequirement(name = "oauth2", scopes = {
+ Constants.KC_LINK_CONFIG_WRITE_ACCESS }))
+ @RequestBody(description = "String representing patch-document.", content = @Content(mediaType = MediaType.APPLICATION_JSON_PATCH_JSON, array = @ArraySchema(schema = @Schema(implementation = JsonPatch.class)), examples = @ExampleObject(name = "Request json example", value = "example/kc-link/config/kc-link-patch.json")))
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = AppConfiguration.class))),
+ @ApiResponse(responseCode = "401", description = "Unauthorized"),
+ @ApiResponse(responseCode = "500", description = "InternalServerError") })
+ @PATCH
+ @Consumes(MediaType.APPLICATION_JSON_PATCH_JSON)
+ @ProtectedApi(scopes = { Constants.KC_LINK_CONFIG_WRITE_ACCESS }, groupScopes = {}, superScopes = {
+ ApiAccessConstants.SUPER_ADMIN_WRITE_ACCESS })
+ public Response patchkcLinkConf(@NotNull String jsonPatchString) throws JsonPatchException, IOException {
+ logger.info("KC Link Config - jsonPatchString:{} ", jsonPatchString);
+ Conf conf = kcLinkConfigService.findKcLinkConf();
+ logger.info("KC Link conf:{} ", conf);
+ if(conf==null) {
+ throwInternalServerException("It seems Kc Link module is not setup, kindly check.");
+ }
+
+ AppConfiguration kcLinkAppConf = Jackson.applyPatch(jsonPatchString, conf.getDynamic());
+ logger.info("KC Link conf details kcLinkAppConf():{}", kcLinkAppConf);
+
+ conf.setDynamic(kcLinkAppConf);
+ kcLinkConfigService.mergeKcLinkConfig(conf);
+ kcLinkAppConf = kcLinkConfigService.find();
+ logger.info("KC KC Link post patch - kcLinkAppConf:{}", kcLinkAppConf);
+ return Response.ok(kcLinkAppConf).build();
+ }
+}
\ No newline at end of file
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/service/KcLinkConfigService.java b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/service/KcLinkConfigService.java
new file mode 100644
index 00000000000..b4fa24a33eb
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/service/KcLinkConfigService.java
@@ -0,0 +1,67 @@
+package io.jans.configapi.plugin.kc.link.service;
+
+import io.jans.as.common.service.common.ApplicationFactory;
+import io.jans.configapi.configuration.ConfigurationFactory;
+import io.jans.keycloak.link.model.config.AppConfiguration;
+import io.jans.keycloak.link.model.config.Conf;
+import io.jans.orm.PersistenceEntryManager;
+import io.jans.orm.util.properties.FileConfiguration;
+import io.jans.util.exception.InvalidConfigurationException;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+
+@ApplicationScoped
+public class KcLinkConfigService {
+
+ @Inject
+ Logger logger;
+
+ @Inject
+ @Named(ApplicationFactory.PERSISTENCE_ENTRY_MANAGER_NAME)
+ PersistenceEntryManager persistenceManager;
+
+ @Inject
+ ConfigurationFactory configurationFactory;
+
+
+ public FileConfiguration getBaseConfiguration() {
+ logger.info(" configurationFactory.getBaseConfiguration():{}", configurationFactory.getBaseConfiguration());
+ return configurationFactory.getBaseConfiguration();
+ }
+
+ public String getKcLinkDn() {
+ String dn = this.getBaseConfiguration().getString("keycloakLink_ConfigurationEntryDN");
+ logger.info(" kcLinkDn:{}", dn);
+ return dn;
+ }
+
+ // Config handling methods
+ public Conf findKcLinkConf() {
+ final String dn = getKcLinkDn();
+ logger.info(" dn:{}", dn);
+ if (StringUtils.isBlank(dn)) {
+ throw new InvalidConfigurationException("Kc Link Configuration DN is undefined!");
+ }
+
+ Conf kcLinkconf = persistenceManager.find(dn, Conf.class, null);
+ logger.info(" kcLinkconf:{}", kcLinkconf);
+
+ return kcLinkconf;
+ }
+
+ public void mergeKcLinkConfig(Conf kcLinkconf) {
+ kcLinkconf.setRevision(kcLinkconf.getRevision() + 1);
+ persistenceManager.merge(kcLinkconf);
+ }
+
+ public AppConfiguration find() {
+ return findKcLinkConf().getDynamic();
+ }
+
+
+}
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/util/Constants.java b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/util/Constants.java
new file mode 100644
index 00000000000..4f422f34e70
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/util/Constants.java
@@ -0,0 +1,19 @@
+/*
+ * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
+ *
+ * Copyright (c) 2020, Janssen Project
+ */
+
+package io.jans.configapi.plugin.kc.link.util;
+
+public class Constants {
+
+ private Constants() {}
+
+ public static final String KC_LINK_CONFIG = "/kcLinkConfig";
+
+
+ public static final String KC_LINK_CONFIG_READ_ACCESS = "https://jans.io/oauth/kc-link-config.readonly";
+ public static final String KC_LINK_CONFIG_WRITE_ACCESS = "https://jans.io/oauth/kc-link-config.write";
+
+}
\ No newline at end of file
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/util/KcLinkUtil.java b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/util/KcLinkUtil.java
new file mode 100644
index 00000000000..02c3b805533
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/java/io/jans/configapi/plugin/kc/link/util/KcLinkUtil.java
@@ -0,0 +1,37 @@
+/*
+ * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
+ *
+ * Copyright (c) 2020, Janssen Project
+ */
+
+package io.jans.configapi.plugin.kc.link.util;
+
+import io.jans.configapi.plugin.kc.link.model.config.KcLinkConfigSource;
+
+import java.util.Map;
+import java.util.Set;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+
+import org.slf4j.Logger;
+
+@ApplicationScoped
+public class KcLinkUtil {
+
+ @Inject
+ Logger logger;
+
+ @Inject
+ KcLinkConfigSource kcLinkConfigSource;
+
+ public Map getProperties() {
+ logger.debug(" KcLinkUtil - kcLinkConfigSource.getProperties():{}", kcLinkConfigSource.getProperties());
+ return kcLinkConfigSource.getProperties();
+ }
+
+ public Set getPropertyNames() {
+ logger.debug(" KcLinkUtil - kcLinkConfigSource.getPropertyNames():{}", kcLinkConfigSource.getPropertyNames());
+ return kcLinkConfigSource.getPropertyNames();
+ }
+}
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/beans.xml b/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/beans.xml
new file mode 100644
index 00000000000..bf2ab180c1c
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
new file mode 100644
index 00000000000..89e970c3e1a
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
@@ -0,0 +1 @@
+io.jans.configapi.plugin.kc.link.extensions.KcLinkExtension
\ No newline at end of file
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers b/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers
new file mode 100644
index 00000000000..b2c9664d366
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers
@@ -0,0 +1,3 @@
+io.jans.configapi.filters.AuthorizationFilter
+io.jans.configapi.filters.LoggingFilter
+
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource b/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource
new file mode 100644
index 00000000000..d6248b5cbdc
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource
@@ -0,0 +1 @@
+io.jans.configapi.plugin.kc.link.model.config.KcLinkConfigSource
\ No newline at end of file
diff --git a/jans-config-api/plugins/kc-link-plugin/src/main/resources/kc-link.properties b/jans-config-api/plugins/kc-link-plugin/src/main/resources/kc-link.properties
new file mode 100644
index 00000000000..6c5c08a213b
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/main/resources/kc-link.properties
@@ -0,0 +1,3 @@
+default.max.count=200
+default.list.size = "50";
+default.list.start.index = "1";
diff --git a/jans-config-api/plugins/kc-link-plugin/src/test/java/io/jans/configapi/KarateTestRunner.java b/jans-config-api/plugins/kc-link-plugin/src/test/java/io/jans/configapi/KarateTestRunner.java
new file mode 100644
index 00000000000..34da4586ef9
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/test/java/io/jans/configapi/KarateTestRunner.java
@@ -0,0 +1,18 @@
+/*
+ * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
+ *
+ * Copyright (c) 2020, Janssen Project
+ */
+
+package io.jans.configapi;
+
+import com.intuit.karate.junit5.Karate;
+
+public class KarateTestRunner {
+
+ @Karate.Test
+ Karate testFullPath() throws Exception {
+ return Karate.run("src/test/resources/feature");
+ }
+
+}
diff --git a/jans-config-api/plugins/kc-link-plugin/src/test/java/io/jans/configapi/TestJenkinsRunner.java b/jans-config-api/plugins/kc-link-plugin/src/test/java/io/jans/configapi/TestJenkinsRunner.java
new file mode 100644
index 00000000000..a7f7d2d80c2
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/test/java/io/jans/configapi/TestJenkinsRunner.java
@@ -0,0 +1,44 @@
+/*
+ * Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
+ *
+ * Copyright (c) 2020, Janssen Project
+ */
+
+package io.jans.configapi;
+
+import com.intuit.karate.Results;
+import com.intuit.karate.Runner;
+
+import io.jans.as.common.model.registration.Client;
+import net.masterthought.cucumber.Configuration;
+import net.masterthought.cucumber.ReportBuilder;
+import org.apache.commons.io.FileUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class TestJenkinsRunner {
+
+ @Test
+ void testParallel() {
+ System.setProperty("karate.env", "jenkins");
+ Results results = Runner.path("src/test/resources/feature").tags("~@ignore").parallel(1);
+ generateReport(results.getReportDir());
+ Assertions.assertEquals(0, results.getFailCount(), results.getErrorMessages());
+ }
+
+ public static void generateReport(String karateOutputPath) {
+ Collection jsonFiles = FileUtils.listFiles(new File(karateOutputPath), new String[] { "json" }, true);
+ List jsonPaths = new ArrayList(jsonFiles.size());
+ jsonFiles.forEach(file -> jsonPaths.add(file.getAbsolutePath()));
+ Configuration config = new Configuration(new File("target"), "karateTesting");
+ ReportBuilder reportBuilder = new ReportBuilder(jsonPaths, config);
+ reportBuilder.generateReports();
+ }
+}
diff --git a/jans-config-api/plugins/kc-link-plugin/src/test/resources/feature/kc-link/kc-link-config.feature b/jans-config-api/plugins/kc-link-plugin/src/test/resources/feature/kc-link/kc-link-config.feature
new file mode 100644
index 00000000000..dd837aaa6ff
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/test/resources/feature/kc-link/kc-link-config.feature
@@ -0,0 +1,41 @@
+@ignore
+Feature: Verify KC Link configuration endpoint
+
+ Background:kcLinkUrl
+ * def mainUrl = kcLinkUrl
+
+ @kc-link-config-get
+ Scenario: Retrieve KC Link configuration
+ Given url mainUrl
+ And header Authorization = 'Bearer ' + accessToken
+ When method GET
+ Then status 200
+ And print response
+ And assert response.length != null
+
+
+ @kc-link-config-put
+ Scenario: Update KC Link configuration
+ Given url mainUrl
+ And header Authorization = 'Bearer ' + accessToken
+ When method GET
+ Then status 200
+ And print response
+ And assert response.length != null
+ Given url mainUrl
+ And header Authorization = 'Bearer ' + accessToken
+ And request response
+ When method PUT
+ Then status 200
+ And print response
+
+
+ @kc-link-config-get-error
+ Scenario: Retrieve KC Link configuration without bearer token
+ Given url mainUrl
+ When method GET
+ Then status 401
+ And print response
+
+
+
\ No newline at end of file
diff --git a/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate-config-jenkins.js b/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate-config-jenkins.js
new file mode 100644
index 00000000000..f17ade676db
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate-config-jenkins.js
@@ -0,0 +1,58 @@
+function() {
+
+ var stream = read('classpath:karate_jenkins.properties');
+ var props = new java.util.Properties();
+ props.load(stream);
+
+ var env = props.get('karate.env'); // get java system property 'karate.env'
+ karate.configure("ssl", true);
+
+ if (!env) {
+ env = 'dev'; //env can be anything: dev, qa, staging, etc.
+ }
+
+ var url = props.get('karate.test.url');
+ var port = props.get('karate.test.port');
+ var baseUrl = url + (port ? ':' + port : '');
+
+ karate.log('karate_jenkins env :', env);
+ karate.log('karate_jenkins url :', url);
+ karate.log('karate_jenkins port :', port);
+ karate.log('karate_jenkins baseUrl :', baseUrl);
+
+ var testStream = read('classpath:test.properties');
+ var testProps = new java.util.Properties();
+ testProps.load(testStream);
+ karate.log(' testProps = '+testProps);
+ var testClientId = testProps.get('test.client.id');
+ var testClientSecret = testProps.get('test.client.secret');
+ var tokenEndpoint = testProps.get('token.endpoint');
+ var testScopes = testProps.get('test.scopes');
+ var issuer = testProps.get('test.issuer');
+ karate.log(' testClientId = '+testClientId);
+ karate.log(' testClientSecret = '+testClientSecret);
+ karate.log(' tokenEndpoint = '+tokenEndpoint);
+ karate.log(' testScopes = '+testScopes);
+ karate.log(' issuer = '+issuer);
+
+
+ var config = {
+ env: env,
+ baseUrl: baseUrl,
+ testProps: testProps,
+ issuer: issuer,
+ accessToken: '123',
+
+ kcLinkUrl: baseUrl + '/jans-config-api/kc-link/kc-link-config',
+
+ };
+
+ karate.configure('connectTimeout', 30000);
+ karate.configure('readTimeout', 60000);
+
+ var result = karate.callSingle('classpath:token.feature', config);
+ print(' result.response = '+result.response);
+ config.accessToken = result.response.access_token;
+
+ return config;
+}
\ No newline at end of file
diff --git a/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate-config.js b/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate-config.js
new file mode 100644
index 00000000000..41958588071
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate-config.js
@@ -0,0 +1,57 @@
+function() {
+
+ var stream = read('classpath:karate.properties');
+ var props = new java.util.Properties();
+ props.load(stream);
+
+ var env = props.get('karate.env'); // get java system property 'karate.env'
+ karate.configure("ssl", true);
+
+ if (!env) {
+ env = 'dev'; //env can be anything: dev, qa, staging, etc.
+ }
+
+ var url = props.get('karate.test.url');
+ var port = props.get('karate.test.port');
+ var baseUrl = url + (port ? ':' + port : '');
+
+ karate.log('karate env :', env);
+ karate.log('karate url :', url);
+ karate.log('karate port :', port);
+ karate.log('karate baseUrl :', baseUrl);
+
+ var testStream = read('classpath:test.properties');
+ var testProps = new java.util.Properties();
+ testProps.load(testStream);
+ karate.log(' testProps = '+testProps);
+ var testClientId = testProps.get('test.client.id');
+ var testClientSecret = testProps.get('test.client.secret');
+ var tokenEndpoint = testProps.get('token.endpoint');
+ var testScopes = testProps.get('test.scopes');
+ var issuer = testProps.get('test.issuer');
+ karate.log(' testClientId = '+testClientId);
+ karate.log(' testClientSecret = '+testClientSecret);
+ karate.log(' tokenEndpoint = '+tokenEndpoint);
+ karate.log(' testScopes = '+testScopes);
+ karate.log(' issuer = '+issuer);
+
+
+ var config = {
+ env: env,
+ baseUrl: baseUrl,
+ testProps: testProps,
+ issuer: issuer,
+ accessToken: '123',
+
+ kcLinkUrl: baseUrl + '/jans-config-api/kc-link/kc-link-config',
+ };
+
+ karate.configure('connectTimeout', 30000);
+ karate.configure('readTimeout', 60000);
+
+ var result = karate.callSingle('classpath:token.feature', config);
+ print(' result.response = '+result.response);
+ config.accessToken = result.response.access_token;
+
+ return config;
+}
\ No newline at end of file
diff --git a/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate.properties b/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate.properties
new file mode 100644
index 00000000000..41c0d369aff
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate.properties
@@ -0,0 +1,5 @@
+#karate.test.url=http://localhost
+#karate.test.port=8080
+#karate.test.url=https://jenkins-config-api.gluu.org/jans-config-api
+#karate.test.port=443
+karate.test.url=${test.server}
diff --git a/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate_jenkins.properties b/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate_jenkins.properties
new file mode 100644
index 00000000000..0b44a8d7b13
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/test/resources/karate_jenkins.properties
@@ -0,0 +1,2 @@
+karate.test.url=${test.server}
+#karate.test.port=443
diff --git a/jans-config-api/plugins/kc-link-plugin/src/test/resources/logback-test.xml b/jans-config-api/plugins/kc-link-plugin/src/test/resources/logback-test.xml
new file mode 100644
index 00000000000..fea195eb039
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/test/resources/logback-test.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+ target/karate.log
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/jans-config-api/plugins/kc-link-plugin/src/test/resources/test.properties b/jans-config-api/plugins/kc-link-plugin/src/test/resources/test.properties
new file mode 100644
index 00000000000..4257f297907
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/test/resources/test.properties
@@ -0,0 +1,8 @@
+test.scopes=${test.scopes}
+
+# Test env Setting
+token.endpoint=${token.endpoint}
+token.grant.type=${token.grant.type}
+test.client.id=${test.client.id}
+test.client.secret=${test.client.secret}
+test.issuer=${test.issuer}
\ No newline at end of file
diff --git a/jans-config-api/plugins/kc-link-plugin/src/test/resources/testClient.feature b/jans-config-api/plugins/kc-link-plugin/src/test/resources/testClient.feature
new file mode 100644
index 00000000000..34cfdffc438
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/test/resources/testClient.feature
@@ -0,0 +1,13 @@
+@ignore
+Feature: This Feature is to get token to test the test cases
+
+Background:
+* def mainUrl = test_url
+
+Scenario: Get Token
+Given url mainUrl
+And print url
+And request ''
+When method POST
+Then status 204
+And print response
diff --git a/jans-config-api/plugins/kc-link-plugin/src/test/resources/token.feature b/jans-config-api/plugins/kc-link-plugin/src/test/resources/token.feature
new file mode 100644
index 00000000000..ef0ad0d262d
--- /dev/null
+++ b/jans-config-api/plugins/kc-link-plugin/src/test/resources/token.feature
@@ -0,0 +1,45 @@
+@ignore
+Feature: This Feature is to get token to test the test cases - Do not remove ignore tag
+
+Background:
+* def mainUrl = testProps.get('token.endpoint');
+* def grantType = testProps.get('token.grant.type');
+* def clientId = testProps.get('test.client.id');
+* def clientSecret = testProps.get('test.client.secret');
+* def scopes = testProps.get('test.scopes');
+* def authStr = clientId+':'+clientSecret
+* def Base64 = Java.type('java.util.Base64')
+* def encodedAuth = Base64.encoder.encodeToString(authStr.bytes)
+* def encodedScopes = java.net.URLDecoder.decode(scopes, 'UTF-8')
+
+
+Scenario: Get Token
+Given url mainUrl
+And print 'mainUrl = '+mainUrl
+And print 'grantType = '+grantType
+And print 'clientId = '+clientId
+And print 'clientSecret = '+clientSecret
+And print 'scopes = '+scopes
+And print 'authStr = '+authStr
+And print 'encodedAuth = '+encodedAuth
+And print 'encodedScopes = '+encodedScopes
+And header Accept = 'application/json'
+And header Authorization = 'Basic '+encodedAuth
+And form field grant_type = grantType
+And form field scope = scopes
+When method POST
+Then status 200
+And print 'token response = '+response
+
+
+
+
+#Scenario: Get Token
+#Given url 'https://pujavs.jans.server/jans-auth/restv1/token'
+#And header Accept = 'application/json'
+#And header Authorization = 'Basic MTgwMi45ZGNkOThhZC1mZTJjLTRmZDktYjcxNy1kOTQzNmQ5ZjIwMDk6dGVzdDEyMzQ='
+#And form field grant_type = 'client_credentials'
+#And form field scope = 'https://jans.io/oauth/config/openid/clients.readonly'
+#When method POST
+#Then status 200
+#And print 'token response = '+response
diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/IdentityProvider.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/IdentityProvider.java
index 024d000dc40..80b1ca7b75a 100644
--- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/IdentityProvider.java
+++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/IdentityProvider.java
@@ -68,7 +68,7 @@ public class IdentityProvider extends Entry implements Serializable {
@AttributeName(name = "nameIDPolicyFormat")
private String nameIDPolicyFormat;
- @AttributeName(name = "idpEntityId")
+ @AttributeName(name = "entityId")
private String idpEntityId;
@AttributeName(name = "singleSignOnServiceUrl")
diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/TrustRelationship.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/TrustRelationship.java
index 7518f1057e6..974c72bf8a9 100644
--- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/TrustRelationship.java
+++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/TrustRelationship.java
@@ -16,6 +16,7 @@
import io.jans.orm.model.base.Entry;
import io.swagger.v3.oas.annotations.Hidden;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Comparator;
@@ -42,6 +43,8 @@ public class TrustRelationship extends Entry implements Serializable {
private String owner;
@AttributeName(name = "jansClntId")
+ @NotNull
+ @Size(min = 0, max = 60, message = "Length of the Client Id should not exceed 60")
private String clientId;
@NotNull
@@ -107,6 +110,18 @@ public class TrustRelationship extends Entry implements Serializable {
@AttributeName(name = "jansSAMLspMetaDataSourceTyp")
private MetadataSourceType spMetaDataSourceType;
+ @AttributeName(name = "nameIDPolicyFormat")
+ private String nameIDPolicyFormat;
+
+ @AttributeName(name = "entityId")
+ private String entityId;
+
+ @AttributeName(name = "singleLogoutServiceUrl")
+ private String singleLogoutServiceUrl;
+
+ @AttributeName(name = "jansRedirectURI")
+ private String[] redirectUris;
+
/**
* Trust Relationship file location of metadata
*/
@@ -120,9 +135,6 @@ public class TrustRelationship extends Entry implements Serializable {
@AttributeName(name = "jansMetaLocation")
private String metaLocation;
- @AttributeName(name = "jansEntityId")
- private List jansEntityId;
-
@AttributeName(name = "jansReleasedAttr")
private List releasedAttributes;
@@ -144,7 +156,7 @@ public class TrustRelationship extends Entry implements Serializable {
private List validationLog;
private Map profileConfigurations = new HashMap();
-
+
public String getInum() {
return inum;
}
@@ -273,6 +285,38 @@ public void setSpMetaDataSourceType(MetadataSourceType spMetaDataSourceType) {
this.spMetaDataSourceType = spMetaDataSourceType;
}
+ public String getNameIDPolicyFormat() {
+ return nameIDPolicyFormat;
+ }
+
+ public void setNameIDPolicyFormat(String nameIDPolicyFormat) {
+ this.nameIDPolicyFormat = nameIDPolicyFormat;
+ }
+
+ public String getEntityId() {
+ return entityId;
+ }
+
+ public void setEntityId(String entityId) {
+ this.entityId = entityId;
+ }
+
+ public String getSingleLogoutServiceUrl() {
+ return singleLogoutServiceUrl;
+ }
+
+ public void setSingleLogoutServiceUrl(String singleLogoutServiceUrl) {
+ this.singleLogoutServiceUrl = singleLogoutServiceUrl;
+ }
+
+ public String[] getRedirectUris() {
+ return redirectUris;
+ }
+
+ public void setRedirectUris(String[] redirectUris) {
+ this.redirectUris = redirectUris;
+ }
+
public String getSpMetaDataFN() {
return spMetaDataFN;
}
@@ -297,14 +341,6 @@ public void setMetaLocation(String metaLocation) {
this.metaLocation = metaLocation;
}
- public List getJansEntityId() {
- return jansEntityId;
- }
-
- public void setJansEntityId(List jansEntityId) {
- this.jansEntityId = jansEntityId;
- }
-
public List getReleasedAttributes() {
return releasedAttributes;
}
@@ -372,7 +408,6 @@ public int compare(TrustRelationship first, TrustRelationship second) {
public static void sortByDataSourceType(List trustRelationships) {
Collections.sort(trustRelationships, new SortByDatasourceTypeComparator());
}
-
@Override
public String toString() {
@@ -382,11 +417,12 @@ public String toString() {
+ ", alwaysDisplayInConsole=" + alwaysDisplayInConsole + ", clientAuthenticatorType="
+ clientAuthenticatorType + ", secret=" + secret + ", registrationAccessToken="
+ registrationAccessToken + ", consentRequired=" + consentRequired + ", spMetaDataSourceType="
- + spMetaDataSourceType + ", spMetaDataFN=" + spMetaDataFN + ", spMetaDataURL=" + spMetaDataURL
- + ", metaLocation=" + metaLocation + ", jansEntityId=" + jansEntityId + ", releasedAttributes="
- + releasedAttributes + ", url=" + url + ", spLogoutURL=" + spLogoutURL + ", status=" + status
- + ", validationStatus=" + validationStatus + ", validationLog=" + validationLog
- + ", profileConfigurations=" + profileConfigurations + "]";
- }
-
+ + spMetaDataSourceType + ", nameIDPolicyFormat=" + nameIDPolicyFormat + ", entityId=" + entityId
+ + ", singleLogoutServiceUrl=" + singleLogoutServiceUrl + ", redirectUris="
+ + Arrays.toString(redirectUris) + ", spMetaDataFN=" + spMetaDataFN + ", spMetaDataURL=" + spMetaDataURL
+ + ", metaLocation=" + metaLocation + ", releasedAttributes=" + releasedAttributes + ", url=" + url
+ + ", spLogoutURL=" + spLogoutURL + ", status=" + status + ", validationStatus=" + validationStatus
+ + ", validationLog=" + validationLog + ", profileConfigurations=" + profileConfigurations + "]";
+ }
+
}
diff --git a/jans-config-api/plugins/pom.xml b/jans-config-api/plugins/pom.xml
index 65e0db6b244..5d4dba29b18 100644
--- a/jans-config-api/plugins/pom.xml
+++ b/jans-config-api/plugins/pom.xml
@@ -22,7 +22,8 @@
user-mgt-plugin
fido2-plugin
kc-saml-plugin
-
+ kc-link-plugin
+
diff --git a/jans-config-api/server/src/main/resources/config-api-rs-protect.json b/jans-config-api/server/src/main/resources/config-api-rs-protect.json
index 7a447d00146..8d0da16c6f7 100644
--- a/jans-config-api/server/src/main/resources/config-api-rs-protect.json
+++ b/jans-config-api/server/src/main/resources/config-api-rs-protect.json
@@ -2303,7 +2303,9 @@
},
{
"httpMethods": [
- "POST","PUT","DELETE"
+ "POST",
+ "PUT",
+ "DELETE"
],
"scopes": [
{
@@ -2349,7 +2351,9 @@
},
{
"httpMethods": [
- "POST","PUT","DELETE"
+ "POST",
+ "PUT",
+ "DELETE"
],
"scopes": [
{
@@ -2395,7 +2399,9 @@
},
{
"httpMethods": [
- "POST","PUT","DELETE"
+ "POST",
+ "PUT",
+ "DELETE"
],
"scopes": [
{
@@ -2441,7 +2447,9 @@
},
{
"httpMethods": [
- "POST","PUT","PATCH"
+ "POST",
+ "PUT",
+ "PATCH"
],
"scopes": [
{
@@ -2487,7 +2495,10 @@
},
{
"httpMethods": [
- "POST","PUT","PATCH","DELETE"
+ "POST",
+ "PUT",
+ "PATCH",
+ "DELETE"
],
"scopes": [
{
@@ -2533,7 +2544,10 @@
},
{
"httpMethods": [
- "POST","PUT","PATCH","DELETE"
+ "POST",
+ "PUT",
+ "PATCH",
+ "DELETE"
],
"scopes": [
{
@@ -2725,7 +2739,7 @@
}
]
},
- {
+ {
"path": "/jans-config-api/api/v1/health/app-version",
"conditions": [
{
@@ -2747,6 +2761,53 @@
]
}
]
+ },
+ {
+ "path": "/jans-config-api/kc-link/kcLinkConfig",
+ "conditions": [
+ {
+ "httpMethods": [
+ "GET"
+ ],
+ "scopes": [
+ {
+ "inum": "1800.01.71",
+ "name": "https://jans.io/oauth/config/saml-config.readonly"
+ }
+ ],
+ "groupScopes": [
+ {
+ "inum": "1800.01.72",
+ "name": "https://jans.io/oauth/config/saml-config.write"
+ }
+ ],
+ "superScopes": [
+ {
+ "inum": "1800.03.1",
+ "name": "https://jans.io/oauth/config/read-all"
+ }
+ ]
+ },
+ {
+ "httpMethods": [
+ "PUT",
+ "PATCH"
+ ],
+ "scopes": [
+ {
+ "inum": "1800.01.72",
+ "name": "https://jans.io/oauth/config/saml-config.write"
+ }
+ ],
+ "groupScopes": [],
+ "superScopes": [
+ {
+ "inum": "1800.03.2",
+ "name": "https://jans.io/oauth/config/write-all"
+ }
+ ]
+ }
+ ]
}
]
}
\ No newline at end of file
diff --git a/jans-linux-setup/jans_setup/schema/jans_schema.json b/jans-linux-setup/jans_setup/schema/jans_schema.json
index 877a9d4d1f4..cbed32cf8d5 100644
--- a/jans-linux-setup/jans_setup/schema/jans_schema.json
+++ b/jans-linux-setup/jans_setup/schema/jans_schema.json
@@ -3688,10 +3688,10 @@
"x_origin":"Jans created attribute"
},
{
- "desc":"idpEntityId",
+ "desc":"entityId",
"equality":"caseIgnoreMatch",
"names":[
- "idpEntityId"
+ "entityId"
],
"oid":"jansAttr",
"substr":"caseIgnoreSubstringsMatch",
@@ -5010,19 +5010,21 @@
"jansRedirectURI",
"jansWebOrigins",
"consentRequired",
+ "nameIDPolicyFormat",
+ "entityId",
+ "singleLogoutServiceUrl",
"jansSAMLMetaDataFilter",
"jansSAMLspMetaDataSourceTyp",
"jansSAMLspMetaDataFN",
"jansSAMLspMetaDataURL",
"jansMetaLocation",
"jansIsFed",
- "jansEntityId",
"jansEntityTyp",
"jansProfileConf",
"jansReleasedAttr",
"url",
"jansPostLogoutRedirectURI",
- "protocol",
+ "protocol",
"jansStatus",
"jansValidationStatus",
"jansValidationLog"
@@ -5049,14 +5051,14 @@
"description",
"realm",
"jansEnabled",
- "providerId",
- "signingCertificate",
- "validateSignature",
- "singleLogoutServiceUrl",
- "nameIDPolicyFormat",
- "idpEntityId",
- "singleSignOnServiceUrl",
- "encryptionPublicKey",
+ "providerId",
+ "signingCertificate",
+ "validateSignature",
+ "singleLogoutServiceUrl",
+ "nameIDPolicyFormat",
+ "entityId",
+ "singleSignOnServiceUrl",
+ "encryptionPublicKey",
"trustEmail",
"storeToken",
"addReadTokenRoleOnCreate",