From d3401e3b695f21a61c5ddc5675d242a30839ef06 Mon Sep 17 00:00:00 2001 From: pujavs <43700552+pujavs@users.noreply.github.com> Date: Wed, 3 Jan 2024 21:49:11 +0530 Subject: [PATCH] fix(kc-saml-plugin): fixed IDP creation issue, enum values and removed kc lib dependency (#7238) * fix(kc-saml-plugin): remove kc lib dependency - wip Signed-off-by: pujavs * fix(kc-saml-plugin): removing dependency of kc lib wip Signed-off-by: pujavs * fix(kc-saml-plugin): removing dependency of kc lib wip Signed-off-by: pujavs * fix(config-api) keycloak lib conflict issue Signed-off-by: pujavs * fix(config-api) keycloak lib conflict issue Signed-off-by: pujavs * fix(config-api) keycloak lib conflict issue Signed-off-by: pujavs * fix(config-api) keycloak lib conflict issue Signed-off-by: pujavs * fix(config-api) keycloak lib conflict issue Signed-off-by: pujavs * fix(kc-config-api): removing kc lib dependency - wip Signed-off-by: pujavs * fix(kc-config-api): removing kc lib dependency - wip Signed-off-by: pujavs * fix(kc-config-api): removing kc lib dependency - wip Signed-off-by: pujavs * feat(kc-config-api): removed kc lib dependency Signed-off-by: pujavs * feat(kc-config-api): removed kc lib dependency Signed-off-by: pujavs * feat(kc-config-api): removed kc lib dependency Signed-off-by: pujavs * feat(kc-config-api): removed kc lib dependency Signed-off-by: pujavs * feat(kc-config-api): sync with main Signed-off-by: pujavs * feat(kc-saml-plugin): sonar code issue fixed Signed-off-by: pujavs --------- Signed-off-by: pujavs --- docs/admin/reference/openapi.md | 1 + .../docs/jans-config-api-swagger.yaml | 48 +- .../plugins/docs/kc-saml-plugin-swagger.yaml | 38 +- .../plugins/kc-saml-plugin/pom.xml | 28 - .../src/main/assembly/assembly.xml | 4 - .../plugin/saml/client/IdpClientFactory.java | 331 ++++++++++-- .../configuration/SamlAppInitializer.java | 30 +- .../SamlConfigurationFactory.java | 3 +- .../saml/configuration/kc/KeycloakConfig.java | 46 -- .../saml/mapper/IdentityProviderMapper.java | 32 -- .../plugin/saml/model/EntityType.java | 2 +- .../plugin/saml/model/IdentityProvider.java | 36 +- .../model/config/SamlAppConfiguration.java | 162 ++++-- .../plugin/saml/rest/ApiApplication.java | 6 +- .../plugin/saml/rest/IdpResource.java | 117 ++-- .../saml/rest/TrustRelationshipResource.java | 1 - .../saml/service/IdentityProviderService.java | 88 +-- .../plugin/saml/service/IdpService.java | 278 +++++----- .../plugin/saml/service/KeycloakService.java | 502 +++++++++--------- .../saml/service/SamlConfigService.java | 72 +++ .../plugin/saml/service/SamlIdpService.java | 5 +- .../plugin/saml/service/SamlService.java | 5 +- .../configapi/plugin/saml/util/Constants.java | 4 + .../configapi/core/rest/BaseResource.java | 11 + .../io/jans/configapi/core/util/Jackson.java | 2 +- .../templates/jans-saml/jans-saml-config.json | 44 +- 26 files changed, 1035 insertions(+), 861 deletions(-) delete mode 100644 jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/kc/KeycloakConfig.java delete mode 100644 jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/mapper/IdentityProviderMapper.java diff --git a/docs/admin/reference/openapi.md b/docs/admin/reference/openapi.md index 37d8c244121..63127591772 100644 --- a/docs/admin/reference/openapi.md +++ b/docs/admin/reference/openapi.md @@ -21,6 +21,7 @@ Follow the links below to access respective documentation. | Jans Core | NA | | Jans FIDO 2 | [Swagger](https://gluu.org/swagger-ui/?url=https://raw.githubusercontent.com/JanssenProject/jans/vreplace-janssen-version/jans-fido2/docs/jansFido2Swagger.yaml) | | Jans SCIM API | [Swagger](https://gluu.org/swagger-ui/?url=https://raw.githubusercontent.com/JanssenProject/jans/vreplace-janssen-version/jans-scim/server/src/main/resources/jans-scim-openapi.yaml) | +| Jans KC SAML API | [Swagger](https://gluu.org/swagger-ui/?url=https://raw.githubusercontent.com/JanssenProject/jans/main/jans-config-api/plugins/docs/kc-saml-plugin-swagger.yaml) | ## Javadocs diff --git a/jans-config-api/docs/jans-config-api-swagger.yaml b/jans-config-api/docs/jans-config-api-swagger.yaml index 2ceea7e4aa1..dc6865acd88 100644 --- a/jans-config-api/docs/jans-config-api-swagger.yaml +++ b/jans-config-api/docs/jans-config-api-swagger.yaml @@ -7862,19 +7862,19 @@ components: type: string selected: type: boolean - userCanEdit: - type: boolean userCanView: type: boolean - userCanEdit: + adminCanEdit: type: boolean adminCanView: type: boolean - adminCanEdit: + userCanEdit: + type: boolean + adminCanAccess: type: boolean userCanAccess: type: boolean - adminCanAccess: + whitePagesCanView: type: boolean baseDn: type: string @@ -8675,6 +8675,8 @@ components: type: boolean skipAuthenticationFilterOptionsMethod: type: boolean + fapi: + type: boolean allResponseTypesSupported: uniqueItems: true type: array @@ -8684,8 +8686,6 @@ components: - code - token - id_token - fapi: - type: boolean AuthenticationFilter: required: - baseDn @@ -9195,6 +9195,16 @@ components: type: string tokenEndpointAuthMethod: type: string + format: enum + enum: + - client_secret_basic + - client_secret_post + - client_secret_jwt + - private_key_jwt + - access_token + - tls_client_auth + - self_signed_tls_client_auth + - none tokenEndpointAuthSigningAlg: type: string defaultMaxAge: @@ -9412,6 +9422,10 @@ components: type: string introspectionEncryptedResponseEnc: type: string + authorizationDetailsTypes: + type: array + items: + type: string CustomObjectAttribute: type: object properties: @@ -9867,29 +9881,29 @@ components: PostgresMessageConfiguration: type: object properties: - jdbc.driver.class-name: + driverClassName: type: string - db-schema-name: + dbSchemaName: type: string - connection-uri: + connectionUri: type: string - auth-user-name: + authUserName: type: string - auth-user-password: + authUserPassword: type: string - connection-pool-max-total: + connectionPoolMaxTotal: type: integer format: int32 - connection-pool-max-idle: + connectionPoolMaxIdle: type: integer format: int32 - connection-pool-min-idle: + connectionPoolMinIdle: type: integer format: int32 - message-wait-millis: + messageWaitMillis: type: integer format: int32 - message-sleep-thread-millis: + messageSleepThreadTime: type: integer format: int32 RedisMessageConfiguration: 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 96b329c3a70..3fef543b0b4 100644 --- a/jans-config-api/plugins/docs/kc-saml-plugin-swagger.yaml +++ b/jans-config-api/plugins/docs/kc-saml-plugin-swagger.yaml @@ -469,13 +469,13 @@ paths: security: - oauth2: - https://jans.io/idp/saml.readonly - /kc/saml/idp/sp-metadata-file/{inum}: + /kc/saml/idp/sp-metadata/{inum}: get: tags: - SAML - Identity Broker - summary: Get SAML SP Metadata Endpoint URL - description: Get SAML SP Metadata Endpoint URL - operationId: get-saml-sp-metadata-url + summary: Get SAML SP Metadata as Json + description: Get SAML SP Metadata as Json + operationId: get-saml-sp-metadata-json parameters: - name: inum in: path @@ -489,7 +489,7 @@ paths: content: application/json: schema: - type: string + $ref: '#/components/schemas/JsonNode' "401": description: Unauthorized "500": @@ -497,13 +497,13 @@ paths: security: - oauth2: - https://jans.io/idp/saml.readonly - /kc/saml/idp/sp-metadata/{inum}: + /kc/saml/idp/sp-metadata-file/{inum}: get: tags: - SAML - Identity Broker - summary: Get SAML SP Metadata as Json - description: Get SAML SP Metadata as Json - operationId: get-saml-sp-metadata-json + summary: Get SAML SP Metadata Endpoint URL + description: Get SAML SP Metadata Endpoint URL + operationId: get-saml-sp-metadata-url parameters: - name: inum in: path @@ -517,7 +517,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/JsonNode' + type: string "401": description: Unauthorized "500": @@ -857,7 +857,7 @@ components: type: string enabled: type: boolean - signingCertificates: + signingCertificate: type: string validateSignature: type: string @@ -956,12 +956,20 @@ components: type: string grantType: type: string + scope: + type: string username: type: string password: type: string spMetadataUrl: type: string + tokenUrl: + type: string + idpUrl: + type: string + idpMetadataImportUrl: + type: string idpRootDir: type: string idpMetadataDir: @@ -986,6 +994,14 @@ components: type: array items: type: string + kcAttributes: + type: array + items: + type: string + kcSamlConfig: + type: array + items: + type: string JsonPatch: type: object ProfileConfiguration: diff --git a/jans-config-api/plugins/kc-saml-plugin/pom.xml b/jans-config-api/plugins/kc-saml-plugin/pom.xml index 970eabb5f51..73e0d0372f7 100644 --- a/jans-config-api/plugins/kc-saml-plugin/pom.xml +++ b/jans-config-api/plugins/kc-saml-plugin/pom.xml @@ -16,9 +16,6 @@ 4.5.13 ${project.version} 3.4.6 - 21.1.1 - 22.0.5 - 1.5.3.Final @@ -143,32 +140,7 @@ java-support 7.5.2 - - - - org.keycloak - keycloak-admin-client-jakarta - ${keycloak.version} - - - org.keycloak - keycloak-core - ${keycloak.version} - - - org.keycloak - keycloak-common - ${keycloak.version} - - - - - org.mapstruct - mapstruct - ${mapstruct.version} - - io.rest-assured diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/assembly/assembly.xml b/jans-config-api/plugins/kc-saml-plugin/src/main/assembly/assembly.xml index 03c925f80bb..8e93631d7cd 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/assembly/assembly.xml +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/assembly/assembly.xml @@ -23,10 +23,6 @@ org.opensaml:opensaml-xmlsec-api org.opensaml:opensaml-core net.shibboleth.utilities:java-support - org.mapstruct:mapstruct - org.keycloak:keycloak-admin-client-jakarta - org.keycloak:keycloak-core - org.keycloak:keycloak-common runtime diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/client/IdpClientFactory.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/client/IdpClientFactory.java index 6be84eda639..049b9baf72e 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/client/IdpClientFactory.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/client/IdpClientFactory.java @@ -6,25 +6,30 @@ package io.jans.configapi.plugin.saml.client; -import static io.jans.as.model.util.Util.escapeLog; - import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; -import io.jans.configapi.core.util.Jackson; +import io.jans.util.exception.InvalidAttributeException; +import io.jans.util.exception.ConfigurationException; +import io.jans.configapi.plugin.saml.util.Constants; +import io.jans.configapi.core.util.Jackson; import jakarta.enterprise.context.ApplicationScoped; +import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.client.Invocation.Builder; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedHashMap; import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Map; import org.apache.commons.lang.StringUtils; -import org.eclipse.microprofile.rest.client.annotation.RegisterProvider; -import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; -import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient43Engine; +import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,62 +37,290 @@ @ApplicationScoped public class IdpClientFactory { - private static Logger log = LoggerFactory.getLogger(IdpClientFactory.class); - private static final String CONTENT_TYPE = "Content-Type"; + private static Logger logger = LoggerFactory.getLogger(IdpClientFactory.class); + public static final String AUTHORIZATION = "Authorization"; + public static final String BEARER = "Bearer "; + public static final String CONTENT_TYPE = "Content-Type"; + public static final String APPLICATION_JSON = "application/json"; + public static final String ACCESS_TOKEN_NULL = "Access Token is null!!!"; + public static final String IDP_URL_NULL = "IDP URL is null!!!"; + + public static String getAccessToken(final String tokenUrl, final String clientId, final String clientSecret, + final String grantType, final String scope, final String username, final String password, + final String serverUrl) throws JsonProcessingException { + logger.info( + "Get tokenUrl:{}, clientId:{}, clientSecret:{}, grantType:{}, scope:{}, username:{}, password:{}, serverUrl:{}", + tokenUrl, clientId, clientSecret, grantType, scope, username, password, serverUrl); + + Builder request = getClientBuilder(tokenUrl); + request.header(AUTHORIZATION, "Basic " + clientId + ":" + clientSecret); + request.header(CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED); + + final MultivaluedHashMap multivaluedHashMap = new MultivaluedHashMap<>(); + multivaluedHashMap.add("client_id", clientId); + multivaluedHashMap.add("client_secret", clientSecret); + multivaluedHashMap.add("grant_type", + (StringUtils.isNotBlank(grantType) ? grantType.toLowerCase() : "password")); + multivaluedHashMap.add("scope", scope); + multivaluedHashMap.add("username", username); + multivaluedHashMap.add("password", password); + multivaluedHashMap.add("redirect_uri", serverUrl); + Response response = request.post(Entity.form(multivaluedHashMap)); + + String token = null; + if (response != null) { + logger.trace( + "Response for Access Token - response.getStatus():{}, response.getStatusInfo():{}, response.getEntity().getClass():{}", + response.getStatus(), response.getStatusInfo(), response.getEntity().getClass()); + String entity = response.readEntity(String.class); + if (response.getStatusInfo().equals(Status.OK)) { + token = Jackson.getElement(entity, Constants.ACCESS_TOKEN); + } else { + throw new WebApplicationException( + "Error while Access Token is " + response.getStatusInfo() + " - " + entity); + } + } + + return token; + } + + public String getAllIdp(String idpUrl, String token) { + logger.info(" All IDP - idpUrl:{}", idpUrl); + + Builder client = getClientBuilder(idpUrl); + client.header(CONTENT_TYPE, MediaType.APPLICATION_JSON); + client.header(AUTHORIZATION, BEARER + token); + Response response = client.get(); + logger.debug("All IDP - response:{}", response); + + String identityProviderJsonList = null; + if (response != null) { + logger.trace( + "Fetch all IDP response.getStatus():{}, response.getStatusInfo():{}, response.getEntity().getClass():{}", + response.getStatus(), response.getStatusInfo(), response.getEntity().getClass()); + String entity = response.readEntity(String.class); + logger.trace("Get All IDP entity:{}", entity); + if (response.getStatusInfo().equals(Status.OK)) { + + identityProviderJsonList = entity; + } else { + throw new WebApplicationException( + "Error while fetching All IDP is " + response.getStatusInfo() + " - " + entity); + } + } + + return identityProviderJsonList; + } + + public String getIdp(String idpUrl, String token) { + logger.info(" Fetch IDP - idpUrl:{}", idpUrl); + Builder client = getClientBuilder(idpUrl); + client.header(CONTENT_TYPE, MediaType.APPLICATION_JSON); + client.header(AUTHORIZATION, BEARER + token); + Response response = client.get(); + logger.debug("Fetch IDP - response:{}", response); + String identityProviderJson = null; + if (response != null) { + logger.trace( + "IDP - response.getStatus():{}, response.getStatusInfo():{}, response.getEntity().getClass():{}", + response.getStatus(), response.getStatusInfo(), response.getEntity().getClass()); + String entity = response.readEntity(String.class); + if (response.getStatusInfo().equals(Status.OK)) { + identityProviderJson = entity; + + } else { + throw new WebApplicationException( + "Error while fetching IDP is " + response.getStatusInfo() + " - " + entity); + } + } + + return identityProviderJson; + } + + public Map extractSamlMetadata(final String idpMetadataConfigUrl, final String token, + final String providerId, String realmName, InputStream idpMetadataStream) throws JsonProcessingException { + Map config = null; + try { + logger.info("Saml Idp Metadata idpMetadataConfigUrl:{}, providerId:{}, realmName:{}, idpMetadataStream:{}", + idpMetadataConfigUrl, providerId, realmName, idpMetadataStream); + + if (StringUtils.isBlank(token)) { + throw new InvalidAttributeException(ACCESS_TOKEN_NULL); + } + if (idpMetadataStream == null) { + throw new InvalidAttributeException("Idp Metedata file is null!!!"); + } + + Builder request = getClientBuilder(idpMetadataConfigUrl); + request.header(AUTHORIZATION, BEARER + token); + MultipartFormDataOutput formData = new MultipartFormDataOutput(); + formData.addFormData("providerId", providerId, MediaType.TEXT_PLAIN_TYPE); + logger.debug("SAML idpMetadataStream.available():{}", idpMetadataStream.available()); + + byte[] content = idpMetadataStream.readAllBytes(); + logger.debug("content:{}", content); + String body = new String(content, StandardCharsets.UTF_8); + formData.addFormData("file", body, MediaType.APPLICATION_OCTET_STREAM_TYPE); + + logger.info("Request for SAML metadata import - formData:{}", formData); + Entity formDataEntity = Entity.entity(formData, MediaType.MULTIPART_FORM_DATA); + Response response = request.post(formDataEntity); + logger.trace("Response for SAML metadata import- response:{}", response); + + if (response != null) { + logger.trace( + "extract Saml Metadata - response.getStatus():{}, response.getStatusInfo():{}, response.getEntity().getClass():{}", + response.getStatus(), response.getStatusInfo(), response.getEntity().getClass()); + String entity = response.readEntity(String.class); + + if (response.getStatusInfo().equals(Status.OK)) { + ObjectMapper mapper = Jackson.createJsonMapper(); + config = mapper.readValue(entity, Map.class); - public static Response requestAccessToken(final String idpServerUrl, final String tokenUrl, final String clientId, - final String clientSecret, final String scope) { - log.info("Request for Access Token - idpServerUrl:{}, tokenUrl:{}, clientId:{}, clientSecret:{}, scope:{} ", idpServerUrl, tokenUrl, - clientId, clientSecret, scope); - Response response = null; + } else { + throw new WebApplicationException( + "Error while validating SAML IDP Metadata " + response.getStatusInfo() + " - " + entity); + } + } + + } catch (Exception ex) { + throw new WebApplicationException("Error while validating SAML IDP Metadata", ex); + } + + return config; + } + + public String createUpdateIdp(final String idpUrl, final String token, boolean isUpdate, + JSONObject identityProviderJson) { + String idpJson = null; try { - Builder request = getClientBuilder(tokenUrl); - request.header("Authorization", "Basic " + clientId+":"+clientSecret); - request.header(CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED); - final MultivaluedHashMap multivaluedHashMap = new MultivaluedHashMap<>(); - multivaluedHashMap.add( "client_id", clientId); - multivaluedHashMap.add( "client_secret", clientSecret); - multivaluedHashMap.add( "grant_type", "client_credentials"); - multivaluedHashMap.add( "redirect_uri", idpServerUrl); - log.debug("Request for Access Token - multivaluedHashMap:{}", multivaluedHashMap); - - response = request.post(Entity.form(multivaluedHashMap)); - log.debug("Response for Access Token - response:{}", response); - if (response.getStatus() == 200) { + logger.info("Add/modify IDP idpUrl:{}, isUpdate:{}, identityProviderJson:{}", idpUrl, isUpdate, + identityProviderJson); + + if (StringUtils.isBlank(idpUrl)) { + throw new InvalidAttributeException(IDP_URL_NULL); + } + if (StringUtils.isBlank(token)) { + throw new InvalidAttributeException(ACCESS_TOKEN_NULL); + } + if (identityProviderJson == null) { + throw new InvalidAttributeException("IDP Json object is null!!!"); + } + + Builder request = getClientBuilder(idpUrl); + request.header(AUTHORIZATION, BEARER + token); + request.header(CONTENT_TYPE, MediaType.APPLICATION_JSON); + Response response = null; + + if (isUpdate) { + logger.trace(" Update SAML IDP in KC server - identityProviderJson.toMap():{}", + identityProviderJson.toMap()); + response = request.put(Entity.json(identityProviderJson.toMap())); + } else { + logger.trace(" Create SAML IDP in KC server - identityProviderJson.toMap():{}", + identityProviderJson.toMap()); + response = request.post(Entity.json(identityProviderJson.toMap())); + } + + logger.debug("Response for SAML IDP - response:{}", response); + + if (response != null) { + logger.debug( + "IDP Add/Update - isUpdate:{}, response.getStatus():{}, response.getStatusInfo():{}, response.getEntity():{},response.getStatusInfo().equals(Status.OK):{}, response.getStatusInfo().equals(Status.CREATED):{}, , response.getStatusInfo().equals(Status.NO_CONTENT):{}", + isUpdate, response.getStatus(), response.getStatusInfo(), response.getEntity(), + response.getStatusInfo().equals(Status.OK), response.getStatusInfo().equals(Status.CREATED), + response.getStatusInfo().equals(Status.NO_CONTENT)); String entity = response.readEntity(String.class); - log.trace("Access Token - entity:{}", entity); - return response; + logger.debug("Add/Update IDP entity:{}", entity); + if (response.getStatusInfo().equals(Status.OK) || response.getStatusInfo().equals(Status.CREATED)) { + logger.debug( + "Successful response for Add/Update IDP - identityProviderJson:{}, status:{}, entity:{}", + identityProviderJson, response.getStatusInfo(), entity); + + } else { + logger.error("Error while creating/updating IDP - identityProviderJson:{}, status:{}, entity:{}", + identityProviderJson, response.getStatusInfo(), entity); + throw new WebApplicationException("Error while creating/updating IDP" + identityProviderJson + + ", Status is " + response.getStatusInfo() + " - " + entity); + } + String name = identityProviderJson.getString(Constants.ALIAS); + logger.debug("Add/Update IDP Id - name:{}", name); + idpJson = getIdp(idpUrl + "/" + name, token); + logger.debug("Added/Updated IDP - idpJson:{}", idpJson); + } + + } catch (Exception ex) { + throw new ConfigurationException("Error while add/updating SAML IDP", ex); + } + + return idpJson; + } + + public boolean deleteIdp(final String idpUrl, final String token) { + boolean isDeleted = false; + try { + logger.info("Delete IDP idpUrl:{}", idpUrl); + + if (StringUtils.isBlank(idpUrl)) { + throw new InvalidAttributeException(IDP_URL_NULL); } - } catch(Exception ex){ - log.error("IdpClientFactory Exception requestAccessToken is - ", ex); - }finally { - + if (StringUtils.isBlank(token)) { + throw new InvalidAttributeException(ACCESS_TOKEN_NULL); + } + + Builder request = getClientBuilder(idpUrl); + request.header(AUTHORIZATION, BEARER + token); + request.header(CONTENT_TYPE, MediaType.APPLICATION_JSON); + Response response = request.delete(); + logger.debug("Response for SAML IDP deletion - response:{}", response); if (response != null) { - response.close(); + logger.trace( + "Delete IDP - response.getStatus():{}, response.getStatusInfo():{}, response.getEntity():{}", + response.getStatus(), response.getStatusInfo(), response.getEntity()); + String entity = response.readEntity(String.class); + logger.trace("Delete IDP entity:{}", entity); + if (response.getStatusInfo().equals(Status.NO_CONTENT)) { + isDeleted = true; + } else { + throw new WebApplicationException( + "Error while deleting IDP " + response.getStatusInfo() + " - " + entity); + } } + + } catch (Exception ex) { + throw new ConfigurationException("Error while deleting SAML IDP", ex); } - return response; + + return isDeleted; } - public Response getSpMetadata(String metadataEndpoint) { - log.info(" SP Metadata - metadataEndpoint:{}", metadataEndpoint); - Builder metadataClient = getClientBuilder(metadataEndpoint); - metadataClient.header(CONTENT_TYPE, MediaType.APPLICATION_JSON); - Response response = metadataClient.get(); - log.debug("SpMetadata- response:{}", response); - - if (response != null ) { - log.trace("SP metadata response.getStatusInfo():{}, response.getEntity():{}, response.getEntity().getClass():{}", - response.getStatusInfo(), response.getEntity(),response.getEntity().getClass()); + public String getSpMetadata(String metadataEndpoint, final String token) { + logger.info(" SP Metadata - metadataEndpoint:{}", metadataEndpoint); + String jsonStrn = null; + + Builder request = getClientBuilder(metadataEndpoint); + request.header(AUTHORIZATION, BEARER + token); + request.header(CONTENT_TYPE, MediaType.APPLICATION_JSON); + Response response = request.get(); + logger.debug("SpMetadata- response:{}", response); + + if (response != null) { + logger.trace( + "IDP Add/Update - response.getStatus():{}, response.getStatusInfo():{}, response.getEntity().getClass():{}", + response.getStatus(), response.getStatusInfo(), response.getEntity().getClass()); + if (response.getStatusInfo().equals(Status.OK)) { + jsonStrn = response.readEntity(String.class); + } else { + throw new WebApplicationException( + "Error while fetching SP Metadata " + response.getStatusInfo() + " - " + jsonStrn); + } } - - return response; + return jsonStrn; } - private static Builder getClientBuilder(String url) { return ClientBuilder.newClient().target(url).request(); - } + } } diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/SamlAppInitializer.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/SamlAppInitializer.java index b59922c571b..1e1c350610b 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/SamlAppInitializer.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/SamlAppInitializer.java @@ -6,17 +6,12 @@ package io.jans.configapi.plugin.saml.configuration; -import io.jans.as.common.service.common.ApplicationFactory; import io.jans.configapi.plugin.saml.timer.MetadataValidationTimer; -import io.jans.orm.PersistenceEntryManager; -import io.jans.service.timer.QuartzSchedulerManager; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.BeforeDestroyed; import jakarta.enterprise.event.Observes; -import jakarta.enterprise.inject.Instance; import jakarta.enterprise.inject.Produces; -import jakarta.enterprise.inject.spi.BeanManager; import jakarta.inject.Inject; import jakarta.inject.Named; import jakarta.servlet.ServletContext; @@ -30,20 +25,9 @@ public class SamlAppInitializer { @Inject Logger log; - @Inject - @Named(ApplicationFactory.PERSISTENCE_ENTRY_MANAGER_NAME) - Instance persistenceEntryManagerInstance; - - @Inject - BeanManager beanManager; - @Inject SamlConfigurationFactory samlConfigurationFactory; - - @Inject - QuartzSchedulerManager quartzSchedulerManager; - @Inject MetadataValidationTimer metadataValidationTimer; @@ -53,23 +37,11 @@ public void onAppStart() { // configuration this.samlConfigurationFactory.create(); - initSchedulerService(); metadataValidationTimer.initTimer(); log.info("============== SAML Plugin IS UP AND RUNNING ==================="); } - - - protected void initSchedulerService() { - log.debug("Initializing Scheduler Service"); - quartzSchedulerManager.start(); - - String disableScheduler = System.getProperties().getProperty("gluu.disable.scheduler"); - if (Boolean.parseBoolean(disableScheduler)) { - this.log.warn("Suspending Quartz Scheduler Service..."); - quartzSchedulerManager.standby(); - } - } + public void destroy(@Observes @BeforeDestroyed(ApplicationScoped.class) ServletContext init) { log.info("================================================================"); diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/SamlConfigurationFactory.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/SamlConfigurationFactory.java index 913b582a294..e3c0f14b163 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/SamlConfigurationFactory.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/SamlConfigurationFactory.java @@ -217,8 +217,7 @@ private void initSamlConf(SamlConf samlConf) { this.samlAppConfiguration, samlLoadedRevision); } - - + private T loadConfigurationFromDb(String dn, T obj, String... returnAttributes) { log.debug("loadConfigurationFromDb dn:{}, clazz:{}, returnAttributes:{}", dn, obj, returnAttributes); final PersistenceEntryManager persistenceEntryManager = persistenceEntryManagerInstance.get(); diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/kc/KeycloakConfig.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/kc/KeycloakConfig.java deleted file mode 100644 index 5b9d053b54f..00000000000 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/configuration/kc/KeycloakConfig.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.jans.configapi.plugin.saml.configuration.kc; - -import io.jans.util.exception.InvalidConfigurationException; -import io.jans.configapi.plugin.saml.service.SamlConfigService; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.keycloak.admin.client.Keycloak; - -@ApplicationScoped -public class KeycloakConfig { - - private static Logger log = LoggerFactory.getLogger(KeycloakConfig.class); - - @Inject - SamlConfigService samlConfigService; - - public Keycloak getInstance() { - log.info("Keycloak instance entry - samlConfigService:{}", samlConfigService); - - if(samlConfigService==null || samlConfigService.find()==null) { - throw new InvalidConfigurationException("Cannot create Keycloak Instance as SAML Config is null!"); - } - - log.trace("Keycloak instance entry - samlConfigService.find():{}", samlConfigService.find()); - - return getInstance(samlConfigService.getServerUrl(), samlConfigService.getRealm(), - samlConfigService.getUsername(), samlConfigService.getPassword(), samlConfigService.getClientId(), - samlConfigService.getClientSecret()); - } - - public Keycloak getInstance(String serverUrl, String realm, String username, String password, String clientId, - String clientSecret) { - log.info( - "Keycloak instance param serverUrl:{}, realm:{}, username:{}, password:{}, clientId:{}, clientSecret:{} ", - serverUrl, realm, username, password, clientId, clientSecret); - Keycloak keycloak = Keycloak.getInstance(serverUrl, realm, username, password, clientId, clientSecret); - log.info("keycloak:{} ", keycloak); - return keycloak; - } - -} diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/mapper/IdentityProviderMapper.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/mapper/IdentityProviderMapper.java deleted file mode 100644 index b45b136393b..00000000000 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/mapper/IdentityProviderMapper.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.saml.mapper; - - -import io.jans.configapi.plugin.saml.model.IdentityProvider; -import jakarta.enterprise.context.ApplicationScoped; - -import org.keycloak.representations.idm.IdentityProviderRepresentation; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.factory.Mappers; - - -@Mapper -@ApplicationScoped -public interface IdentityProviderMapper { - - IdentityProviderMapper INSTANCE = Mappers.getMapper(IdentityProviderMapper.class); - - @Mapping(target = "inum", source = "kcIdentityProviderRepresentation.internalId") - @Mapping(target = "name", source = "kcIdentityProviderRepresentation.alias") - IdentityProvider kcIdentityProviderToIdentityProvider(IdentityProviderRepresentation kcIdentityProviderRepresentation); - - @Mapping(target = "internalId", source = "identityProvider.inum") - @Mapping(target = "alias", source = "identityProvider.name") - IdentityProviderRepresentation identityProviderToKCIdentityProvider(IdentityProvider identityProvider); -} diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/EntityType.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/EntityType.java index 1e218fa715d..019c1ff997a 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/EntityType.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/EntityType.java @@ -18,7 +18,7 @@ public enum EntityType implements AttributeEnum { private final String value; private final String displayName; - private static final Map mapByValues = new HashMap(); + private static final Map mapByValues = new HashMap<>(); static { for (EntityType enumType : values()) { mapByValues.put(enumType.getValue(), enumType); 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 4c207e41291..024d000dc40 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 @@ -12,14 +12,11 @@ import io.jans.model.GluuStatus; import io.jans.orm.annotation.AttributeName; import io.jans.orm.annotation.DataEntry; -import io.jans.orm.annotation.JsonObject; import io.jans.orm.annotation.ObjectClass; import io.jans.orm.model.base.Entry; import io.swagger.v3.oas.annotations.Hidden; import java.util.List; -import java.util.HashMap; -import java.util.Map; import java.io.Serializable; import jakarta.validation.constraints.NotNull; @@ -59,8 +56,8 @@ public class IdentityProvider extends Entry implements Serializable { @AttributeName(name = "jansEnabled") private boolean enabled; - @AttributeName(name = "signingCertificates") - private String signingCertificates; + @AttributeName(name = "signingCertificate") + private String signingCertificate; @AttributeName(name = "validateSignature") private String validateSignature; @@ -132,11 +129,6 @@ public class IdentityProvider extends Entry implements Serializable { @AttributeName(name = "jansValidationLog") private List validationLog; - - @Hidden - @JsonObject - @AttributeName(name = "jansSAMLidpConfDyn") - private Map config = new HashMap<>(); public String getInum() { return inum; @@ -192,14 +184,14 @@ public boolean isEnabled() { public void setEnabled(boolean enabled) { this.enabled = enabled; - } + } - public String getSigningCertificates() { - return signingCertificates; + public String getSigningCertificate() { + return signingCertificate; } - public void setSigningCertificates(String signingCertificates) { - this.signingCertificates = signingCertificates; + public void setSigningCertificate(String signingCertificate) { + this.signingCertificate = signingCertificate; } public String getValidateSignature() { @@ -385,20 +377,12 @@ public List getValidationLog() { public void setValidationLog(List validationLog) { this.validationLog = validationLog; } - - public Map getConfig() { - return config; - } - - public void setConfig(Map config) { - this.config = config; - } @Override public String toString() { return "IdentityProvider [inum=" + inum + ", creatorId=" + creatorId + ", name=" + name + ", displayName=" + displayName + ", description=" + description + ", realm=" + realm + ", enabled=" + enabled - + ", signingCertificates=" + signingCertificates + ", validateSignature=" + validateSignature + + ", signingCertificate=" + signingCertificate + ", validateSignature=" + validateSignature + ", singleLogoutServiceUrl=" + singleLogoutServiceUrl + ", nameIDPolicyFormat=" + nameIDPolicyFormat + ", idpEntityId=" + idpEntityId + ", singleSignOnServiceUrl=" + singleSignOnServiceUrl + ", encryptionPublicKey=" + encryptionPublicKey + ", providerId=" + providerId + ", trustEmail=" @@ -408,8 +392,8 @@ public String toString() { + postBrokerLoginFlowAlias + ", spMetaDataFN=" + spMetaDataFN + ", spMetaDataURL=" + spMetaDataURL + ", spMetaDataLocation=" + spMetaDataLocation + ", idpMetaDataFN=" + idpMetaDataFN + ", idpMetaDataURL=" + idpMetaDataURL + ", idpMetaDataLocation=" + idpMetaDataLocation + ", status=" - + status + ", validationStatus=" + validationStatus + ", validationLog=" + validationLog + ", config=" - + config + "]"; + + status + ", validationStatus=" + validationStatus + ", validationLog=" + validationLog + + "]"; } } diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/config/SamlAppConfiguration.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/config/SamlAppConfiguration.java index c18c68d7776..217aad9406b 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/config/SamlAppConfiguration.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/config/SamlAppConfiguration.java @@ -19,9 +19,13 @@ public class SamlAppConfiguration implements Configuration { private String clientId; private String clientSecret; private String grantType; + private String scope; private String username; private String password; private String spMetadataUrl; + private String tokenUrl; + private String idpUrl; + private String idpMetadataImportUrl; private String idpRootDir; private String idpMetadataDir; @@ -37,212 +41,264 @@ public class SamlAppConfiguration implements Configuration { private boolean ignoreValidation; private List idpMetadataMandatoryAttributes; - + private List kcAttributes; + private List kcSamlConfig; + public String getApplicationName() { return applicationName; } - + public void setApplicationName(String applicationName) { this.applicationName = applicationName; } - + public String getSamlTrustRelationshipDn() { return samlTrustRelationshipDn; } - + public void setSamlTrustRelationshipDn(String samlTrustRelationshipDn) { this.samlTrustRelationshipDn = samlTrustRelationshipDn; } - + public String getTrustedIdpDn() { return trustedIdpDn; } - + public void setTrustedIdpDn(String trustedIdpDn) { this.trustedIdpDn = trustedIdpDn; } - + public boolean isEnabled() { return enabled; } - + public void setEnabled(boolean enabled) { this.enabled = enabled; } - + public String getSelectedIdp() { return selectedIdp; } - + public void setSelectedIdp(String selectedIdp) { this.selectedIdp = selectedIdp; } - + public String getServerUrl() { return serverUrl; } - + public void setServerUrl(String serverUrl) { this.serverUrl = serverUrl; } - + public String getRealm() { return realm; } - + public void setRealm(String realm) { this.realm = realm; } - + public String getClientId() { return clientId; } - + public void setClientId(String clientId) { this.clientId = clientId; } - + public String getClientSecret() { return clientSecret; } - + public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } - + public String getGrantType() { return grantType; } - + public void setGrantType(String grantType) { this.grantType = grantType; } - + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + public String getUsername() { return username; } - + public void setUsername(String username) { this.username = username; } - + public String getPassword() { return password; } - + public void setPassword(String password) { this.password = password; } - + public String getSpMetadataUrl() { return spMetadataUrl; } - + public void setSpMetadataUrl(String spMetadataUrl) { this.spMetadataUrl = spMetadataUrl; } - + + public String getTokenUrl() { + return tokenUrl; + } + + public void setTokenUrl(String tokenUrl) { + this.tokenUrl = tokenUrl; + } + + public String getIdpUrl() { + return idpUrl; + } + + public void setIdpUrl(String idpUrl) { + this.idpUrl = idpUrl; + } + + public String getIdpMetadataImportUrl() { + return idpMetadataImportUrl; + } + + public void setIdpMetadataImportUrl(String idpMetadataImportUrl) { + this.idpMetadataImportUrl = idpMetadataImportUrl; + } + public String getIdpRootDir() { return idpRootDir; } - + public void setIdpRootDir(String idpRootDir) { this.idpRootDir = idpRootDir; } - + public String getIdpMetadataDir() { return idpMetadataDir; } - + public void setIdpMetadataDir(String idpMetadataDir) { this.idpMetadataDir = idpMetadataDir; } - + public String getIdpMetadataTempDir() { return idpMetadataTempDir; } - + public void setIdpMetadataTempDir(String idpMetadataTempDir) { this.idpMetadataTempDir = idpMetadataTempDir; } - + public String getIdpMetadataFilePattern() { return idpMetadataFilePattern; } - + public void setIdpMetadataFilePattern(String idpMetadataFilePattern) { this.idpMetadataFilePattern = idpMetadataFilePattern; } - + public String getIdpMetadataFile() { return idpMetadataFile; } - + public void setIdpMetadataFile(String idpMetadataFile) { this.idpMetadataFile = idpMetadataFile; } - + public String getSpMetadataDir() { return spMetadataDir; } - + public void setSpMetadataDir(String spMetadataDir) { this.spMetadataDir = spMetadataDir; } - + public String getSpMetadataTempDir() { return spMetadataTempDir; } - + public void setSpMetadataTempDir(String spMetadataTempDir) { this.spMetadataTempDir = spMetadataTempDir; } - + public String getSpMetadataFilePattern() { return spMetadataFilePattern; } - + public void setSpMetadataFilePattern(String spMetadataFilePattern) { this.spMetadataFilePattern = spMetadataFilePattern; } - + public String getSpMetadataFile() { return spMetadataFile; } - + public void setSpMetadataFile(String spMetadataFile) { this.spMetadataFile = spMetadataFile; } - + public boolean isIgnoreValidation() { return ignoreValidation; } - + public void setIgnoreValidation(boolean ignoreValidation) { this.ignoreValidation = ignoreValidation; } - + public List getIdpMetadataMandatoryAttributes() { return idpMetadataMandatoryAttributes; } - + public void setIdpMetadataMandatoryAttributes(List idpMetadataMandatoryAttributes) { this.idpMetadataMandatoryAttributes = idpMetadataMandatoryAttributes; } - + + public List getKcAttributes() { + return kcAttributes; + } + + public void setKcAttributes(List kcAttributes) { + this.kcAttributes = kcAttributes; + } + + public List getKcSamlConfig() { + return kcSamlConfig; + } + + public void setKcSamlConfig(List kcSamlConfig) { + this.kcSamlConfig = kcSamlConfig; + } + @Override public String toString() { return "SamlAppConfiguration [applicationName=" + applicationName + ", samlTrustRelationshipDn=" + samlTrustRelationshipDn + ", trustedIdpDn=" + trustedIdpDn + ", enabled=" + enabled + ", selectedIdp=" + selectedIdp + ", serverUrl=" + serverUrl + ", realm=" + realm + ", clientId=" + clientId - + ", clientSecret=" + clientSecret + ", grantType=" + grantType + ", username=" + username - + ", password=" + password + ", spMetadataUrl=" + spMetadataUrl + ", idpRootDir=" + idpRootDir + + ", clientSecret=" + clientSecret + ", grantType=" + grantType + ", scope=" + scope + ", username=" + + username + ", password=" + password + ", spMetadataUrl=" + spMetadataUrl + ", tokenUrl=" + tokenUrl + + ", idpUrl=" + idpUrl + ", idpMetadataImportUrl=" + idpMetadataImportUrl + ", idpRootDir=" + idpRootDir + ", idpMetadataDir=" + idpMetadataDir + ", idpMetadataTempDir=" + idpMetadataTempDir + ", idpMetadataFilePattern=" + idpMetadataFilePattern + ", idpMetadataFile=" + idpMetadataFile + ", spMetadataDir=" + spMetadataDir + ", spMetadataTempDir=" + spMetadataTempDir + ", spMetadataFilePattern=" + spMetadataFilePattern + ", spMetadataFile=" + spMetadataFile + ", ignoreValidation=" + ignoreValidation + ", idpMetadataMandatoryAttributes=" - + idpMetadataMandatoryAttributes + "]"; + + idpMetadataMandatoryAttributes + ", kcAttributes=" + kcAttributes + ", kcSamlConfig=" + kcSamlConfig + + "]"; } - + } diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/ApiApplication.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/ApiApplication.java index 49285a5036c..50384cc65e8 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/ApiApplication.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/ApiApplication.java @@ -1,5 +1,6 @@ package io.jans.configapi.plugin.saml.rest; +import io.jans.configapi.core.configuration.ObjectMapperContextResolver; import io.jans.configapi.core.rest.BaseApiApplication; import io.jans.configapi.plugin.saml.util.Constants; import io.swagger.v3.oas.annotations.OpenAPIDefinition; @@ -33,7 +34,7 @@ } ))) public class ApiApplication extends BaseApiApplication { - + @Override public Set> getClasses() { HashSet> classes = new HashSet<>(); @@ -41,6 +42,9 @@ public Set> getClasses() { // General classes = (HashSet) addCommonClasses((classes)); + // General Application level class + classes.add(ObjectMapperContextResolver.class); + classes.add(SamlConfigResource.class); classes.add(TrustRelationshipResource.class); classes.add(IdpResource.class); diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/IdpResource.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/IdpResource.java index 828ab35bf03..ffcb5fffa29 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/IdpResource.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/IdpResource.java @@ -41,9 +41,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.slf4j.Logger; import org.jboss.resteasy.annotations.providers.multipart.MultipartForm; @@ -131,13 +129,17 @@ public Response getSamlSPMetadataJson( if (log.isInfoEnabled()) { log.info("Fetch SAML SP Metadata for IDP by inum:{}", escapeLog(inum)); } - IdentityProvider identityProvider = idpService.getIdentityProviderByInum(inum); - log.debug(" identityProvider:{} ", identityProvider); - checkResourceNotNull(identityProvider, SAML_IDP_CHECK_STR + inum + "'"); - Response response = idpService.getSpMetadata(identityProvider); - log.info(" response:{} ", response); - - return Response.ok(response.getEntity()).build(); + String json = null; + try { + IdentityProvider identityProvider = idpService.getIdentityProviderByInum(inum); + log.debug(" identityProvider:{} ", identityProvider); + checkResourceNotNull(identityProvider, SAML_IDP_CHECK_STR + inum + "'"); + json = idpService.getSpMetadata(identityProvider); + log.info(" json:{} ", json); + } catch (Exception ex) { + throwInternalServerException("SAML_SP_METADATA", ex.getMessage()); + } + return Response.ok(json).build(); } @Operation(summary = "Get SAML SP Metadata Endpoint URL", description = "Get SAML SP Metadata Endpoint URL", operationId = "get-saml-sp-metadata-url", tags = { @@ -151,7 +153,7 @@ public Response getSamlSPMetadataJson( @Path(Constants.SP_METADATA_FILE_PATH + Constants.INUM_PATH_PARAM) @ProtectedApi(scopes = { Constants.JANS_IDP_SAML_READ_ACCESS }) @Produces(MediaType.APPLICATION_OCTET_STREAM) - public Response getSamlSPMetadataFile( + public Response getSamlSPMetadataURL( @Parameter(description = "Unique identifier") @PathParam(ApiConstants.INUM) @NotNull String inum) { if (log.isInfoEnabled()) { log.info("Fetch SAML SP Metadata URL IDP by inum:{}", escapeLog(inum)); @@ -202,9 +204,6 @@ public Response createSamlIdentityProvider(@MultipartForm BrokerIdentityProvider InputStream metaDataFile = brokerIdentityProviderForm.getMetaDataFile(); log.debug(" Create metaDataFile:{} ", metaDataFile); - populateIdpMetadataConfig(idp, metaDataFile); - log.info("IDP Creation checked if config to be populated idp:{}", idp); - // create SAML IDP try { idp = idpService.createSamlIdentityProvider(idp, metaDataFile); @@ -216,7 +215,6 @@ public Response createSamlIdentityProvider(@MultipartForm BrokerIdentityProvider } throwInternalServerException(ex); } - populateIdpMetadataElementsFromConfig(idp); log.info("Create IdentityProvider - idp:{}", idp); return Response.status(Response.Status.CREATED).entity(idp).build(); @@ -258,12 +256,8 @@ public Response updateSamlIdentityProvider(@MultipartForm BrokerIdentityProvider InputStream metaDataFile = brokerIdentityProviderForm.getMetaDataFile(); log.debug(" Update metaDataFile:{} ", metaDataFile); - populateIdpMetadataConfig(idp, metaDataFile); - log.info("IDP Creation checked if config to be populated idp:{}", idp); - // update SAML IDP idp = idpService.updateSamlIdentityProvider(idp, metaDataFile); - populateIdpMetadataElementsFromConfig(idp); log.info("Updated IdentityProvider idp:{}", idp); return Response.ok(idp).build(); @@ -311,80 +305,33 @@ public Response processMetadataFiles() { return Response.ok().build(); } - private IdentityProviderPagedResult doSearch(SearchRequest searchReq) - throws IllegalAccessException, InvocationTargetException { + private IdentityProviderPagedResult doSearch(SearchRequest searchReq) { + if (log.isInfoEnabled()) { log.info("IdentityProvider search params - searchReq:{} ", escapeLog(searchReq)); } + IdentityProviderPagedResult pagedIdentityProvider = null; + try { + PagedResult pagedResult = idpService.getIdentityProviders(searchReq); + if (log.isTraceEnabled()) { + log.debug("IdentityProvider PagedResult - pagedResult:{}", pagedResult); + } - PagedResult pagedResult = idpService.getIdentityProviders(searchReq); - if (log.isTraceEnabled()) { - log.debug("IdentityProvider PagedResult - pagedResult:{}", pagedResult); - } + pagedIdentityProvider = new IdentityProviderPagedResult(); + if (pagedResult != null) { + log.debug("IdentityProviders fetched - pagedResult.getEntries():{}", pagedResult.getEntries()); + List identityProviderList = pagedResult.getEntries(); + pagedIdentityProvider.setStart(pagedResult.getStart()); + pagedIdentityProvider.setEntriesCount(pagedResult.getEntriesCount()); + pagedIdentityProvider.setTotalEntriesCount(pagedResult.getTotalEntriesCount()); + pagedIdentityProvider.setEntries(identityProviderList); + } - IdentityProviderPagedResult pagedIdentityProvider = new IdentityProviderPagedResult(); - if (pagedResult != null) { - log.debug("IdentityProviders fetched - pagedResult.getEntries():{}", pagedResult.getEntries()); - List identityProviderList = pagedResult.getEntries(); - pagedIdentityProvider.setStart(pagedResult.getStart()); - pagedIdentityProvider.setEntriesCount(pagedResult.getEntriesCount()); - pagedIdentityProvider.setTotalEntriesCount(pagedResult.getTotalEntriesCount()); - pagedIdentityProvider.setEntries(identityProviderList); + log.info("pagedIdentityProvider:{}", pagedIdentityProvider); + } catch (Exception ex) { + throwInternalServerException(ex.getMessage()); } - - log.info("pagedIdentityProvider:{}", pagedIdentityProvider); return pagedIdentityProvider; } - private IdentityProvider populateIdpMetadataConfig(IdentityProvider idp, InputStream metaDataFile) - throws IOException { - log.info("Populate IDP Metadata config - idp:{}, metaDataFile:{}", idp, metaDataFile); - - if (idp == null || (metaDataFile != null && metaDataFile.available() > 0)) { - log.info("IDP metaDataFile for available():{}, hence no need to populate config.", - metaDataFile.available()); - return idp; - } - - // validate required fields - checkNotNull(idp.getSingleSignOnServiceUrl(), Constants.SINGLE_SIGN_ON_SERVICE_URL); - checkNotNull(idp.getIdpEntityId(), Constants.IDP_ENTITY_ID); - - Map config = new HashMap<>(); - config.put(Constants.SIGNING_CERTIFICATES, idp.getSigningCertificates()); - config.put(Constants.VALIDATE_SIGNATURE, idp.getValidateSignature()); - config.put(Constants.SINGLE_LOGOUT_SERVICE_URL, idp.getSingleLogoutServiceUrl()); - config.put(Constants.NAME_ID_POLICY_FORMAT, idp.getNameIDPolicyFormat()); - config.put(Constants.IDP_ENTITY_ID, idp.getIdpEntityId()); - config.put(Constants.SINGLE_SIGN_ON_SERVICE_URL, idp.getSingleSignOnServiceUrl()); - config.put(Constants.ENCRYPTION_PUBLIC_KEY, idp.getEncryptionPublicKey()); - log.info("Populated- config:{}", config); - - idp.setConfig(config); - - return idp; - } - - private IdentityProvider populateIdpMetadataElementsFromConfig(IdentityProvider idp) { - log.info("Populate IDP individual metadata elements - idp:{}", idp); - - if (idp == null || idp.getConfig() == null || idp.getConfig().isEmpty()) { - return idp; - } - - Map config = idp.getConfig(); - log.info("Populate IDP Metadata individual metadata elements - config:{}", config); - idp.setSigningCertificates(idp.getConfig().get(Constants.SIGNING_CERTIFICATES)); - idp.setValidateSignature(idp.getConfig().get(Constants.VALIDATE_SIGNATURE)); - idp.setSingleLogoutServiceUrl(idp.getConfig().get(Constants.SINGLE_LOGOUT_SERVICE_URL)); - idp.setNameIDPolicyFormat(idp.getConfig().get(Constants.NAME_ID_POLICY_FORMAT)); - idp.setIdpEntityId(idp.getConfig().get(Constants.IDP_ENTITY_ID)); - idp.setSingleSignOnServiceUrl(idp.getConfig().get(Constants.SINGLE_SIGN_ON_SERVICE_URL)); - idp.setEncryptionPublicKey(idp.getConfig().get(Constants.ENCRYPTION_PUBLIC_KEY)); - - log.info("Populated IDP object with individual metadata elements - idp:{}", idp); - - return idp; - } - } \ No newline at end of file diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/TrustRelationshipResource.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/TrustRelationshipResource.java index 80527602f6f..e897150dc36 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/TrustRelationshipResource.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/rest/TrustRelationshipResource.java @@ -20,7 +20,6 @@ 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; diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/IdentityProviderService.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/IdentityProviderService.java index cff3d76f0cb..8fa6e5dc94c 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/IdentityProviderService.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/IdentityProviderService.java @@ -6,18 +6,27 @@ package io.jans.configapi.plugin.saml.service; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; + import io.jans.as.common.model.registration.Client; -import io.jans.as.common.service.common.InumService; import io.jans.as.common.service.OrganizationService; +import io.jans.as.common.service.common.InumService; import io.jans.as.common.util.AttributeConstants; -import io.jans.util.exception.InvalidConfigurationException; import io.jans.configapi.configuration.ConfigurationFactory; -import io.jans.configapi.plugin.saml.service.SamlConfigService; -import io.jans.configapi.plugin.saml.service.SamlIdpService; +import io.jans.configapi.plugin.saml.model.IdentityProvider; import io.jans.configapi.plugin.saml.timer.MetadataValidationTimer; import io.jans.configapi.plugin.saml.util.Constants; -import io.jans.configapi.plugin.saml.model.IdentityProvider; - import io.jans.model.GluuStatus; import io.jans.model.SearchRequest; import io.jans.orm.PersistenceEntryManager; @@ -25,23 +34,10 @@ import io.jans.orm.model.SortOrder; import io.jans.orm.search.filter.Filter; import io.jans.util.StringHelper; - +import io.jans.util.exception.InvalidConfigurationException; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; - @ApplicationScoped public class IdentityProviderService { @@ -69,7 +65,6 @@ public class IdentityProviderService { @Inject MetadataValidationTimer metadataValidationTimer; - public boolean containsIdentityProvider(String dn) { return persistenceEntryManager.contains(dn, IdentityProvider.class); } @@ -117,7 +112,7 @@ public IdentityProvider getIdentityProviderByInum(String inum) { try { result = persistenceEntryManager.find(IdentityProvider.class, getDnForIdentityProvider(inum)); } catch (Exception ex) { - log.error("Failed to load IdentityProvider entry", ex); + log.error("Failed to load IdentityProvider entry", ex); } return result; } @@ -200,21 +195,14 @@ public PagedResult getIdentityProvider(SearchRequest searchReq } - public IdentityProvider addSamlIdentityProvider(IdentityProvider identityProvider, InputStream file) - throws IOException { + public IdentityProvider addSamlIdentityProvider(IdentityProvider identityProvider, InputStream file) { log.info("Add new identityProvider:{}, file:{}", identityProvider, file); - String inum = generateInumForIdentityProvider(); - identityProvider.setInum(inum); - identityProvider.setDn(getDnForIdentityProvider(inum)); - if (file != null) { log.info("Save IDP metadatfile on server"); saveIdpMetaDataFileSourceTypeFile(identityProvider, file); } - // Set default Value for SAML IDP - setSamlIdentityProviderDefaultValue(identityProvider, false); persistenceEntryManager.persist(identityProvider); return getIdentityProviderByInum(identityProvider.getInum()); @@ -234,8 +222,6 @@ public IdentityProvider updateIdentityProvider(IdentityProvider identityProvider saveIdpMetaDataFileSourceTypeFile(identityProvider, file); } - // Set default Value for SAML IDP - setSamlIdentityProviderDefaultValue(identityProvider, true); persistenceEntryManager.merge(identityProvider); return getIdentityProviderByInum(identityProvider.getInum()); @@ -282,23 +268,6 @@ public String generateInumForNewIdentityProvider() { return newInum; } - private IdentityProvider setSamlIdentityProviderDefaultValue(IdentityProvider identityProvider, boolean update) { - log.info("setting default value for identityProvider:{}, update:{}", identityProvider, update); - if (identityProvider == null) { - return identityProvider; - } - - //Set default Realm in-case null - if(StringUtils.isBlank(identityProvider.getRealm())){ - identityProvider.setRealm(Constants.REALM_MASTER); - } - - if (!update) { - identityProvider.setProviderId(Constants.SAML); - } - return identityProvider; - } - private boolean saveIdpMetaDataFileSourceTypeFile(IdentityProvider identityProvider, InputStream file) { log.info("Saving file identityProvider:{}, file:{}", identityProvider, file); @@ -310,14 +279,14 @@ private boolean saveIdpMetaDataFileSourceTypeFile(IdentityProvider identityProvi if ((file == null)) { log.debug("File is null"); if (emptyidpMetaDataFN) { - log.error("The trust relationship {} has an empty Metadata filename", identityProvider.getInum()); + log.debug("The trust relationship {} has an empty Metadata filename", identityProvider.getInum()); return false; } String filePath = getIdpMetadataTempDirFilePath(idpMetaDataFN); log.debug("filePath:{}", filePath); if (filePath == null) { - log.error("The trust relationship {} has an invalid Metadata file storage path", + log.debug("The trust relationship {} has an invalid Metadata file storage path", identityProvider.getInum()); return false; } @@ -328,7 +297,7 @@ private boolean saveIdpMetaDataFileSourceTypeFile(IdentityProvider identityProvi log.trace("newFile:{}", newFile); if (!newFile.exists()) { - log.error( + log.info( "The trust relationship {} metadata used local storage but the IDP metadata file `{}` was not found", identityProvider.getInum(), filePath); return false; @@ -346,8 +315,8 @@ private boolean saveIdpMetaDataFileSourceTypeFile(IdentityProvider identityProvi InputStream targetStream = file; log.debug("targetStream:{}, idpMetaDataFN:{}", targetStream, idpMetaDataFN); - String result = samlIdpService.saveMetadataFile(getIdpMetadataTempDirFilePath(), - idpMetaDataFN, Constants.IDP_MODULE, targetStream); + String result = samlIdpService.saveMetadataFile(getIdpMetadataTempDirFilePath(), idpMetaDataFN, + Constants.IDP_MODULE, targetStream); log.debug("targetStream:{}, idpMetaDataFN:{}", targetStream, idpMetaDataFN); if (StringHelper.isNotEmpty(result)) { metadataValidationTimer.idpQueue(result); @@ -370,7 +339,7 @@ private String getIdpNewMetadataFileName(IdentityProvider identityProvider) { getIdpMetadataFileName(identityProvider.getInum())); return getIdpMetadataFileName(identityProvider.getInum()); } - + private String getIdpMetadataTempDirFilePath(String idpMetaDataFN) { log.debug("idpMetaDataFN:{}", idpMetaDataFN); if (StringUtils.isBlank(getIdpMetadataTempDirFilePath())) { @@ -379,13 +348,12 @@ private String getIdpMetadataTempDirFilePath(String idpMetaDataFN) { return getIdpMetadataTempDirFilePath() + idpMetaDataFN; } - - + private String getIdpMetadataFileName(String inum) { String id = StringHelper.removePunctuation(inum); return String.format(samlConfigService.getIdpMetadataFilePattern(), id); } - + private String getIdpMetadataTempDirFilePath() { return samlConfigService.getIdpMetadataTempDir() + File.separator; } @@ -393,13 +361,13 @@ private String getIdpMetadataTempDirFilePath() { public void processUnprocessedIdpMetadataFiles() { log.info("Processing unprocessed IDP Metadata files "); String directory = samlConfigService.getIdpMetadataTempDir(); - log.trace("IDP Metadata directory:{}, Files.exists(Paths.get(directory):{}", directory, Files.exists(Paths.get(directory))); + log.trace("IDP Metadata directory:{}, Files.exists(Paths.get(directory):{}", directory, + Files.exists(Paths.get(directory))); if (Files.exists(Paths.get(directory))) { log.trace("IDP Metadata directory:{} does exists)", directory); File folder = new File(directory); File[] files = folder.listFiles(); - log.trace("IDP Metadata files:{}", files); if (files != null && files.length > 0) { for (File file : files) { diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/IdpService.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/IdpService.java index d4238224324..83481c9406d 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/IdpService.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/IdpService.java @@ -6,11 +6,14 @@ package io.jans.configapi.plugin.saml.service; +import com.fasterxml.jackson.core.JsonProcessingException; import io.jans.as.common.service.OrganizationService; +import io.jans.configapi.core.util.DataUtil; import io.jans.configapi.util.AuthUtil; + import io.jans.configapi.plugin.saml.client.IdpClientFactory; -import io.jans.configapi.plugin.saml.mapper.IdentityProviderMapper; import io.jans.configapi.plugin.saml.model.IdentityProvider; +import io.jans.configapi.plugin.saml.util.Constants; import io.jans.model.SearchRequest; import io.jans.orm.PersistenceEntryManager; import io.jans.orm.model.PagedResult; @@ -18,7 +21,6 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import jakarta.ws.rs.core.Response; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -28,8 +30,6 @@ import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; -import org.keycloak.representations.idm.IdentityProviderRepresentation; - @ApplicationScoped public class IdpService { @@ -51,9 +51,6 @@ public class IdpService { @Inject KeycloakService keycloakService; - @Inject - IdentityProviderMapper identityProviderMapper; - @Inject IdpClientFactory idpClientFactory; @@ -68,8 +65,8 @@ public String getSpMetadataUrl(String realm, String name) { return samlConfigService.getSpMetadataUrl(realm, name); } - public List getAllIdentityProviders() { - return this.identityProviderService.getAllIdentityProvider(0); + public List getAllIdentityProviders(String realmName) throws IOException { + return keycloakService.findAllIdentityProviders(realmName); } public IdentityProvider getIdentityProviderByInum(String inum) { @@ -84,6 +81,15 @@ public PagedResult getIdentityProviders(SearchRequest searchRe return identityProviderService.getIdentityProvider(searchRequest); } + public List getAllIdp(String realmName) throws IOException { + log.info("Fetch all IDP from realm:{}", realmName); + if (StringUtils.isBlank(realmName)) { + realmName = Constants.REALM_MASTER; + } + return keycloakService.findAllIdentityProviders(realmName); + + } + public IdentityProvider createSamlIdentityProvider(IdentityProvider identityProvider, InputStream idpMetadataStream) throws IOException { log.info( @@ -95,41 +101,19 @@ public IdentityProvider createSamlIdentityProvider(IdentityProvider identityProv throw new InvalidAttributeException("IdentityProvider object is null!!!"); } - if (idpMetadataStream != null && idpMetadataStream.available() > 0) { - // validate metadata and set in config - Map config = validateSamlMetadata(identityProvider.getRealm(), idpMetadataStream); - log.info("Validated metadata to create IDP - config:{}", config); - identityProvider.setConfig(config); - } else { - // ensure individual metadata elements are present - boolean validConfig = validateIdpMetadataElements(identityProvider); - log.info("Is metadata individual elements for IDP creation present:{}", validConfig); - } + // Set Inum + String inum = identityProviderService.generateInumForIdentityProvider(); + identityProvider.setInum(inum); + identityProvider.setDn(identityProviderService.getDnForIdentityProvider(inum)); + + // common code + identityProvider = processIdentityProvider(identityProvider, idpMetadataStream, false); + log.debug("Create IdentityProvider identityProvider:{}", identityProvider); // Create IDP in Jans DB - log.debug("Create IdentityProvider identityProvider:{})", identityProvider); identityProviderService.addSamlIdentityProvider(identityProvider, idpMetadataStream); - log.debug("Created IdentityProvider in Jans DB - identityProvider:{})", identityProvider); - - if (samlConfigService.isSamlEnabled()) { - // Create IDP in KC - IdentityProviderRepresentation kcIdp = this.convertToIdentityProviderRepresentation(identityProvider); - log.debug("converted kcIdp:{}", kcIdp); - - log.debug("IDP Service idpMetadataStream:{}, identityProvider.getRealm():{}", idpMetadataStream, - identityProvider.getRealm()); - kcIdp = keycloakService.createIdentityProvider(identityProvider.getRealm(), kcIdp); - log.debug("Newly created kcIdp:{}", kcIdp); - identityProvider = this.convertToIdentityProvider(identityProvider, kcIdp); - log.debug("Final created identityProvider:{}", identityProvider); + log.debug("Created IdentityProvider in Jans DB - identityProvider:{}", identityProvider); - // set KC SP MetadataURL name - if (identityProvider != null) { - String spMetadataUrl = getSpMetadataUrl(identityProvider.getRealm(), identityProvider.getName()); - log.info(" Setting KC SP Metadata URL - spMetadataUrl:{} ", spMetadataUrl); - identityProvider.setSpMetaDataURL(spMetadataUrl); - } - } return identityProvider; } @@ -144,67 +128,46 @@ public IdentityProvider updateSamlIdentityProvider(IdentityProvider identityProv throw new InvalidAttributeException("IdentityProvider object for update is null!!!"); } - if (idpMetadataStream != null && idpMetadataStream.available() > 0) { - // validate metadata and set in config - Map config = validateSamlMetadata(identityProvider.getRealm(), idpMetadataStream); - log.debug("Validated metadata to update IDP - config:{}", config); - identityProvider.setConfig(config); - } else { - // ensure individual metadata elements are present - boolean validConfig = validateIdpMetadataElements(identityProvider); - log.info("Is metadata individual for update elements present:{}", validConfig); - } - - // validate metadata and set in config - Map config = validateSamlMetadata(identityProvider.getRealm(), idpMetadataStream); - log.debug("Validated metadata to update config:{}", config); - identityProvider.setConfig(config); + // common code + identityProvider = processIdentityProvider(identityProvider, idpMetadataStream, true); + log.debug("Update IdentityProvider identityProvider:{}", identityProvider); // Update IDP in Jans DB updateIdentityProvider(identityProvider); - log.debug("Updated IdentityProvider dentityProvider:{}, , identityProvider.getRealm():{})", identityProvider, - identityProvider.getRealm()); - - if (samlConfigService.isSamlEnabled()) { - // Update IDP in KC - IdentityProviderRepresentation kcIdp = this.convertToIdentityProviderRepresentation(identityProvider); - log.debug("converted kcIdp:{}", kcIdp); - - kcIdp = keycloakService.updateIdentityProvider(identityProvider.getRealm(), kcIdp); - log.debug("Updated kcIdp:{}", kcIdp); - identityProvider = this.convertToIdentityProvider(identityProvider, kcIdp); - - // set KC SP MetadataURL name - if (identityProvider != null) { - String spMetadataUrl = getSpMetadataUrl(identityProvider.getRealm(), identityProvider.getName()); - log.info(" Updating KC SP Metadata URL - spMetadataUrl:{} ", spMetadataUrl); - identityProvider.setSpMetaDataURL(spMetadataUrl); - } - } + log.info("Updated IdentityProvider - identityProvider:{}", identityProvider); return identityProvider; } public void deleteIdentityProvider(IdentityProvider identityProvider) { + boolean status = false; + log.info("Delete dentityProvider:{}, samlConfigService.isSamlEnabled():{}", identityProvider, + samlConfigService.isSamlEnabled()); + // validate + if (identityProvider == null) { + throw new InvalidAttributeException("IdentityProvider object for delete is null!!!"); + } if (samlConfigService.isSamlEnabled()) { // Delete IDP in KC - keycloakService.deleteIdentityProvider(identityProvider.getRealm(), identityProvider.getName()); + status = keycloakService.deleteIdentityProvider(identityProvider.getRealm(), identityProvider.getName()); } + log.info("Delete IDP status:{},)", status); // Delete in Jans DB - identityProviderService.removeIdentityProvider(identityProvider); + if (status) { + identityProviderService.removeIdentityProvider(identityProvider); + } } public void processUnprocessedIdpMetadataFiles() { identityProviderService.processUnprocessedIdpMetadataFiles(); } - public Response getSpMetadata(IdentityProvider identityProvider) { - Response response = null; + public String getSpMetadata(IdentityProvider identityProvider) throws JsonProcessingException { + if (identityProvider == null) { - return response; + throw new InvalidAttributeException("IdentityProvider object is null!!!"); } - return idpClientFactory - .getSpMetadata(getSpMetadataUrl(identityProvider.getRealm(), identityProvider.getName())); + return keycloakService.getSpMetadata(identityProvider.getRealm(), identityProvider.getName()); } @@ -213,97 +176,138 @@ private IdentityProvider updateIdentityProvider(IdentityProvider identityProvide // Update IDP in Jans DB identityProviderService.updateIdentityProvider(identityProvider); - log.debug("Updated IdentityProvider in Jans DB - identityProvider:{})", identityProvider); + log.debug("Updated IdentityProvider in Jans DB - identityProvider:{}", identityProvider); return identityProvider; } - private Map validateSamlMetadata(String realmName, InputStream idpMetadataStream) { - return keycloakService.validateSamlMetadata(realmName, idpMetadataStream); - } + private IdentityProvider setSamlIdentityProviderDefaultValue(IdentityProvider identityProvider, boolean update) { + log.info("Setting default value for identityProvider:{}, update:{}", identityProvider, update); + if (identityProvider == null) { + return identityProvider; + } - private IdentityProvider convertToIdentityProvider(IdentityProvider identityProvider, - IdentityProviderRepresentation kcIdp) { - log.debug("identityProvider:{}, kcIdp:{}", identityProvider, kcIdp); - - IdentityProvider idp = this.convertToIdentityProvider(kcIdp); - log.info("convertToIdentityProvider - idp:{}", idp); - - if (idp != null && identityProvider != null) { - idp.setRealm(identityProvider.getRealm()); - idp.setSpMetaDataFN(identityProvider.getSpMetaDataFN()); - idp.setSpMetaDataURL(identityProvider.getSpMetaDataURL()); - idp.setSpMetaDataLocation(identityProvider.getSpMetaDataLocation()); - idp.setIdpMetaDataFN(identityProvider.getIdpMetaDataFN()); - idp.setIdpMetaDataLocation(identityProvider.getIdpMetaDataLocation()); - idp.setIdpMetaDataURL(identityProvider.getIdpMetaDataURL()); - idp.setStatus(identityProvider.getStatus()); - idp.setValidationStatus(identityProvider.getValidationStatus()); - idp.setValidationLog(identityProvider.getValidationLog()); + // Set default Realm in-case null + if (StringUtils.isBlank(identityProvider.getRealm())) { + identityProvider.setRealm(Constants.REALM_MASTER); } - return idp; + if (StringUtils.isBlank(identityProvider.getProviderId())) { + identityProvider.setProviderId(Constants.SAML); + } + return identityProvider; } - private IdentityProvider convertToIdentityProvider(IdentityProviderRepresentation kcIdp) { - log.debug("kcIdp:{}", kcIdp); - IdentityProvider idp = null; - if (kcIdp == null) { - return idp; + private IdentityProvider processIdentityProvider(IdentityProvider identityProvider, InputStream idpMetadataStream, + boolean isUpdate) throws IOException { + log.info("Common processing for identityProvider:{}, idpMetadataStream:{}, isUpdate:{}", identityProvider, + idpMetadataStream, isUpdate); + + if (identityProvider == null) { + return identityProvider; } - idp = identityProviderMapper.kcIdentityProviderToIdentityProvider(kcIdp); - log.info("convertToIdentityProvider - idp:{}", idp); - return idp; - } + // Set default Value for SAML IDP + setSamlIdentityProviderDefaultValue(identityProvider, isUpdate); - private IdentityProviderRepresentation convertToIdentityProviderRepresentation(IdentityProvider idp) { - log.info("idp:{}", idp); - IdentityProviderRepresentation kcIdp = null; - if (idp == null) { - return kcIdp; + // SAML IDP Metadata handling + if (idpMetadataStream != null && idpMetadataStream.available() > 0) { + Map config = validateSamlMetadata(identityProvider.getProviderId(), + identityProvider.getRealm(), idpMetadataStream); + log.debug("Validated metadata to create IDP - config:{}", config); + populateIdpMetadataElements(identityProvider, config); } - kcIdp = identityProviderMapper.identityProviderToKCIdentityProvider(idp); - log.debug("convert IdentityProviderRepresentation - kcIdp:{}", kcIdp); - log.trace( - "convert IDP data kcIdp.getAlias():{}, kcIdp.getInternalId():{}, kcIdp.getProviderId():{}, kcIdp.getConfig():{}, kcIdp.isEnabled():{}, kcIdp.isLinkOnly():{}, kcIdp.isStoreToken():{},kcIdp.getFirstBrokerLoginFlowAlias():{}, kcIdp.getPostBrokerLoginFlowAlias():{},kcIdp.isTrustEmail():{}", - kcIdp.getAlias(), kcIdp.getInternalId(), kcIdp.getProviderId(), kcIdp.getConfig(), kcIdp.isEnabled(), - kcIdp.isLinkOnly(), kcIdp.isStoreToken(), kcIdp.getFirstBrokerLoginFlowAlias(), - kcIdp.getPostBrokerLoginFlowAlias(), kcIdp.isTrustEmail()); + // ensure individual metadata elements are present + boolean validConfig = validateIdpMetadataElements(identityProvider); + log.info("Is metadata individual elements for IDP creation present:{}", validConfig); + + if (samlConfigService.isSamlEnabled()) { + // Create IDP in KC + log.info("Create/Update IDP Service idpMetadataStream:{}, identityProvider.getRealm():{}", + idpMetadataStream, identityProvider.getRealm()); + identityProvider = keycloakService.createUpdateIdentityProvider(identityProvider.getRealm(), isUpdate, + identityProvider); + + log.info("Newly created identityProvider:{}", identityProvider); + + // set KC SP MetadataURL name + if (identityProvider != null) { + String spMetadataUrl = getSpMetadataUrl(identityProvider.getRealm(), identityProvider.getName()); + log.debug(" Setting KC SP Metadata URL - spMetadataUrl:{} ", spMetadataUrl); + identityProvider.setSpMetaDataURL(spMetadataUrl); + } + } + return identityProvider; + } - return kcIdp; + private Map validateSamlMetadata(String prorviderId, String realmName, + InputStream idpMetadataStream) throws JsonProcessingException { + return keycloakService.importSamlMetadata(prorviderId, realmName, idpMetadataStream); } private boolean validateIdpMetadataElements(IdentityProvider identityProvider) { - log.info("identityProvider:{}, samlConfigService.getIdpMetadataMandatoryAttributes():{}", identityProvider, samlConfigService.getIdpMetadataMandatoryAttributes()); + log.info("identityProvider:{}, samlConfigService.getIdpMetadataMandatoryAttributes():{}", identityProvider, + samlConfigService.getIdpMetadataMandatoryAttributes()); boolean isValid = false; - if (identityProvider == null || identityProvider.getConfig() == null - || identityProvider.getConfig().isEmpty() || samlConfigService.getIdpMetadataMandatoryAttributes().isEmpty()) { + if (identityProvider == null || samlConfigService.getIdpMetadataMandatoryAttributes().isEmpty()) { isValid = true; return isValid; } List missingElements = null; - for(String attribute: samlConfigService.getIdpMetadataMandatoryAttributes()) { - log.info("attribute:{}", attribute); - if(StringUtils.isBlank(identityProvider.getConfig().get(attribute))){ - if(missingElements == null) { + for (String attribute : samlConfigService.getIdpMetadataMandatoryAttributes()) { + log.debug("attribute:{}, getValue(identityProvider, attribute):{}", attribute, + getValue(identityProvider, attribute)); + if (StringUtils.isBlank(getValue(identityProvider, attribute))) { + if (missingElements == null) { missingElements = new ArrayList<>(); } missingElements.add(attribute); - } + } } - + log.info("missingElements:{}", missingElements); if (missingElements != null && !missingElements.isEmpty()) { isValid = false; - log.error("IDP elements are missing:{}, isValid:{} !", missingElements, isValid); - throw new InvalidAttributeException("IDP mandatory attribute missing - "+missingElements+" !!!"); + log.debug("IDP elements are missing:{}, isValid:{} !", missingElements, isValid); + throw new InvalidAttributeException("IDP mandatory attribute missing - " + missingElements + " !!!"); } isValid = true; log.info("validateIdpMetadataElements - isValid:{}", isValid); return isValid; } + + private IdentityProvider populateIdpMetadataElements(IdentityProvider identityProvider, + Map config) { + log.info("identityProvider:{}, config:{}, samlConfigService.getKcSamlConfig():{}", identityProvider, config, + samlConfigService.getKcSamlConfig()); + + if (identityProvider == null || config == null || samlConfigService.getKcSamlConfig().isEmpty()) { + return identityProvider; + } + + for (String attribute : samlConfigService.getKcSamlConfig()) { + log.trace("attribute:{}, config.get(attribute):{}", attribute, + config.get(attribute)); + DataUtil.invokeReflectionSetter(identityProvider, attribute, config.get(attribute)); + } + + log.info("validateIdpMetadataElements - identityProvider:{}", identityProvider); + return identityProvider; + } + + private String getValue(IdentityProvider identityProvider, String property) { + log.debug("Get Field Value - identityProvider:{}, property:{}", identityProvider, property); + String value = null; + try { + value = (String) DataUtil.getValue(identityProvider, property); + log.debug("Field Value - property:{}, value:{}", property, value); + } catch (Exception ex) { + log.error("Error while getting value of config ", ex); + } + return value; + } + } diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/KeycloakService.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/KeycloakService.java index 22e00f3b25b..4bddc1efeea 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/KeycloakService.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/KeycloakService.java @@ -6,369 +6,347 @@ package io.jans.configapi.plugin.saml.service; -import io.jans.configapi.plugin.saml.configuration.kc.KeycloakConfig; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.jans.configapi.core.util.Jackson; +import io.jans.configapi.plugin.saml.client.IdpClientFactory; +import io.jans.configapi.plugin.saml.model.IdentityProvider; import io.jans.configapi.plugin.saml.util.Constants; import io.jans.util.exception.ConfigurationException; import io.jans.util.exception.InvalidAttributeException; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import java.util.*; - -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.MultivaluedHashMap; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.core.Response.Status; -import jakarta.ws.rs.core.Response.StatusType; -import jakarta.ws.rs.WebApplicationException; - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.io.InputStream; +import java.util.*; import org.apache.commons.lang.StringUtils; -import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; -import org.keycloak.admin.client.resource.IdentityProviderResource; -import org.keycloak.admin.client.resource.IdentityProvidersResource; -import org.keycloak.admin.client.resource.RealmResource; -import org.keycloak.admin.client.resource.RealmsResource; -import org.keycloak.representations.idm.IdentityProviderMapperRepresentation; -import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation; -import org.keycloak.representations.idm.IdentityProviderRepresentation; -import org.keycloak.representations.idm.RealmRepresentation; - +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.slf4j.Logger; @ApplicationScoped public class KeycloakService { + public static final String REALM_NAME_NULL = "Realm name is null!!!"; + @Inject Logger logger; @Inject - KeycloakConfig keycloakConfig; + IdpClientFactory idpClientFactory; - private RealmResource getRealmResource(String realm) { - logger.info("Get RealmResource for realm:{}", realm); - if (StringUtils.isBlank(realm)) { - realm = Constants.REALM_MASTER; - } - RealmResource realmResource = keycloakConfig.getInstance().realm(realm); - logger.debug("realmResource:{}", realmResource); - return realmResource; - } + @Inject + SamlConfigService samlConfigService; - + public List findAllIdentityProviders(String realmName) throws IOException { + logger.info("Fetch all IdentityProvider for realmName:{}, samlConfigService:{}", realmName, samlConfigService); - public IdentityProvidersResource getIdentityProvidersResource(String realmName) { if (StringUtils.isBlank(realmName)) { - throw new InvalidAttributeException("Realm name is null!!!"); + throw new InvalidAttributeException("IDP Realm name file is null!!!"); } - IdentityProvidersResource identityProvidersResource = getRealmResource(realmName).identityProviders(); - logger.debug("identityProvidersResource:{}", identityProvidersResource); - return identityProvidersResource; - } - public List findAllIdentityProviders(String realmName) { - logger.info("Fetch all IdentityProvider for realmName:{}", realmName); + // Get token + String token = this.getKcAccessToken(realmName); + String idpUrl = getIdpUrl(realmName); + logger.debug("Fetch all IdentityProvider for idpUrl:{}", idpUrl); - IdentityProvidersResource identityProvidersResource = this.getIdentityProvidersResource(realmName); - List identityProviders = identityProvidersResource.findAll(); + String idpListAsString = idpClientFactory.getAllIdp(idpUrl, token); + logger.info("Fetch all IdentityProvider for idpListAsString:{}", idpListAsString); - logger.info("identityProviders:{}", identityProviders); - - return identityProviders; + List identityProvider = createIdentityProviderList(idpListAsString); + logger.info("Fetch all IdentityProvider for realmName:{}, identityProvider:{}", realmName, identityProvider); + return identityProvider; } - public IdentityProviderRepresentation getIdentityProviderById(String realmName, String internalId) { - logger.info("Fetch IdentityProvider by id realmName:{}, internalId:{}", realmName, internalId); + public Map importSamlMetadata(String providerId, String realmName, InputStream idpMetadataStream) + throws JsonProcessingException { + logger.info("Import config providerId:{}, realmName:{}, idpMetadataStream:{} ", providerId, realmName, + idpMetadataStream); - if (StringUtils.isBlank(realmName) || StringUtils.isBlank(internalId)) { - throw new InvalidAttributeException("Realm name or IdentityProvider internalId is null!!!"); + if (StringUtils.isBlank(providerId)) { + throw new InvalidAttributeException("IDP ProviderId is null!!!"); } - List identityProviders = findAllIdentityProviders(realmName); - logger.debug("identityProviders:{}", identityProviders); - IdentityProviderRepresentation identityProvider = null; - if (identityProviders == null || identityProviders.isEmpty()) { - return identityProvider; + if (StringUtils.isBlank(realmName)) { + throw new InvalidAttributeException("IDP Realm name file is null!!!"); } - for (IdentityProviderRepresentation data : identityProviders) { - if (internalId.equals(data.getInternalId())) { - identityProvider = data; - break; - } + if (idpMetadataStream == null) { + throw new InvalidAttributeException("IDP Metedata file is null!!!"); } - logger.info("IdentityProvider fetched by id realmName:{}, internalId:{}, identityProvider:{}", realmName, - internalId, identityProvider); - return identityProvider; - } - public IdentityProviderRepresentation getIdentityProviderByName(String realmName, String alias) { - logger.info("Get IdentityProvider by name realmName:{}, alias:{}", realmName, alias); + // Get token + String token = this.getKcAccessToken(realmName); + String samlMetadataImportUrl = this.getSamlMetadataImportUrl(realmName); + logger.info(" samlMetadataImportUrl:{}", samlMetadataImportUrl); - if (StringUtils.isBlank(realmName) || StringUtils.isBlank(alias)) { - throw new InvalidAttributeException("Realm name or IdentityProvider alias is null!!!"); - } - - List identityProviders = findAllIdentityProviders(realmName); - logger.debug("identityProviders:{}", identityProviders); - IdentityProviderRepresentation identityProvider = null; - if (identityProviders == null || identityProviders.isEmpty()) { - return identityProvider; - } + Map config = idpClientFactory.extractSamlMetadata(samlMetadataImportUrl, token, providerId, + realmName, idpMetadataStream); + logger.info("Import SAML response for realmName:{}, config:{}", realmName, config); - for (IdentityProviderRepresentation data : identityProviders) { - if (alias.equals(data.getAlias())) { - identityProvider = data; - break; - } + boolean valid = verifySamlIdpConfig(config); + logger.debug("Is IDP metadata config valid:{}", valid); + if (!valid) { + throw new InvalidAttributeException("Idp Metedata file is not valid !!!"); } - logger.debug("IdentityProvider fetched by name realmName:{}, alias:{}, identityProvider:{}", realmName, alias, - identityProvider); - return identityProvider; + return config; } - public Map validateSamlMetadata(String realmName, InputStream idpMetadataStream) { - Map config = null; + public IdentityProvider createUpdateIdentityProvider(String realmName, boolean isUpdate, + IdentityProvider identityProvider) { + IdentityProvider idp = null; try { - logger.info("Verify Saml Idp Metadata realmName:{}, idpMetadataStream:{}", realmName, idpMetadataStream); + logger.info("Add/Update IdentityProvider under realmName:{}, isUpdate:{}, identityProvider:{})", realmName, + isUpdate, identityProvider); - if (idpMetadataStream == null) { - throw new InvalidAttributeException("Idp Metedata file is null!!!"); + if (StringUtils.isBlank(realmName)) { + throw new InvalidAttributeException(REALM_NAME_NULL); } - MultipartFormDataOutput form = new MultipartFormDataOutput(); - form.addFormData("providerId", "saml", MediaType.TEXT_PLAIN_TYPE); - logger.debug("SAML idpMetadataStream.available():{}", idpMetadataStream.available()); + if (identityProvider == null) { + throw new InvalidAttributeException("IdentityProvider object is null!!!"); + } - byte[] content = idpMetadataStream.readAllBytes(); - logger.debug("content:{}", content); - String body = new String(content, Charset.forName("utf-8")); - form.addFormData("file", body, MediaType.APPLICATION_XML_TYPE, "saml-idp-metadata.xml"); + // Get token + String token = this.getKcAccessToken(realmName); + String idpUrl = getIdpUrl(realmName); - IdentityProvidersResource identityProvidersResource = this.getIdentityProvidersResource(realmName); - if (identityProvidersResource == null) { - return config; - } - config = identityProvidersResource.importFrom(form); - logger.debug("IDP metadata importConfig config:{})", config); - boolean valid = verifySamlIdpConfig(config); - logger.debug("Is IDP metadata config valid:{})", valid); - if (!valid) { - throw new InvalidAttributeException("Idp Metedata file is not valid !!!"); + if (isUpdate) { + idpUrl = idpUrl + "/" + identityProvider.getName(); + logger.info("Final URL for update IDP idpUrl:{}", idpUrl); } + JSONObject jsonObject = createIdentityProviderJson(identityProvider); + + // Populate KC SAML config + populateKcConfig(jsonObject); + + // Create KC JsonObject + JSONObject kcJsonObject = createKcJSONObject(jsonObject); + logger.info("Create new IdentityProvider - kcJsonObject:{}", kcJsonObject); + + String idpJson = idpClientFactory.createUpdateIdp(idpUrl, token, isUpdate, kcJsonObject); + logger.debug("IdentityProvider response idpJson:{}", idpJson); + + idp = this.createIdentityProvider(idpJson); + logger.debug("IdentityProvider idp:{}", idp); + } catch (Exception ex) { - throw new ConfigurationException("Error while validating SAML IDP Metadata", ex); + throw new ConfigurationException("Error while Add/Update SAML IDP ", ex); } - return config; + return identityProvider; } - public IdentityProviderRepresentation createIdentityProvider(String realmName, - IdentityProviderRepresentation identityProviderRepresentation) { - + public boolean deleteIdentityProvider(String realmName, String idpName) { + boolean deleteStatus = false; try { - logger.info("Create new IdentityProvider under realmName:{}, identityProviderRepresentation:{})", - realmName, identityProviderRepresentation); + logger.info("Delete IdentityProvider under realmName:{}, idpName:{})", realmName, idpName); if (StringUtils.isBlank(realmName)) { - throw new InvalidAttributeException("Realm name is null!!!"); + throw new InvalidAttributeException(REALM_NAME_NULL); } - if (identityProviderRepresentation == null) { - throw new InvalidAttributeException("IdentityProviderRepresentation is null!!!"); + if (StringUtils.isBlank(idpName)) { + throw new InvalidAttributeException("Name of IdentityProvider to be deleted is null!!!"); } - // validate IDP metadata - logger.debug("IDP metadata config identityProviderRepresentation.getConfig():{})", - identityProviderRepresentation.getConfig()); - if (identityProviderRepresentation.getConfig() == null - || identityProviderRepresentation.getConfig().isEmpty()) { - throw new InvalidAttributeException("Idp Metedata config is null!!!"); - } + // Get token + String token = this.getKcAccessToken(realmName); + String idpUrl = getIdpUrl(realmName) + "/" + idpName; + logger.info("IDP URL for delete is idpUrl:{}", idpUrl); - boolean valid = verifySamlIdpConfig(identityProviderRepresentation.getConfig()); - logger.debug("Is IDP metadata config valid:{})", valid); - - // create Identity Provider - IdentityProvidersResource identityProvidersResource = this.getIdentityProvidersResource(realmName); - if (identityProvidersResource == null) { - throw new ConfigurationException( - "identityProvidersResource are null, could not create Identity Provider!!!"); - } - logger.trace( - "IDP data identityProviderRepresentation.getAlias():{}, identityProviderRepresentation.getInternalId():{}, identityProviderRepresentation.getProviderId():{}, identityProviderRepresentation.getConfig():{}, identityProviderRepresentation.isEnabled():{}, identityProviderRepresentation.isLinkOnly():{}, identityProviderRepresentation.isStoreToken():{},identityProviderRepresentation.getFirstBrokerLoginFlowAlias():{}, identityProviderRepresentation.getPostBrokerLoginFlowAlias():{},identityProviderRepresentation.isTrustEmail():{}", - identityProviderRepresentation.getAlias(), identityProviderRepresentation.getInternalId(), - identityProviderRepresentation.getProviderId(), identityProviderRepresentation.getConfig(), - identityProviderRepresentation.isEnabled(), identityProviderRepresentation.isLinkOnly(), - identityProviderRepresentation.isStoreToken(), - identityProviderRepresentation.getFirstBrokerLoginFlowAlias(), - identityProviderRepresentation.getPostBrokerLoginFlowAlias(), - identityProviderRepresentation.isTrustEmail()); - Response response = identityProvidersResource.create(identityProviderRepresentation); - - logger.debug("IdentityProvider creation response:{}", response); - if (response != null) { - logger.debug("IdentityProvider creation response.getStatusInfo():{}, response.getEntity():{}", - response.getStatusInfo(), response.getEntity()); - - String id = getCreatedId(response); - logger.debug("IdentityProvider creation id():{}", id); - - List identityProvider = findAllIdentityProviders(realmName); - if (identityProvider != null && !identityProvider.isEmpty()) { - identityProvider.stream() - .forEach(e -> System.out.println(e.getInternalId() + "::" + e.getDisplayName())); - } - - identityProviderRepresentation = getIdentityProviderByName(realmName, - identityProviderRepresentation.getAlias()); - logger.debug("Final identityProviderRepresentation:{}", identityProviderRepresentation); - - response.close(); + deleteStatus = idpClientFactory.deleteIdp(idpUrl, token); + logger.info("IdentityProvider delete response deleteStatus:{}", deleteStatus); - } } catch (Exception ex) { - throw new ConfigurationException("Error while creating SAML IDP ", ex); + throw new ConfigurationException("Error while Deleting SAML IDP ", ex); } - return identityProviderRepresentation; + return deleteStatus; } - public IdentityProviderRepresentation updateIdentityProvider(String realmName, - IdentityProviderRepresentation identityProviderRepresentation) { - logger.info("Update IdentityProvider under realmName:{}, identityProviderRepresentation:{}", realmName, - identityProviderRepresentation); - - // validations + public String getSpMetadata(String realmName, String idpName) throws JsonProcessingException { + String spMetadataJson = null; if (StringUtils.isBlank(realmName)) { - throw new InvalidAttributeException("Realm name is null!!!"); + throw new InvalidAttributeException(REALM_NAME_NULL); } - if (identityProviderRepresentation == null) { - throw new InvalidAttributeException("IdentityProviderRepresentation for updation is null!!!"); + if (StringUtils.isBlank(idpName)) { + throw new InvalidAttributeException("Name of IdentityProvider is null!!!"); } - // validate IDP metadata - logger.debug("IDP metadata config while update identityProviderRepresentation.getConfig():{}", - identityProviderRepresentation.getConfig()); - if (identityProviderRepresentation.getConfig() == null - || identityProviderRepresentation.getConfig().isEmpty()) { - throw new InvalidAttributeException("Idp Metedata config is null!!!"); + // Get token + String token = this.getKcAccessToken(realmName); + String idpUrl = getSpMetadataUrl(realmName, idpName); + logger.info("IDP URL for delete is idpUrl:{}", idpUrl); + + spMetadataJson = idpClientFactory.getSpMetadata(idpUrl, token); + logger.info("IdentityProvider delete response spMetadataJson:{}", spMetadataJson); + return spMetadataJson; + } + + private String getKcAccessToken(String realmName) throws JsonProcessingException { + logger.info(" realmName:{}", realmName); + + String tokenUrl = getTokenUrl(realmName); + + return IdpClientFactory.getAccessToken(tokenUrl, samlConfigService.getClientId(), + samlConfigService.getClientSecret(), samlConfigService.getGrantType(), samlConfigService.getScope(), + samlConfigService.getUsername(), samlConfigService.getPassword(), samlConfigService.getServerUrl()); + } + + private String getIdpUrl(String realmName) { + return samlConfigService.getIdpUrl(realmName); + } + + private String getTokenUrl(String realmName) { + return samlConfigService.getTokenUrl(realmName); + } + + private String getSpMetadataUrl(String realm, String name) { + return samlConfigService.getSpMetadataUrl(realm, name); + } + + private String getSamlMetadataImportUrl(String realmName) { + return samlConfigService.getIdpMetadataImportUrl(realmName); + } + + private List getKcAttributes() { + return samlConfigService.getKcAttributes(); + } + + private List getKcSamlConfig() { + return samlConfigService.getKcSamlConfig(); + } + + private boolean verifySamlIdpConfig(Map config) { + // import endpoint simply converts IDPSSODescriptor into key value pairs. + // check that saml-idp-metadata.xml was properly converted into key value pairs + logger.debug("verifySamlConfig - config:{}", config); + if (config == null || config.isEmpty()) { + return false; } + logger.info("config.keySet().containsAll(Constants.SAML_IDP_CONFIG):{}", + config.keySet().containsAll(Constants.SAML_IDP_CONFIG)); - boolean valid = verifySamlIdpConfig(identityProviderRepresentation.getConfig()); - logger.debug("Is IDP metadata update config valid?:{})", valid); + return config.keySet().containsAll(Constants.SAML_IDP_CONFIG); + } - // validate IDP to update - IdentityProvidersResource identityProvidersResource = this.getIdentityProvidersResource(realmName); - if (identityProvidersResource == null) { - throw new ConfigurationException( - "identityProvidersResource is null, could not update Identity Provider!!!"); + private List createIdentityProviderList(String jsonIdentityProviderList) throws IOException { + logger.info("jsonIdentityProviderList:{}", jsonIdentityProviderList); + List idpList = null; + if (StringUtils.isBlank(jsonIdentityProviderList)) { + return idpList; } - IdentityProviderResource identityProviderResource = identityProvidersResource - .get(identityProviderRepresentation.getAlias()); - logger.debug( - "Is IDP resource present for update identityProviderRepresentation.getAlias():{}, identityProviderResource:{}", - identityProviderRepresentation.getAlias(), identityProviderResource); - if (identityProviderResource == null) { - throw new InvalidAttributeException("IdentityProvider not found to update!!!"); + JSONArray jsonArray = new JSONArray(jsonIdentityProviderList); + int count = jsonArray.length(); // get totalCount of all jsonObjects + idpList = new ArrayList<>(); + for (int i = 0; i < count; i++) { // iterate through jsonArray + JSONObject jsonObject = jsonArray.getJSONObject(i); // get jsonObject @ i position + logger.trace(" i:{},{}", i, jsonObject); + if (jsonObject != null) { + idpList.add(createIdentityProvider(jsonObject.toString())); + } } + logger.info("idpList:{}", idpList); + return idpList; + } - // update - identityProviderResource.update(identityProviderRepresentation); - identityProviderRepresentation = identityProviderResource.toRepresentation(); + private JSONObject createIdentityProviderJson(IdentityProvider identityProvider) throws IOException { + logger.info("Create Json - identityProvider:{}", identityProvider); + JSONObject jsonObj = null; + if (identityProvider == null) { + return jsonObj; + } + String json = Jackson.asJson(identityProvider); - logger.info( - "Updated IdentityProvider identityProviderRepresentation.getAlias():{} under realmName:{} is identityProviderRepresentation:{}", - identityProviderRepresentation.getAlias(), realmName, identityProviderRepresentation); + jsonObj = new JSONObject(json); + jsonObj.put(Constants.INTERNAL_ID, identityProvider.getInum()); + jsonObj.put(Constants.ALIAS, identityProvider.getName()); + logger.info("jsonObj:{}", jsonObj); + return jsonObj; - return identityProviderRepresentation; } - public void deleteIdentityProvider(String realmName, String alias) { - logger.info("IdentityProvider to delete realmName:{}, alias:{}", realmName, alias); - if (StringUtils.isBlank(realmName) || StringUtils.isBlank(alias)) { - throw new InvalidAttributeException("Realm name or IdentityProvider alias is null!!!"); + private IdentityProvider createIdentityProvider(String jsonIdentityProvider) throws IOException { + logger.info("jsonIdentityProvider:{}", jsonIdentityProvider); + IdentityProvider identityProvider = null; + if (StringUtils.isBlank(jsonIdentityProvider)) { + return identityProvider; } - IdentityProvidersResource identityProvidersResource = this.getIdentityProvidersResource(realmName); - if (identityProvidersResource == null) { - throw new ConfigurationException( - "IdentityProvidersResource is null, could not delete Identity Provider!!!"); - } + JSONObject jsonObj = new JSONObject(jsonIdentityProvider); + jsonObj.put(Constants.INUM, Jackson.getElement(jsonIdentityProvider, Constants.INTERNAL_ID)); + jsonObj.put(Constants.NAME, Jackson.getElement(jsonIdentityProvider, Constants.ALIAS)); - logger.debug( - "IdentityProviderResource fetched for delete realmName:{}, alias:{}, identityProvidersResource:{} ", - realmName, alias, identityProvidersResource); + ObjectMapper mapper = Jackson.createJsonMapper(); + identityProvider = mapper.readValue(jsonObj.toString(), IdentityProvider.class); + logger.info("IDP - identityProvider:{}", identityProvider); - IdentityProviderResource identityProviderResource = identityProvidersResource.get(alias); + return identityProvider; + } - if (identityProviderResource == null) { - throw new InvalidAttributeException("IdentityProvidersResource not found to delete!!!"); + private JSONObject populateKcConfig(JSONObject jsonObject) { + logger.info("IDP - jsonObject:{}", jsonObject); + List kcSamlConfig = getKcSamlConfig(); + + if (jsonObject == null || kcSamlConfig == null || kcSamlConfig.isEmpty()) { + return jsonObject; } - identityProviderResource.remove(); - logger.debug("Deleted IdentityProvider under realmName:{}, alias:{}", realmName, alias); - IdentityProviderRepresentation identityProviderRepresentation = getIdentityProviderByName(realmName, alias); - logger.debug("Checking identityProvider is deleted - identityProviderRepresentation:{}", - identityProviderRepresentation); + Map config = new HashMap<>(); + for (String name : kcSamlConfig) { + logger.trace("name:{}, jsonObject.has(name):{}", name, jsonObject.has(name)); + if (jsonObject.has(name)) { + config.put(name, jsonObject.getString(name)); + } + } + + logger.info("config:{}", config); + jsonObject.put("config", config); - if (identityProviderResource != null) { - throw new InvalidAttributeException("IdentityProviders could not be deleted!!!"); + // validate IDP metadata + logger.debug("IDP metadata config config:{})", config); + if (config == null || config.isEmpty()) { + throw new InvalidAttributeException("Idp Metedata config is null!!!"); } - return; - } + boolean valid = verifySamlIdpConfig(config); + logger.debug("Is IDP metadata config valid:{})", valid); - public void getSAMLServiceProviderMetadata(String realmName, String alias) { - // To-do + logger.info("Post config IDP jsonObject:{}", jsonObject); + return jsonObject; } - private static String getCreatedId(Response response) { - URI location = response.getLocation(); - if (!response.getStatusInfo().equals(Status.CREATED)) { - StatusType statusInfo = response.getStatusInfo(); - throw new WebApplicationException("Create method returned status " + statusInfo.getReasonPhrase() - + " (Code: " + statusInfo.getStatusCode() + "); expected status: Created (201)", response); - } - if (location == null) { - return null; + private JSONObject createKcJSONObject(JSONObject jsonObject) { + logger.info("For KC - jsonObject:{}", jsonObject); + List kcAttributes = getKcAttributes(); + + if (jsonObject == null || kcAttributes == null || kcAttributes.isEmpty()) { + return jsonObject; } - String path = location.getPath(); - return path.substring(path.lastIndexOf('/') + 1); - } - private boolean verifySamlIdpConfig(Map config) { - // import endpoint simply converts IDPSSODescriptor into key value pairs. - // check that saml-idp-metadata.xml was properly converted into key value pairs - logger.debug("verifySamlConfig - config:{}", config); - if (config == null || config.isEmpty()) { - return false; + JSONObject kcJSONObject = new JSONObject(); + for (String name : kcAttributes) { + try { + logger.trace("name:{}, jsonObject.get(name):{}", name, jsonObject.get(name)); + kcJSONObject.put(name, jsonObject.get(name)); + } catch (JSONException jex) { + logger.error("JSONException for attribute:{}, is:{}", name, jex); + } } - logger.info("config.keySet().containsAll(Constants.SAML_IDP_CONFIG):{}", - config.keySet().containsAll(Constants.SAML_IDP_CONFIG)); - - return config.keySet().containsAll(Constants.SAML_IDP_CONFIG); + + logger.info("kcJSONObject:{}", kcJSONObject); + + return kcJSONObject; } } diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlConfigService.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlConfigService.java index 3ebe268aaff..38ce40edba0 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlConfigService.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlConfigService.java @@ -142,6 +142,16 @@ public String getGrantType() { return grantType; } + public String getScope() { + final SamlConf samlConf = getSamlConf(); + SamlAppConfiguration samlAppConfiguration = samlConf.getDynamicConf(); + String scope = null; + if (samlAppConfiguration != null) { + scope = samlAppConfiguration.getScope(); + } + return scope; + } + public String getUsername() { final SamlConf samlConf = getSamlConf(); SamlAppConfiguration samlAppConfiguration = samlConf.getDynamicConf(); @@ -176,6 +186,48 @@ public String getSpMetadataUrl(String realm, String name) { return spMetadataUrl; } + public String getTokenUrl(String realm) { + logger.debug("Get SAML Token Url - realm:{}", realm); + final SamlConf samlConf = getSamlConf(); + SamlAppConfiguration samlAppConfiguration = samlConf.getDynamicConf(); + String tokenUrl = null; + if (samlAppConfiguration != null) { + StringBuilder sb = new StringBuilder(); + sb.append(samlAppConfiguration.getServerUrl()).append(samlAppConfiguration.getTokenUrl()); + tokenUrl = String.format(sb.toString(), realm); + } + logger.debug("SAML Token Url - tokenUrl:{}", tokenUrl); + return tokenUrl; + } + + public String getIdpUrl(String realm) { + logger.debug("Get SAML IDP Url - realm:{}", realm); + final SamlConf samlConf = getSamlConf(); + SamlAppConfiguration samlAppConfiguration = samlConf.getDynamicConf(); + String idpUrl = null; + if (samlAppConfiguration != null) { + StringBuilder sb = new StringBuilder(); + sb.append(samlAppConfiguration.getServerUrl()).append(samlAppConfiguration.getIdpUrl()); + idpUrl = String.format(sb.toString(), realm); + } + logger.debug("SAML IDP Url - idpUrl:{}", idpUrl); + return idpUrl; + } + + public String getIdpMetadataImportUrl(String realm) { + logger.debug("Get SAML IDP Metadata Import Url - realm:{}", realm); + final SamlConf samlConf = getSamlConf(); + SamlAppConfiguration samlAppConfiguration = samlConf.getDynamicConf(); + String idpMetadataImportUrl = null; + if (samlAppConfiguration != null) { + StringBuilder sb = new StringBuilder(); + sb.append(samlAppConfiguration.getServerUrl()).append(samlAppConfiguration.getIdpMetadataImportUrl()); + idpMetadataImportUrl = String.format(sb.toString(), realm); + } + logger.debug("SAML IDP Metadata Import Url - idpMetadataImportUrl:{}", idpMetadataImportUrl); + return idpMetadataImportUrl; + } + public String getIdpRootDir() { final SamlConf samlConf = getSamlConf(); SamlAppConfiguration samlAppConfiguration = samlConf.getDynamicConf(); @@ -286,6 +338,26 @@ public List getIdpMetadataMandatoryAttributes() { return idpMetadataMandatoryAttributes; } + public List getKcAttributes() { + final SamlConf samlConf = getSamlConf(); + SamlAppConfiguration samlAppConfiguration = samlConf.getDynamicConf(); + List kcAttributes = null; + if (samlAppConfiguration != null) { + kcAttributes = samlAppConfiguration.getKcAttributes(); + } + return kcAttributes; + } + + public List getKcSamlConfig() { + final SamlConf samlConf = getSamlConf(); + SamlAppConfiguration samlAppConfiguration = samlConf.getDynamicConf(); + List kcSamlConfig = null; + if (samlAppConfiguration != null) { + kcSamlConfig = samlAppConfiguration.getKcSamlConfig(); + } + return kcSamlConfig; + } + private SamlConf getSamlConf() { SamlConf samlConf = findSamlConf(); if (samlConf == null) { diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlIdpService.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlIdpService.java index ecfc02ed561..11642931ddc 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlIdpService.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlIdpService.java @@ -10,7 +10,6 @@ import io.jans.service.document.store.conf.DocumentStoreType; import io.jans.service.document.store.service.LocalDocumentStoreService; import io.jans.util.exception.InvalidConfigurationException; -import io.jans.util.StringHelper; import io.jans.util.INumGenerator; import io.jans.xml.GluuErrorHandler; import io.jans.xml.XMLValidator; @@ -19,14 +18,12 @@ import org.xml.sax.SAXException; import org.opensaml.saml.common.xml.SAMLSchemaBuilder; import org.opensaml.saml.common.xml.SAMLSchemaBuilder.SAML1Version; -import org.opensaml.xml.parse.XMLParserException; import jakarta.annotation.PostConstruct; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import javax.xml.validation.Schema; -import java.io.File; import java.io.InputStream; import java.io.IOException; import java.util.*; @@ -111,7 +108,7 @@ public String saveMetadataFile(String metadataTempDir, String metadataFileName, } public GluuErrorHandler validateMetadata(String metadataPath) - throws ParserConfigurationException, SAXException, IOException, XMLParserException { + throws ParserConfigurationException, SAXException, IOException { if (samlSchema == null) { final List validationLog = new ArrayList<>(); validationLog.add(GluuErrorHandler.SCHEMA_CREATING_ERROR_MESSAGE); diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlService.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlService.java index c44ac8bb5c6..196d6c47933 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlService.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/service/SamlService.java @@ -37,10 +37,6 @@ import java.util.Map; import java.util.UUID; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.filefilter.AgeFileFilter; -import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; @@ -255,6 +251,7 @@ public void removeTrustRelationship(TrustRelationship trustRelationship) { } private TrustRelationship setTrustRelationshipDefaultValue(TrustRelationship trustRelationship, boolean update) { + log.debug("trustRelationship:{}, update:{}",trustRelationship, update); return trustRelationship; } diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/util/Constants.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/util/Constants.java index 9a4f901f13e..aa9b832f92c 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/util/Constants.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/util/Constants.java @@ -43,10 +43,14 @@ private Constants() { public static final String CLIENTID = "clientId"; public static final String ID = "id"; public static final String IDP = "idp"; + public static final String INUM = "inum"; public static final String NAME = "name"; public static final String OIDC = "oidc"; public static final String SAML = "saml"; public static final String REALM = "realm"; + public static final String ACCESS_TOKEN = "access_token"; + public static final String INTERNAL_ID = "internalId"; + public static final String ALIAS = "alias"; public static final String SIGNING_CERTIFICATES = "signingCertificates"; public static final String VALIDATE_SIGNATURE = "validateSignature"; diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/BaseResource.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/BaseResource.java index cf6f297d01e..578dbebb98a 100644 --- a/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/BaseResource.java +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/rest/BaseResource.java @@ -135,6 +135,10 @@ public static void throwBadRequestException(Object obj) { public static void throwInternalServerException(String msg) { throw new InternalServerErrorException(getInternalServerException(msg)); } + + public static void throwInternalServerException(String msg, String description) { + throw new InternalServerErrorException(getInternalServerException(msg, description)); + } public static void throwInternalServerException(Throwable throwable) { throwable = findRootError(throwable); @@ -188,6 +192,13 @@ protected static Response getInternalServerException(String msg) { .build(); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build(); } + + protected static Response getInternalServerException(String msg, String description) { + ApiError error = new ApiError.ErrorBuilder() + .withCode(String.valueOf(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode())).withMessage(msg).andDescription(description) + .build(); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(error).build(); + } protected SearchRequest createSearchRequest(String schemas, String filter, String sortBy, String sortOrder, Integer startIndex, Integer count, String attrsList, String excludedAttrsList, int maximumRecCount, String fieldValuePair, Class entityClass) { diff --git a/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/Jackson.java b/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/Jackson.java index a454897181f..d40e8c0bd6a 100644 --- a/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/Jackson.java +++ b/jans-config-api/shared/src/main/java/io/jans/configapi/core/util/Jackson.java @@ -103,7 +103,7 @@ public static ObjectMapper jsonMapper() { } } - public String getJsonString(T obj) throws IOException { + public static String getJsonString(T obj) throws IOException { ObjectMapper mapper = new ObjectMapper(); return mapper.writeValueAsString(obj); } diff --git a/jans-linux-setup/jans_setup/templates/jans-saml/jans-saml-config.json b/jans-linux-setup/jans_setup/templates/jans-saml/jans-saml-config.json index 3dad8cdd3fa..b0c8d192f5f 100644 --- a/jans-linux-setup/jans_setup/templates/jans-saml/jans-saml-config.json +++ b/jans-linux-setup/jans_setup/templates/jans-saml/jans-saml-config.json @@ -9,22 +9,50 @@ "clientId": "${jans_idp_client_id}", "clientSecret": "${jans_idp_client_secret}", "grantType": "${jans_idp_grant_type}", + "scope": "openid", "username": "${jans_idp_user_name}", "password": "${jans_idp_user_password}", "spMetadataUrl":"/realms/%s/broker/%s/endpoint/descriptor", - "idpRootDir": "/opt/jans/idp/", - "idpMetadataDir": "/opt/idp/configs/keycloak/idp/metadata", - "idpMetadataTempDir": "/opt/idp/configs/keycloak/idp/temp_metadata", + "tokenUrl":"/realms/%s/protocol/openid-connect/token", + "idpUrl":"/admin/realms/%s/identity-provider/instances", + "idpMetadataImportUrl":"/admin/realms/%s/identity-provider/import-config", + "idpRootDir":"/opt/jans/idp/", + "idpMetadataDir":"/opt/idp/configs/keycloak/idp/metadata", + "idpMetadataTempDir":"/opt/idp/configs/keycloak/idp/temp_metadata", "idpMetadataFilePattern":"%s-idp-metadata.xml", "idpMetadataFile":"idp-metadata.xml", - "spMetadataDir": "/opt/idp/configs/keycloak/sp/metadata", - "spMetadataTempDir": "/opt/idp/configs/keycloak/sp/temp_metadata", + "spMetadataDir":"/opt/idp/configs/keycloak/sp/metadata", + "spMetadataTempDir":"/opt/idp/configs/keycloak/sp/temp_metadata", "spMetadataFilePattern":"%s-sp-metadata.xml", "spMetadataFile":"sp-metadata.xml", - "ignoreValidation": "false", - "idpMetadataMandatoryAttributes": [ + "ignoreValidation":"false", + "idpMetadataMandatoryAttributes":[ "nameIDPolicyFormat", "idpEntityId", "singleSignOnServiceUrl" + ], + "kcAttributes":[ + "alias", + "displayName", + "internalId", + "providerId", + "enabled", + "trustEmail", + "storeToken", + "addReadTokenRoleOnCreate", + "authenticateByDefault", + "linkOnly", + "firstBrokerLoginFlowAlias", + "postBrokerLoginFlowAlias", + "config" + ], + "kcSamlConfig":[ + "signingCertificate", + "validateSignature", + "singleLogoutServiceUrl", + "nameIDPolicyFormat", + "idpEntityId", + "singleSignOnServiceUrl", + "encryptionPublicKey" ] -} +} \ No newline at end of file