diff --git a/jans-config-api/common/src/main/java/io/jans/configapi/model/configuration/ApiAppConfiguration.java b/jans-config-api/common/src/main/java/io/jans/configapi/model/configuration/ApiAppConfiguration.java index e5d433ac194..b8c0ecf38d2 100644 --- a/jans-config-api/common/src/main/java/io/jans/configapi/model/configuration/ApiAppConfiguration.java +++ b/jans-config-api/common/src/main/java/io/jans/configapi/model/configuration/ApiAppConfiguration.java @@ -10,6 +10,7 @@ public class ApiAppConfiguration implements Configuration { private boolean configOauthEnabled; + private boolean customAttributeValidationEnabled; private List apiApprovedIssuer; private String apiProtectionType; private String apiClientId; @@ -48,6 +49,14 @@ public void setConfigOauthEnabled(boolean configOauthEnabled) { this.configOauthEnabled = configOauthEnabled; } + public boolean isCustomAttributeValidationEnabled() { + return customAttributeValidationEnabled; + } + + public void setCustomAttributeValidationEnabled(boolean customAttributeValidationEnabled) { + this.customAttributeValidationEnabled = customAttributeValidationEnabled; + } + public List getApiApprovedIssuer() { return apiApprovedIssuer; } @@ -260,24 +269,20 @@ public void setPlugins(List plugins) { @Override public String toString() { - return "ApiAppConfiguration [" + " apiApprovedIssuer=" + apiApprovedIssuer + ", apiProtectionType=" + return "ApiAppConfiguration [configOauthEnabled=" + configOauthEnabled + ", customAttributeValidationEnabled=" + + customAttributeValidationEnabled + ", apiApprovedIssuer=" + apiApprovedIssuer + ", apiProtectionType=" + apiProtectionType + ", apiClientId=" + apiClientId + ", apiClientPassword=" + apiClientPassword + ", endpointInjectionEnabled=" + endpointInjectionEnabled + ", authIssuerUrl=" + authIssuerUrl + ", authOpenidConfigurationUrl=" + authOpenidConfigurationUrl + ", authOpenidIntrospectionUrl=" + authOpenidIntrospectionUrl + ", authOpenidTokenUrl=" + authOpenidTokenUrl + ", authOpenidRevokeUrl=" - + authOpenidRevokeUrl + ", smallryeHealthRootPath=" + smallryeHealthRootPath - + ", corsConfigurationFilters=" + corsConfigurationFilters + ", exclusiveAuthScopes=" - + exclusiveAuthScopes + ", loggingLevel=" + loggingLevel + " , loggingLayout=" + loggingLayout - + " , externalLoggerConfiguration=" + externalLoggerConfiguration + " , disableJdkLogger=" - + disableJdkLogger + " , maxCount =" + maxCount - + " , userExclusionAttributes="+ userExclusionAttributes - + " , userMandatoryAttributes="+ userMandatoryAttributes - + " , agamaConfiguration="+ agamaConfiguration - + " , auditLogConf="+ auditLogConf - + " , dataFormatConversionConf="+ dataFormatConversionConf - + " , plugins="+ plugins + + authOpenidRevokeUrl + ", smallryeHealthRootPath=" + smallryeHealthRootPath + ", exclusiveAuthScopes=" + + exclusiveAuthScopes + ", corsConfigurationFilters=" + corsConfigurationFilters + ", loggingLevel=" + + loggingLevel + ", loggingLayout=" + loggingLayout + ", externalLoggerConfiguration=" + + externalLoggerConfiguration + ", disableJdkLogger=" + disableJdkLogger + ", maxCount=" + maxCount + + ", userExclusionAttributes=" + userExclusionAttributes + ", userMandatoryAttributes=" + + userMandatoryAttributes + ", agamaConfiguration=" + agamaConfiguration + ", auditLogConf=" + + auditLogConf + ", dataFormatConversionConf=" + dataFormatConversionConf + ", plugins=" + plugins + "]"; } - } diff --git a/jans-config-api/docs/jans-config-api-swagger.yaml b/jans-config-api/docs/jans-config-api-swagger.yaml index d60e1364af3..a915c2368b8 100644 --- a/jans-config-api/docs/jans-config-api-swagger.yaml +++ b/jans-config-api/docs/jans-config-api-swagger.yaml @@ -686,6 +686,8 @@ paths: } "401": description: Unauthorized + "406": + description: NotAcceptable "500": description: InternalServerError security: @@ -772,8 +774,12 @@ paths: ], "whitePagesCanView": false } + "400": + description: BadRequest "401": description: Unauthorized + "406": + description: NotAcceptable "500": description: InternalServerError security: @@ -7888,21 +7894,21 @@ components: $ref: '#/components/schemas/AttributeValidation' tooltip: type: string - whitePagesCanView: - type: boolean selected: type: boolean - adminCanEdit: + adminCanAccess: type: boolean - adminCanView: + userCanAccess: + type: boolean + userCanEdit: type: boolean userCanView: type: boolean - userCanEdit: + adminCanView: type: boolean - userCanAccess: + adminCanEdit: type: boolean - adminCanAccess: + whitePagesCanView: type: boolean baseDn: type: string @@ -9520,6 +9526,8 @@ components: properties: configOauthEnabled: type: boolean + customAttributeValidationEnabled: + type: boolean apiApprovedIssuer: type: array items: @@ -10172,10 +10180,10 @@ components: ttl: type: integer format: int32 - opbrowserState: - type: string persisted: type: boolean + opbrowserState: + type: string SessionIdAccessMap: type: object properties: 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 a668b352de6..d986ae87191 100644 --- a/jans-config-api/plugins/docs/kc-saml-plugin-swagger.yaml +++ b/jans-config-api/plugins/docs/kc-saml-plugin-swagger.yaml @@ -1007,11 +1007,20 @@ components: type: string signResponses: type: string + SAMLMetadata: + type: object + properties: + nameIDPolicyFormat: + type: string + entityId: + type: string + singleLogoutServiceUrl: + type: string TrustRelationship: required: - - clientId - description - displayName + - name - spMetaDataSourceType type: object properties: @@ -1021,7 +1030,7 @@ components: type: string owner: type: string - clientId: + name: maxLength: 60 minLength: 0 type: string @@ -1061,12 +1070,8 @@ components: - federation - manual - mdq - nameIDPolicyFormat: - type: string - entityId: - type: string - singleLogoutServiceUrl: - type: string + samlMetadata: + $ref: '#/components/schemas/SAMLMetadata' redirectUris: type: array items: diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/SAMLMetadata.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/SAMLMetadata.java new file mode 100644 index 00000000000..f6fc946a6a0 --- /dev/null +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/SAMLMetadata.java @@ -0,0 +1,55 @@ +/* + * 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.model; + + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.io.Serializable; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class SAMLMetadata implements Serializable { + + private static final long serialVersionUID = 1L; + private String nameIDPolicyFormat; + private String entityId; + private String singleLogoutServiceUrl; + + public String getNameIDPolicyFormat() { + return nameIDPolicyFormat; + } + + public void setNameIDPolicyFormat(String nameIDPolicyFormat) { + this.nameIDPolicyFormat = nameIDPolicyFormat; + } + + public String getEntityId() { + return entityId; + } + + public void setEntityId(String entityId) { + this.entityId = entityId; + } + + public String getSingleLogoutServiceUrl() { + return singleLogoutServiceUrl; + } + + public void setSingleLogoutServiceUrl(String singleLogoutServiceUrl) { + this.singleLogoutServiceUrl = singleLogoutServiceUrl; + } + + @Override + public String toString() { + return "SPMetadata [nameIDPolicyFormat=" + nameIDPolicyFormat + ", entityId=" + entityId + + ", singleLogoutServiceUrl=" + singleLogoutServiceUrl + "]"; + } + + +} diff --git a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/TrustRelationship.java b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/TrustRelationship.java index 974c72bf8a9..6c1eb1ee35c 100644 --- a/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/TrustRelationship.java +++ b/jans-config-api/plugins/kc-saml-plugin/src/main/java/io/jans/configapi/plugin/saml/model/TrustRelationship.java @@ -12,6 +12,7 @@ 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; @@ -30,7 +31,7 @@ @DataEntry(sortBy = { "displayName" }) -@ObjectClass(value = "jansSAMLconfig") +@ObjectClass(value = "jansTrustRelationship") @JsonInclude(JsonInclude.Include.NON_NULL) public class TrustRelationship extends Entry implements Serializable { @@ -42,10 +43,10 @@ public class TrustRelationship extends Entry implements Serializable { @AttributeName private String owner; - @AttributeName(name = "jansClntId") + @AttributeName(name = "name") @NotNull - @Size(min = 0, max = 60, message = "Length of the Client Id should not exceed 60") - private String clientId; + @Size(min = 0, max = 60, message = "Length of the name should not exceed 60") + private String name; @NotNull @Size(min = 0, max = 60, message = "Length of the Display Name should not exceed 60") @@ -86,7 +87,7 @@ public class TrustRelationship extends Entry implements Serializable { private boolean enabled; /** - * Always list this client in the Account UI, even if the user does not have an + * Always list this in the Account UI, even if the user does not have an * active session. */ @AttributeName(name = "displayInConsole") @@ -110,14 +111,9 @@ public class TrustRelationship extends Entry implements Serializable { @AttributeName(name = "jansSAMLspMetaDataSourceTyp") private MetadataSourceType spMetaDataSourceType; - @AttributeName(name = "nameIDPolicyFormat") - private String nameIDPolicyFormat; - - @AttributeName(name = "entityId") - private String entityId; - - @AttributeName(name = "singleLogoutServiceUrl") - private String singleLogoutServiceUrl; + @JsonObject + @AttributeName(name = "samlMetadata") + private SAMLMetadata samlMetadata; @AttributeName(name = "jansRedirectURI") private String[] redirectUris; @@ -173,12 +169,12 @@ public void setOwner(String owner) { this.owner = owner; } - public String getClientId() { - return clientId; + public String getName() { + return name; } - public void setClientId(String clientId) { - this.clientId = clientId; + public void setName(String name) { + this.name = name; } public String getDisplayName() { @@ -285,28 +281,12 @@ public void setSpMetaDataSourceType(MetadataSourceType spMetaDataSourceType) { this.spMetaDataSourceType = spMetaDataSourceType; } - public String getNameIDPolicyFormat() { - return nameIDPolicyFormat; - } - - public void setNameIDPolicyFormat(String nameIDPolicyFormat) { - this.nameIDPolicyFormat = nameIDPolicyFormat; - } - - public String getEntityId() { - return entityId; + public SAMLMetadata getSamlMetadata() { + return samlMetadata; } - public void setEntityId(String entityId) { - this.entityId = entityId; - } - - public String getSingleLogoutServiceUrl() { - return singleLogoutServiceUrl; - } - - public void setSingleLogoutServiceUrl(String singleLogoutServiceUrl) { - this.singleLogoutServiceUrl = singleLogoutServiceUrl; + public void setSamlMetadata(SAMLMetadata samlMetadata) { + this.samlMetadata = samlMetadata; } public String[] getRedirectUris() { @@ -411,18 +391,17 @@ public static void sortByDataSourceType(List trustRelationshi @Override public String toString() { - return "TrustRelationship [inum=" + inum + ", owner=" + owner + ", clientId=" + clientId + ", displayName=" + return "TrustRelationship [inum=" + inum + ", owner=" + owner + ", name=" + name + ", displayName=" + displayName + ", description=" + description + ", rootUrl=" + rootUrl + ", adminUrl=" + adminUrl + ", baseUrl=" + baseUrl + ", surrogateAuthRequired=" + surrogateAuthRequired + ", enabled=" + enabled + ", alwaysDisplayInConsole=" + alwaysDisplayInConsole + ", clientAuthenticatorType=" + clientAuthenticatorType + ", secret=" + secret + ", registrationAccessToken=" + registrationAccessToken + ", consentRequired=" + consentRequired + ", spMetaDataSourceType=" - + spMetaDataSourceType + ", nameIDPolicyFormat=" + nameIDPolicyFormat + ", entityId=" + entityId - + ", singleLogoutServiceUrl=" + singleLogoutServiceUrl + ", redirectUris=" + + spMetaDataSourceType + ", samlMetadata=" + samlMetadata + ", redirectUris=" + Arrays.toString(redirectUris) + ", spMetaDataFN=" + spMetaDataFN + ", spMetaDataURL=" + spMetaDataURL + ", metaLocation=" + metaLocation + ", releasedAttributes=" + releasedAttributes + ", url=" + url + ", spLogoutURL=" + spLogoutURL + ", status=" + status + ", validationStatus=" + validationStatus + ", validationLog=" + validationLog + ", profileConfigurations=" + profileConfigurations + "]"; } - + } diff --git a/jans-config-api/plugins/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 e897150dc36..3286ff52fa3 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 @@ -6,6 +6,7 @@ import io.jans.configapi.core.rest.BaseResource; import io.jans.configapi.core.rest.ProtectedApi; import io.jans.configapi.plugin.saml.util.Constants; +import io.jans.configapi.util.AttributeNames; import io.jans.configapi.plugin.saml.service.SamlService; import io.swagger.v3.oas.annotations.Operation; @@ -28,6 +29,7 @@ import java.io.InputStream; import java.io.IOException; import java.util.*; +import java.util.stream.*; import org.jboss.resteasy.annotations.providers.multipart.MultipartForm; import org.slf4j.Logger; @@ -40,7 +42,9 @@ public class TrustRelationshipResource extends BaseResource { private static final String SAML_TRUST_RELATIONSHIP = "Trust Relationship"; private static final String SAML_TRUST_RELATIONSHIP_FORM = "Trust Relationship From"; private static final String SAML_TRUST_RELATIONSHIP_CHECK_STR = "Trust Relationship identified by '"; - + private static final String NAME_CONFLICT = "NAME_CONFLICT"; + private static final String NAME_CONFLICT_MSG = "Trust Relationship with same name `%s` already exists!"; + @Inject Logger logger; @@ -105,7 +109,17 @@ public Response createTrustRelationshipWithFile(@MultipartForm TrustRelationship TrustRelationship trustRelationship = trustRelationshipForm.getTrustRelationship(); logger.debug(" Create trustRelationship:{} ", trustRelationship); - checkResourceNotNull(trustRelationshipForm.getTrustRelationship(), SAML_TRUST_RELATIONSHIP); + + //validation + checkResourceNotNull(trustRelationship, SAML_TRUST_RELATIONSHIP); + checkNotNull(trustRelationship.getName(), "Name"); + + // check if TrustRelationship with same name already exists + List existingTrustRelationship = samlService.getAllTrustRelationshipByName(trustRelationship.getName()); + logger.debug(" existingTrustRelationship:{} ", existingTrustRelationship); + if (existingTrustRelationship != null && !existingTrustRelationship.isEmpty()) { + throwBadRequestException(NAME_CONFLICT,String.format(NAME_CONFLICT_MSG, trustRelationship.getName())); + } InputStream metaDataFile = trustRelationshipForm.getMetaDataFile(); logger.debug(" Create metaDataFile:{} ", metaDataFile); @@ -143,15 +157,13 @@ public Response updateTrustRelationship(@MultipartForm TrustRelationshipForm tru TrustRelationship trustRelationship = trustRelationshipForm.getTrustRelationship(); logger.debug(" Create trustRelationship:{} ", trustRelationship); - checkResourceNotNull(trustRelationshipForm.getTrustRelationship(), SAML_TRUST_RELATIONSHIP); - - InputStream metaDataFile = trustRelationshipForm.getMetaDataFile(); - logger.debug(" Create metaDataFile:{} ", metaDataFile); - if (metaDataFile != null) { - logger.debug(" Create metaDataFile.available():{}", metaDataFile.available()); - } - - // validation of TrustRelationship + + //validation + checkResourceNotNull(trustRelationship, SAML_TRUST_RELATIONSHIP); + checkNotNull(trustRelationship.getName(), "Name"); + checkNotNull(trustRelationship.getInum(), AttributeNames.INUM); + + // check if TrustRelationship exists TrustRelationship existingTrustRelationship = samlService .getTrustRelationshipByInum(trustRelationship.getInum()); logger.info("TrustRelationship found by trustRelationship.getInum():{}, existingTrustRelationship:{}", @@ -159,6 +171,30 @@ public Response updateTrustRelationship(@MultipartForm TrustRelationshipForm tru checkResourceNotNull(existingTrustRelationship, SAML_TRUST_RELATIONSHIP_CHECK_STR + trustRelationship.getInum() + "'"); + // check if another TrustRelationship with same name already exists + final String inum = trustRelationship.getInum(); + List trustRelationshipList = samlService + .getAllTrustRelationshipByName(trustRelationship.getName()); + logger.info(" trustRelationshipList:{} ", trustRelationshipList); + if (trustRelationshipList != null && !trustRelationshipList.isEmpty()) { + List inumList = trustRelationshipList.stream().map(TrustRelationship::getInum) + .collect(Collectors.toList()); + logger.info("TrustRelationship's with name:{}, inumList:{}", trustRelationship.getName(), inumList); + List list = trustRelationshipList.stream().filter(e -> !e.getInum().equalsIgnoreCase(inum)) + .collect(Collectors.toList()); + logger.info("Other TrustRelationship's with same name:{} list:{}", trustRelationship.getName(), list); + if (list != null && !list.isEmpty()) { + throwBadRequestException(NAME_CONFLICT, String.format(NAME_CONFLICT_MSG, trustRelationship.getName())); + } + } + + InputStream metaDataFile = trustRelationshipForm.getMetaDataFile(); + logger.debug(" Create metaDataFile:{} ", metaDataFile); + if (metaDataFile != null) { + logger.debug(" Create metaDataFile.available():{}", metaDataFile.available()); + } + + // Update trustRelationship = samlService.updateTrustRelationship(trustRelationship); @@ -180,7 +216,7 @@ public Response deleteTrustRelationship( @Parameter(description = "Unique Id of Trust Relationship") @PathParam(Constants.ID) @NotNull String id) { if (logger.isInfoEnabled()) { - logger.info("Delete client identified by id:{}", escapeLog(id)); + logger.info("Delete TrustRelationship identified by id:{}", escapeLog(id)); } TrustRelationship trustRelationship = samlService.getTrustRelationshipByInum(id); 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 196d6c47933..4f585ea75f5 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 @@ -6,7 +6,6 @@ package io.jans.configapi.plugin.saml.service; -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.util.AttributeConstants; @@ -117,7 +116,7 @@ public List getAllTrustRelationshipByInum(String inum) { return persistenceEntryManager.findEntries(getDnForTrustRelationship(inum), TrustRelationship.class, null); } - public List getAllTrustRelationshipByName(String name) { + public List getAllTrustRelationshipByDisplayName(String name) { log.info("Search TrustRelationship with name:{}", name); String[] targetArray = new String[] { name }; @@ -126,7 +125,14 @@ public List getAllTrustRelationshipByName(String name) { return persistenceEntryManager.findEntries(getDnForTrustRelationship(null), TrustRelationship.class, displayNameFilter); } - + + public List getAllTrustRelationshipByName(String name) { + log.info("Search TrustRelationship with name:{}", name); + Filter nameFilter = Filter.createEqualityFilter("name", name); + log.debug("Search TrustRelationship with nameFilter:{}", nameFilter); + return persistenceEntryManager.findEntries(getDnForTrustRelationship(null), TrustRelationship.class, nameFilter); + } + public TrustRelationship getTrustContainerFederation(TrustRelationship trustRelationship) { return getRelationshipByDn(trustRelationship.getDn()); } @@ -171,7 +177,7 @@ public List getAllTrustRelationship(int sizeLimit) { sizeLimit); } - public PagedResult getTrustRelationship(SearchRequest searchRequest) { + public PagedResult getTrustRelationship(SearchRequest searchRequest) { log.info("Search TrustRelationship with searchRequest:{}", searchRequest); Filter searchFilter = null; @@ -204,7 +210,7 @@ public PagedResult getTrustRelationship(SearchRequest searchRequest) { log.info("TrustRelationship searchFilter:{}", searchFilter); - return persistenceEntryManager.findPagedEntries(getDnForTrustRelationship(null), Client.class, searchFilter, + return persistenceEntryManager.findPagedEntries(getDnForTrustRelationship(null), TrustRelationship.class, searchFilter, null, searchRequest.getSortBy(), SortOrder.getByValue(searchRequest.getSortOrder()), searchRequest.getStartIndex(), searchRequest.getCount(), searchRequest.getMaxCount()); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java index c16a78b7e63..9bf61fde9d2 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/rest/resource/auth/AttributesResource.java @@ -116,7 +116,9 @@ public Response getAttributeByInum(@Parameter(description = "Attribute Id") @Pat @RequestBody(description = "JansAttribute object", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = JansAttribute.class), examples = @ExampleObject(name = "Request example", value = "example/attribute/attribute.json"))) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = JansAttribute.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute.json"))), + @ApiResponse(responseCode = "400", description = "BadRequest"), @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "406", description = "NotAcceptable"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @POST @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, groupScopes = {}, superScopes = { @@ -129,7 +131,7 @@ public Response createAttribute(@Valid JansAttribute attribute) { // check if attribute exists in schema boolean attributeValidation = attributeService.validateAttributeDefinition(attribute.getName()); - log.debug("Validate attribute while creation - attribute.getName():{}, attributeValidation:{}", attribute.getName(), attributeValidation); + log.info("Validate attribute while creation - attribute.getName():{}, attributeValidation:{}", attribute.getName(), attributeValidation); if (!attributeValidation) { throw new WebApplicationException(getNotAcceptableException("The attribute type '" + attribute.getName() + "' not defined in DB schema")); } @@ -150,6 +152,7 @@ public Response createAttribute(@Valid JansAttribute attribute) { @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = JansAttribute.class), examples = @ExampleObject(name = "Response example", value = "example/attribute/attribute.json"))), @ApiResponse(responseCode = "401", description = "Unauthorized"), + @ApiResponse(responseCode = "406", description = "NotAcceptable"), @ApiResponse(responseCode = "500", description = "InternalServerError") }) @PUT @ProtectedApi(scopes = { ApiAccessConstants.ATTRIBUTES_WRITE_ACCESS }, groupScopes = {}, superScopes = { @@ -164,7 +167,7 @@ public Response updateAttribute(@Valid JansAttribute attribute) { // check if attribute exists in schema boolean attributeValidation = attributeService.validateAttributeDefinition(attribute.getName()); - log.debug("Validate attribute - attribute.getName():{}, attributeValidation:{}", attribute.getName(), attributeValidation); + log.info("Validate attribute - attribute.getName():{}, attributeValidation:{}", attribute.getName(), attributeValidation); if (!attributeValidation) { throw new WebApplicationException(getNotAcceptableException( "The attribute type '" + attribute.getName() + "' not defined in DB schema")); diff --git a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/AttributeService.java b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/AttributeService.java index 1cb200bd703..43b061d0e2b 100644 --- a/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/AttributeService.java +++ b/jans-config-api/server/src/main/java/io/jans/configapi/service/auth/AttributeService.java @@ -4,10 +4,11 @@ import static io.jans.as.model.util.Util.escapeLog; import io.jans.as.common.model.common.SimpleUser; import io.jans.as.common.util.AttributeConstants; -import io.jans.orm.model.AttributeType; +import io.jans.configapi.model.configuration.ApiAppConfiguration; import io.jans.configapi.util.ApiConstants; import io.jans.model.JansAttribute; import io.jans.model.SearchRequest; +import io.jans.orm.model.AttributeType; import io.jans.orm.model.PagedResult; import io.jans.orm.model.SortOrder; import io.jans.orm.search.filter.Filter; @@ -26,6 +27,9 @@ public class AttributeService extends io.jans.as.common.service.AttributeService private static final long serialVersionUID = -820393743995746612L; + @Inject + private ApiAppConfiguration appConfiguration; + @Inject transient ConfigurationService configurationService; @@ -111,11 +115,19 @@ public JansAttribute getAttributeUsingName(String claimName) { } public boolean validateAttributeDefinition(String attributeName) { - log.info(" Validate attributeName:{}, getPersistenceType():{}", attributeName, getPersistenceType()); + log.info(" Validate attributeName:{}, getPersistenceType():{}, appConfiguration:{}", attributeName, getPersistenceType(), appConfiguration); boolean isValidAttribute = false; try { + + //return if isCustomAttributeValidationEnabled not enabled + if(appConfiguration!=null && !appConfiguration.isCustomAttributeValidationEnabled()) { + return true; + } + + log.info(" attributeName:{}, persistenceEntryManager.getAttributeType(ou=people,o=jans, SimpleUser.class,attributeName)():{}", attributeName, persistenceEntryManager.getAttributeType("ou=people,o=jans", SimpleUser.class, + attributeName)); AttributeType attributeType = persistenceEntryManager.getAttributeType("ou=people,o=jans", SimpleUser.class, - "uid"); + attributeName); log.info(" attributeName:{}, attributeType():{}", attributeName, attributeType); if (attributeType != null) { diff --git a/jans-config-api/server/src/main/resources/config-api-rs-protect.json b/jans-config-api/server/src/main/resources/config-api-rs-protect.json index 8d0da16c6f7..e041fce9f82 100644 --- a/jans-config-api/server/src/main/resources/config-api-rs-protect.json +++ b/jans-config-api/server/src/main/resources/config-api-rs-protect.json @@ -2772,13 +2772,13 @@ "scopes": [ { "inum": "1800.01.71", - "name": "https://jans.io/oauth/config/saml-config.readonly" + "name": "https://jans.io/oauth/kc-link-config.readonly" } ], "groupScopes": [ { "inum": "1800.01.72", - "name": "https://jans.io/oauth/config/saml-config.write" + "name": "https://jans.io/oauth/kc-link-config.write" } ], "superScopes": [ @@ -2796,7 +2796,7 @@ "scopes": [ { "inum": "1800.01.72", - "name": "https://jans.io/oauth/config/saml-config.write" + "name": "https://jans.io/oauth/kc-link-config.write" } ], "groupScopes": [], 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 578dbebb98a..32627bcfcdc 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 @@ -76,7 +76,7 @@ public static void checkResourceNotNull(T resource, String objectName) { } public static void checkNotNull(String attribute, String attributeName) { - if (attribute == null) { + if (StringUtils.isBlank(attribute)) { throw new BadRequestException(getMissingAttributeError(attributeName)); } } diff --git a/jans-linux-setup/jans_setup/schema/jans_schema.json b/jans-linux-setup/jans_setup/schema/jans_schema.json index cbed32cf8d5..85a9d675754 100644 --- a/jans-linux-setup/jans_setup/schema/jans_schema.json +++ b/jans-linux-setup/jans_setup/schema/jans_schema.json @@ -3485,15 +3485,15 @@ "x_origin": "Jans created attribute" }, { - "desc": "SAML Trust Relationship file location of metadata", - "equality": "caseIgnoreMatch", - "names": [ - "jansSAMLspMetaDataFN" - ], - "oid": "jansAttr", - "substr": "caseIgnoreSubstringsMatch", - "syntax": "1.3.6.1.4.1.1466.115.121.1.15", - "x_origin": "Jans created attribute" + "desc": "SAML Trust Relationship file location of metadata", + "equality": "caseIgnoreMatch", + "names": [ + "jansSAMLspMetaDataFN" + ], + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" }, { "desc": "Provider Id", @@ -3590,15 +3590,15 @@ "x_origin": "Jans created attribute" }, { - "desc": "SAML Trusted IDP file location of metadata", - "equality": "caseIgnoreMatch", - "names": [ - "jansSAMLidpMetaDataFN" - ], - "oid": "jansAttr", - "substr": "caseIgnoreSubstringsMatch", - "syntax": "1.3.6.1.4.1.1466.115.121.1.15", - "x_origin": "Jans created attribute" + "desc": "SAML Trusted IDP file location of metadata", + "equality": "caseIgnoreMatch", + "names": [ + "jansSAMLidpMetaDataFN" + ], + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" }, { "desc": "SAML Trusted IDP URI location of metadata", @@ -3643,140 +3643,151 @@ "syntax": "1.3.6.1.4.1.1466.115.121.1.15", "x_origin": "Jans created attribute" }, - { - "desc":"signingCertificate", - "equality":"caseIgnoreMatch", - "names":[ + { + "desc": "signingCertificate", + "equality": "caseIgnoreMatch", + "names": [ "signingCertificate" ], - "oid":"jansAttr", - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - }, - { - "desc":"validateSignature", - "equality":"caseIgnoreMatch", - "names":[ + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "validateSignature", + "equality": "caseIgnoreMatch", + "names": [ "validateSignature" ], - "oid":"jansAttr", - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - }, - { - "desc":"singleLogoutServiceUrl", - "equality":"caseIgnoreMatch", - "names":[ + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "singleLogoutServiceUrl", + "equality": "caseIgnoreMatch", + "names": [ "singleLogoutServiceUrl" ], - "oid":"jansAttr", - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - }, - { - "desc":"nameIDPolicyFormat", - "equality":"caseIgnoreMatch", - "names":[ + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "nameIDPolicyFormat", + "equality": "caseIgnoreMatch", + "names": [ "nameIDPolicyFormat" ], - "oid":"jansAttr", - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - }, - { - "desc":"entityId", - "equality":"caseIgnoreMatch", - "names":[ + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "entityId", + "equality": "caseIgnoreMatch", + "names": [ "entityId" ], - "oid":"jansAttr", - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - }, - { - "desc":"singleSignOnServiceUrl", - "equality":"caseIgnoreMatch", - "names":[ + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "singleSignOnServiceUrl", + "equality": "caseIgnoreMatch", + "names": [ "singleSignOnServiceUrl" ], - "oid":"jansAttr", - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - }, - { - "desc":"encryptionPublicKey", - "equality":"caseIgnoreMatch", - "names":[ - "encryptionPublicKey" - ], - "oid":"jansAttr", - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - }, -{ - "desc":"Webhook identifier", - "equality":"caseIgnoreMatch", - "names":[ + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "encryptionPublicKey", + "equality": "caseIgnoreMatch", + "names": [ + "encryptionPublicKey" + ], + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "Webhook identifier", + "equality": "caseIgnoreMatch", + "names": [ "webhookId" ], - "oid":"jansAttr", - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - }, - { - "desc":"HTTP request method", - "equality":"caseIgnoreMatch", - "names":[ + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "HTTP request method", + "equality": "caseIgnoreMatch", + "names": [ "httpMethod" ], - "oid":"jansAttr", - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - }, - { - "desc":"HTTP request headers", - "equality":"caseIgnoreMatch", - "names":[ + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "HTTP request headers", + "equality": "caseIgnoreMatch", + "names": [ "httpHeaders" ], "multivalued": true, - "oid":"jansAttr", - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - }, - { - "desc":"HTTP request body", - "equality":"caseIgnoreMatch", - "names":[ + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "HTTP request body", + "equality": "caseIgnoreMatch", + "names": [ "httpRequestBody" ], - "oid":"jansAttr", + "oid": "jansAttr", "json": true, - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - }, - { - "desc":"Admin UI feature identifier", - "equality":"caseIgnoreMatch", - "names":[ + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "Admin UI feature identifier", + "equality": "caseIgnoreMatch", + "names": [ "auiFeatureId" ], - "oid":"jansAttr", - "substr":"caseIgnoreSubstringsMatch", - "syntax":"1.3.6.1.4.1.1466.115.121.1.15", - "x_origin":"Jans created attribute" - } + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + }, + { + "desc": "SAML Metadata", + "equality": "caseIgnoreMatch", + "names": [ + "samlMetadata" + ], + "oid": "jansAttr", + "substr": "caseIgnoreSubstringsMatch", + "syntax": "1.3.6.1.4.1.1466.115.121.1.15", + "x_origin": "Jans created attribute" + } ], "objectClasses": [ { @@ -4995,7 +5006,7 @@ "may": [ "inum", "owner", - "jansClntId", + "name", "displayName", "description", "rootUrl", @@ -5010,9 +5021,7 @@ "jansRedirectURI", "jansWebOrigins", "consentRequired", - "nameIDPolicyFormat", - "entityId", - "singleLogoutServiceUrl", + "samlMetadata", "jansSAMLMetaDataFilter", "jansSAMLspMetaDataSourceTyp", "jansSAMLspMetaDataFN", @@ -5033,7 +5042,7 @@ "objectclass" ], "names": [ - "jansSAMLconfig" + "jansTrustRelationship" ], "oid": "jansObjClass", "sup": [ @@ -5089,50 +5098,50 @@ ], "x_origin": "Jans created objectclass" }, -{ - "kind": "STRUCTURAL", - "may": [ - "auiFeatureId", - "displayName", - "jansScope", - "webhookId" - ], - "must": [ - "objectclass" - ], - "names": [ - "auiFeatures" - ], - "oid": "jansObjClass", - "sup": [ - "top" - ], - "x_origin": "Jans created objectclass" - }, - { - "kind": "STRUCTURAL", - "may": [ - "webhookId", - "displayName", - "description", - "url", - "httpMethod", - "httpRequestBody", - "jansEnabled", - "httpHeaders" - ], - "must": [ - "objectclass" - ], - "names": [ - "auiWebhooks" - ], - "oid": "jansObjClass", - "sup": [ - "top" - ], - "x_origin": "Jans created objectclass" - } + { + "kind": "STRUCTURAL", + "may": [ + "auiFeatureId", + "displayName", + "jansScope", + "webhookId" + ], + "must": [ + "objectclass" + ], + "names": [ + "auiFeatures" + ], + "oid": "jansObjClass", + "sup": [ + "top" + ], + "x_origin": "Jans created objectclass" + }, + { + "kind": "STRUCTURAL", + "may": [ + "webhookId", + "displayName", + "description", + "url", + "httpMethod", + "httpRequestBody", + "jansEnabled", + "httpHeaders" + ], + "must": [ + "objectclass" + ], + "names": [ + "auiWebhooks" + ], + "oid": "jansObjClass", + "sup": [ + "top" + ], + "x_origin": "Jans created objectclass" + } ], "oidMacros": { "jansAttr": "jansPublished:3", @@ -5143,4 +5152,4 @@ "jansReserved": "jansOrgOID:0", "jansSyntax": "jansPublished:1" } -} +} \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/templates/jans-config-api/dynamic-conf.json b/jans-linux-setup/jans_setup/templates/jans-config-api/dynamic-conf.json index 2f0f17fb8c7..438ab313194 100644 --- a/jans-linux-setup/jans_setup/templates/jans-config-api/dynamic-conf.json +++ b/jans-linux-setup/jans_setup/templates/jans-config-api/dynamic-conf.json @@ -1,5 +1,6 @@ { "configOauthEnabled": ${configOauthEnabled}, + "customAttributeValidationEnabled": false, "apiApprovedIssuer": ["${apiApprovedIssuer}"], "apiProtectionType": "${apiProtectionType}", "apiClientId": "${jca_client_id}", @@ -97,6 +98,11 @@ "name": "saml", "description": "saml plugin", "className": "io.jans.configapi.plugin.saml.rest.ApiApplication" + }, + { + "name": "kc-link", + "description": "kc-link plugin", + "className": "io.jans.configapi.plugin.kc.link.rest.ApiApplication" } ]