diff --git a/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/ClientLanguageMetadataTest.java b/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/ClientLanguageMetadataTest.java index a36929d5e30..1d3ce8ea3e6 100644 --- a/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/ClientLanguageMetadataTest.java +++ b/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/ClientLanguageMetadataTest.java @@ -147,16 +147,6 @@ public void authorizationCodeFlow( .claimsPresence(JwtClaimName.PHONE_NUMBER_VERIFIED, JwtClaimName.ADDRESS, JwtClaimName.USER_NAME) .claimsNoPresence("org_name", "work_phone") .check(); - - // 7. Request client info - ClientInfoClient clientInfoClient = new ClientInfoClient(clientInfoEndpoint); - ClientInfoResponse clientInfoResponse = clientInfoClient.execClientInfo(accessToken); - - showClient(clientInfoClient); - AssertBuilder.clientInfoResponse(clientInfoResponse) - .notNullClientInfoClaims() - .claimsPresence(CLIENT_INFO_NAME_CLAIMS) - .check(); } @Parameters({"userId", "userSecret", "redirectUri", "redirectUris", "clientJwksUri", @@ -223,16 +213,6 @@ public void requestParameterMethodRS256( .notNullClaimsPersonalData() .claimsPresence(JwtClaimName.EMAIL) .check(); - - // 5. Request client info - ClientInfoClient clientInfoClient = new ClientInfoClient(clientInfoEndpoint); - ClientInfoResponse clientInfoResponse = clientInfoClient.execClientInfo(accessToken); - - showClient(clientInfoClient); - AssertBuilder.clientInfoResponse(clientInfoResponse) - .notNullClientInfoClaims() - .claimsPresence(CLIENT_INFO_NAME_CLAIMS) - .check(); } private RegisterResponse getRegisterResponse(String redirectUris, String sectorIdentifierUri, List responseTypes, List scopes, String clientJwksUri) { diff --git a/jans-auth-server/common/src/main/java/io/jans/as/common/model/registration/Client.java b/jans-auth-server/common/src/main/java/io/jans/as/common/model/registration/Client.java index 4ffd90f2ed0..56b1b8cab81 100644 --- a/jans-auth-server/common/src/main/java/io/jans/as/common/model/registration/Client.java +++ b/jans-auth-server/common/src/main/java/io/jans/as/common/model/registration/Client.java @@ -26,7 +26,7 @@ /** * @author Javier Rojas Blum - * @version June 30, 2022 + * @version October 17, 2022 */ @DataEntry(sortBy = {"displayName"}) @ObjectClass(value = "jansClnt") @@ -79,29 +79,44 @@ public class Client extends DeletableEntity implements Serializable { private String idTokenTokenBindingCnf; @AttributeName(name = "displayName") + private String clientName; + + @AttributeName(name = "jansLogoURI") + private String logoUri; + + @AttributeName(name = "jansClntURI") + private String clientUri; + + @AttributeName(name = "jansPolicyURI") + private String policyUri; + + @AttributeName(name = "jansTosURI") + private String tosUri; + + @AttributeName(name = "displayNameLocalized") @JsonObject @LanguageTag - private LocalizedString clientName = new LocalizedString(); + private LocalizedString clientNameLocalized = new LocalizedString(); - @AttributeName(name = "jansLogoURI") + @AttributeName(name = "jansLogoURILocalized") @JsonObject @LanguageTag - private LocalizedString logoUri = new LocalizedString(); + private LocalizedString logoUriLocalized = new LocalizedString(); - @AttributeName(name = "jansClntURI") + @AttributeName(name = "jansClntURILocalized") @JsonObject @LanguageTag - private LocalizedString clientUri = new LocalizedString(); + private LocalizedString clientUriLocalized = new LocalizedString(); - @AttributeName(name = "jansPolicyURI") + @AttributeName(name = "jansPolicyURILocalized") @JsonObject @LanguageTag - private LocalizedString policyUri = new LocalizedString(); + private LocalizedString policyUriLocalized = new LocalizedString(); - @AttributeName(name = "jansTosURI") + @AttributeName(name = "jansTosURILocalized") @JsonObject @LanguageTag - private LocalizedString tosUri = new LocalizedString(); + private LocalizedString tosUriLocalized = new LocalizedString(); @AttributeName(name = "jansJwksURI") private String jwksUri; @@ -590,11 +605,11 @@ public boolean isTokenBindingSupported() { } /** - * Returns the name of the Client to be presented to the user represented in a language and a script. + * Returns the name of the Client to be presented to the user. * * @return The name of the Client to be presented to the user. */ - public LocalizedString getClientName() { + public String getClientName() { return clientName; } @@ -604,7 +619,102 @@ public LocalizedString getClientName() { * @param clientName The name of the Client to be presented to the user. */ public void setClientName(String clientName) { - this.clientName.setValue(clientName); + this.clientName = clientName; + } + + /** + * Returns a URL that references a logo for the Client application. + * + * @return The URL of a logo image for the Client where it can be retrieved. + */ + public String getLogoUri() { + return logoUri; + } + + /** + * Sets a URL that references a logo for the Client application. + * + * @param logoUri The URL of a logo image for the Client where it can be retrieved. + */ + public void setLogoUri(String logoUri) { + this.logoUri = logoUri; + } + + /** + * Returns a URL of the home page of the Client. + * + * @return The URL of the home page of the Client. + */ + public String getClientUri() { + return clientUri; + } + + /** + * Sets a URL of the home page of the Client. + * + * @param clientUri The URL of the home page of the Client. + */ + public void setClientUri(String clientUri) { + this.clientUri = clientUri; + } + + /** + * Returns a URL that the Relying Party Client provides to the End-User to read about how the profile data will + * be used. + * + * @return A URL location about how the profile data will be used. + */ + public String getPolicyUri() { + return policyUri; + } + + /** + * Sets a URL that the Relying Party Client provides to the End-User to read about how the profile data will + * be used. + * + * @param policyUri A URL location about how the profile data will be used. + */ + public void setPolicyUri(String policyUri) { + this.policyUri = policyUri; + } + + /** + * Returns a URL that the Relying Party Client provides to the End-User to read about the Relying Party's terms + * of service. + * + * @return The terms of service URL. + */ + public String getTosUri() { + return tosUri; + } + + /** + * Sets a URL that the Relying Party Client provides to the End-User to read about the Relying Party's terms of + * service. + * + * @param tosUri The terms of service URL. + */ + public void setTosUri(String tosUri) { + this.tosUri = tosUri; + } + + /** + * Returns the name of the Client to be presented to the user represented in a language and a script. + * + * @return The name of the Client to be presented to the user. + */ + public LocalizedString getClientNameLocalized() { + return clientNameLocalized; + } + + /** + * Sets the name of the Client to be presented to the user. + * + * @param clientName The name of the Client to be presented to the user. + */ + public void setClientNameLocalized(String clientName) { + this.clientName = clientName; + this.clientNameLocalized.setValue(clientName); } /** @@ -613,8 +723,12 @@ public void setClientName(String clientName) { * @param clientName The name of the Client to be presented to the user. * @param locale The locale */ - public void setClientName(String clientName, Locale locale) { - this.clientName.setValue(clientName, locale); + public void setClientNameLocalized(String clientName, Locale locale) { + if (StringUtils.isNotBlank(locale.toString())) { + this.clientNameLocalized.setValue(clientName, locale); + } else { + setClientNameLocalized(clientName); + } } /** @@ -622,8 +736,8 @@ public void setClientName(String clientName, Locale locale) { * * @return The URL of a logo image for the Client where it can be retrieved. */ - public LocalizedString getLogoUri() { - return logoUri; + public LocalizedString getLogoUriLocalized() { + return logoUriLocalized; } /** @@ -631,8 +745,9 @@ public LocalizedString getLogoUri() { * * @param logoUri The URL of a logo image for the Client where it can be retrieved. */ - public void setLogoUri(String logoUri) { - this.logoUri.setValue(logoUri); + public void setLogoUriLocalized(String logoUri) { + this.logoUri = logoUri; + this.logoUriLocalized.setValue(logoUri); } /** @@ -641,8 +756,12 @@ public void setLogoUri(String logoUri) { * @param logoUri The URL of a logo image for the Client where it can be retrieved. * @param locale The locale */ - public void setLogoUri(String logoUri, Locale locale) { - this.logoUri.setValue(logoUri, locale); + public void setLogoUriLocalized(String logoUri, Locale locale) { + if (StringUtils.isNotBlank(locale.toString())) { + this.logoUriLocalized.setValue(logoUri, locale); + } else { + setLogoUriLocalized(logoUri); + } } /** @@ -650,8 +769,8 @@ public void setLogoUri(String logoUri, Locale locale) { * * @return The URL of the home page of the Client. */ - public LocalizedString getClientUri() { - return clientUri; + public LocalizedString getClientUriLocalized() { + return clientUriLocalized; } /** @@ -659,8 +778,9 @@ public LocalizedString getClientUri() { * * @param clientUri The URL of the home page of the Client. */ - public void setClientUri(String clientUri) { - this.clientUri.setValue(clientUri); + public void setClientUriLocalized(String clientUri) { + this.clientUri = clientUri; + this.clientUriLocalized.setValue(clientUri); } /** @@ -669,8 +789,12 @@ public void setClientUri(String clientUri) { * @param clientUri The URL of the home page of the Client. * @param locale The locale */ - public void setClientUri(String clientUri, Locale locale) { - this.clientUri.setValue(clientUri, locale); + public void setClientUriLocalized(String clientUri, Locale locale) { + if (StringUtils.isNotBlank(locale.toString())) { + this.clientUriLocalized.setValue(clientUri, locale); + } else { + setClientUriLocalized(clientUri); + } } /** @@ -679,8 +803,8 @@ public void setClientUri(String clientUri, Locale locale) { * * @return A URL location about how the profile data will be used. */ - public LocalizedString getPolicyUri() { - return policyUri; + public LocalizedString getPolicyUriLocalized() { + return policyUriLocalized; } /** @@ -689,8 +813,9 @@ public LocalizedString getPolicyUri() { * * @param policyUri A URL location about how the profile data will be used. */ - public void setPolicyUri(String policyUri) { - this.policyUri.setValue(policyUri); + public void setPolicyUriLocalized(String policyUri) { + this.policyUri = policyUri; + this.policyUriLocalized.setValue(policyUri); } /** @@ -700,8 +825,12 @@ public void setPolicyUri(String policyUri) { * @param policyUri A URL location about how the profile data will be used. * @param locale The locale */ - public void setPolicyUri(String policyUri, Locale locale) { - this.policyUri.setValue(policyUri, locale); + public void setPolicyUriLocalized(String policyUri, Locale locale) { + if (StringUtils.isNotBlank(locale.toString())) { + this.policyUriLocalized.setValue(policyUri, locale); + } else { + setPolicyUriLocalized(policyUri); + } } /** @@ -710,8 +839,8 @@ public void setPolicyUri(String policyUri, Locale locale) { * * @return The terms of service URL. */ - public LocalizedString getTosUri() { - return tosUri; + public LocalizedString getTosUriLocalized() { + return tosUriLocalized; } /** @@ -720,8 +849,9 @@ public LocalizedString getTosUri() { * * @param tosUri The terms of service URL. */ - public void setTosUri(String tosUri) { - this.tosUri.setValue(tosUri); + public void setTosUriLocalized(String tosUri) { + this.tosUri = tosUri; + this.tosUriLocalized.setValue(tosUri); } /** @@ -731,8 +861,12 @@ public void setTosUri(String tosUri) { * @param tosUri The terms of service URL. * @param locale The Locale */ - public void setTosUri(String tosUri, Locale locale) { - this.tosUri.setValue(tosUri, locale); + public void setTosUriLocalized(String tosUri, Locale locale) { + if (StringUtils.isNotBlank(locale.toString())) { + this.tosUriLocalized.setValue(tosUri, locale); + } else { + setTosUriLocalized(tosUri); + } } /** @@ -1288,7 +1422,7 @@ public void setBackchannelUserCodeParameter(Boolean backchannelUserCodeParameter } public String getDisplayName() { - return getClientName().getValue(); + return getClientName(); } public void setDisplayName(String displayName) { diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterJsonService.java b/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterJsonService.java index 899d5340c5a..60073ba9d47 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterJsonService.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterJsonService.java @@ -84,6 +84,12 @@ public JSONObject getJSONObject(Client client) throws JSONException, StringEncry Util.addToJSONObjectIfNotNull(responseJsonObject, POLICY_URI.toString(), client.getPolicyUri()); Util.addToJSONObjectIfNotNull(responseJsonObject, TOS_URI.toString(), client.getTosUri()); + Util.addToJSONObjectIfNotNull(responseJsonObject, CLIENT_NAME.toString(), client.getClientNameLocalized()); + Util.addToJSONObjectIfNotNull(responseJsonObject, LOGO_URI.toString(), client.getLogoUriLocalized()); + Util.addToJSONObjectIfNotNull(responseJsonObject, CLIENT_URI.toString(), client.getClientUriLocalized()); + Util.addToJSONObjectIfNotNull(responseJsonObject, POLICY_URI.toString(), client.getPolicyUriLocalized()); + Util.addToJSONObjectIfNotNull(responseJsonObject, TOS_URI.toString(), client.getTosUriLocalized()); + Util.addToJSONObjectIfNotNull(responseJsonObject, REDIRECT_URIS.toString(), client.getRedirectUris()); Util.addToJSONObjectIfNotNull(responseJsonObject, CLAIMS_REDIRECT_URIS.toString(), client.getClaimRedirectUris()); Util.addToJSONObjectIfNotNull(responseJsonObject, RESPONSE_TYPES.toString(), ResponseType.toStringArray(client.getResponseTypes())); diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterService.java b/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterService.java index a8527cd35f2..8bf8a968fce 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterService.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterService.java @@ -149,19 +149,19 @@ public void updateClientFromRequestObject(Client client, RegisterRequest request } for (String key : requestObject.getClientNameLanguageTags()) { - client.setClientName(requestObject.getClientName(key), Locale.forLanguageTag(key)); + client.setClientNameLocalized(requestObject.getClientName(key), Locale.forLanguageTag(key)); } for (String key : requestObject.getLogoUriLanguageTags()) { - client.setLogoUri(requestObject.getLogoUri(key), Locale.forLanguageTag(key)); + client.setLogoUriLocalized(requestObject.getLogoUri(key), Locale.forLanguageTag(key)); } for (String key : requestObject.getClientUriLanguageTags()) { - client.setClientUri(requestObject.getClientUri(key), Locale.forLanguageTag(key)); + client.setClientUriLocalized(requestObject.getClientUri(key), Locale.forLanguageTag(key)); } for (String key : requestObject.getPolicyUriLanguageTags()) { - client.setPolicyUri(requestObject.getPolicyUri(key), Locale.forLanguageTag(key)); + client.setPolicyUriLocalized(requestObject.getPolicyUri(key), Locale.forLanguageTag(key)); } for (String key : requestObject.getTosUriLanguageTags()) { - client.setTosUri(requestObject.getTosUri(key), Locale.forLanguageTag(key)); + client.setTosUriLocalized(requestObject.getTosUri(key), Locale.forLanguageTag(key)); } if (StringUtils.isNotBlank(requestObject.getJwksUri())) { diff --git a/jans-linux-setup/jans_setup/static/rdbm/sql_data_types.json b/jans-linux-setup/jans_setup/static/rdbm/sql_data_types.json index 8f32c9ecff4..a560f799534 100644 --- a/jans-linux-setup/jans_setup/static/rdbm/sql_data_types.json +++ b/jans-linux-setup/jans_setup/static/rdbm/sql_data_types.json @@ -26,6 +26,17 @@ "type": "STRING" } }, + "displayNameLocalized": { + "mysql": { + "type": "JSON" + }, + "pgsql": { + "type": "JSONB" + }, + "spanner": { + "type": "ARRAY" + } + }, "givenName": { "mysql": { "size": 128, @@ -301,6 +312,17 @@ "type": "STRING(MAX)" } }, + "jansLogoURILocalized": { + "mysql": { + "type": "JSON" + }, + "pgsql": { + "type": "JSONB" + }, + "spanner": { + "type": "ARRAY" + } + }, "jansPolicyURI": { "mysql": { "type": "TINYTEXT" @@ -312,6 +334,17 @@ "type": "STRING(MAX)" } }, + "jansPolicyURILocalized": { + "mysql": { + "type": "JSON" + }, + "pgsql": { + "type": "JSONB" + }, + "spanner": { + "type": "ARRAY" + } + }, "jansSectorIdentifierURI": { "mysql": { "type": "TINYTEXT" @@ -334,6 +367,17 @@ "type": "STRING(MAX)" } }, + "jansClntURILocalized": { + "mysql": { + "type": "JSON" + }, + "pgsql": { + "type": "JSONB" + }, + "spanner": { + "type": "ARRAY" + } + }, "jansTosURI": { "mysql": { "type": "TINYTEXT" @@ -345,6 +389,17 @@ "type": "STRING(MAX)" } }, + "jansTosURILocalized": { + "mysql": { + "type": "JSON" + }, + "pgsql": { + "type": "JSONB" + }, + "spanner": { + "type": "ARRAY" + } + }, "jansJwt": { "mysql": { "type": "TEXT" diff --git a/jans-orm/core/src/main/java/io/jans/orm/impl/BaseEntryManager.java b/jans-orm/core/src/main/java/io/jans/orm/impl/BaseEntryManager.java index 1605f8990c3..c7c7752356a 100644 --- a/jans-orm/core/src/main/java/io/jans/orm/impl/BaseEntryManager.java +++ b/jans-orm/core/src/main/java/io/jans/orm/impl/BaseEntryManager.java @@ -6,44 +6,9 @@ package io.jans.orm.impl; -import java.io.Serializable; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.stream.Collectors; - -import org.apache.commons.codec.binary.Base64; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.fasterxml.jackson.databind.ObjectMapper; - import io.jans.orm.PersistenceEntryManager; -import io.jans.orm.annotation.AttributeEnum; -import io.jans.orm.annotation.AttributeName; -import io.jans.orm.annotation.AttributesList; -import io.jans.orm.annotation.CustomObjectClass; -import io.jans.orm.annotation.DN; -import io.jans.orm.annotation.DataEntry; -import io.jans.orm.annotation.Expiration; -import io.jans.orm.annotation.JsonObject; -import io.jans.orm.annotation.LanguageTag; -import io.jans.orm.annotation.ObjectClass; -import io.jans.orm.annotation.SchemaEntry; +import io.jans.orm.annotation.*; import io.jans.orm.exception.EntryPersistenceException; import io.jans.orm.exception.InvalidArgumentException; import io.jans.orm.exception.MappingException; @@ -63,6 +28,19 @@ import io.jans.orm.search.filter.FilterProcessor; import io.jans.orm.util.ArrayHelper; import io.jans.orm.util.StringHelper; +import org.apache.commons.codec.binary.Base64; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.*; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import static io.jans.orm.model.base.LocalizedString.*; /** * Abstract Entry Manager @@ -1018,7 +996,7 @@ protected List createEntities(Class entryClass, List filteredAttrs = attributesMap.entrySet().stream() .filter(x -> x.getKey().toLowerCase().startsWith(finalLdapAttributeName.toLowerCase())) .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); @@ -1201,13 +1179,20 @@ public Class getCustomAttributesListItemType(Object entry, AttributesList att protected void loadLocalizedString(Map attributesMap, LocalizedString localizedString, Map filteredAttrs) { filteredAttrs.forEach((key, value) -> { AttributeData data = attributesMap.get(key); - if (data.getValues() != null && data.getValues().length == 1 && data.getValues()[0] instanceof Map) { - Map values = (Map) data.getValues()[0]; - values.forEach((languageTag, val) -> { - if (languageTag instanceof String && val instanceof String) { - localizedString.setValue((String) val, Locale.forLanguageTag((String) languageTag)); - } - }); + if (data.getValues() != null && data.getValues().length == 1) { + if (data.getValues()[0] instanceof Map) { + Map values = (Map) data.getValues()[0]; + values.forEach((languageTag, val) -> { + if (languageTag instanceof String && val instanceof String) { + localizedString.setValue((String) val, Locale.forLanguageTag((String) languageTag)); + } + }); + } else if (data.getValues()[0] instanceof String) { + String jsonStr = (String) data.getValues()[0]; + JSONObject jsonObject = new JSONObject(jsonStr); + + localizedString.loadFromJson(jsonObject, key); + } } }); } @@ -1586,11 +1571,7 @@ protected List getAttributesListForPersist(Object entry, LanguageTag.class); if (ldapAttribute != null) { if (languageTag != null) { - List listAttributes = getAttributeDataFromLocalizedString( - entry, ldapAttribute, propertyName); - if (listAttributes != null) { - attributes.addAll(listAttributes); - } + addAttributeDataFromLocalizedString(entry, ldapAttribute, propertyName, attributes); } else { AttributeData attribute = getAttributeDataFromAttribute(entry, ldapAttribute, propertiesAnnotation, propertyName); @@ -1644,40 +1625,48 @@ private AttributeData getAttributeDataFromAttribute(Object entry, Annotation lda return attribute; } - private List getAttributeDataFromLocalizedString( - Object entry, Annotation ldapAttribute, String propertyName) { + protected void addAttributeDataFromLocalizedString(Object entry, Annotation ldapAttribute, String propertyName, List attributes) { + Class entryClass = entry.getClass(); - Class entryClass = entry.getClass(); + Getter getter = getGetter(entryClass, propertyName); + if (getter == null) { + throw new MappingException("Entry should has getter for property " + propertyName); + } - Getter getter = getGetter(entryClass, propertyName); - if (getter == null) { - throw new MappingException("Entry should has getter for property " + propertyName); - } + Object propertyValue = getter.get(entry); + if (propertyValue == null) { + return; + } - Object propertyValue = getter.get(entry); - if (propertyValue == null) { - return null; - } + if (!(propertyValue instanceof LocalizedString)) { + throw new MappingException("Entry property should be LocalizedString"); + } - if (!(propertyValue instanceof LocalizedString)) { - throw new MappingException("Entry property should be LocalizedString"); - } + LocalizedString localizedString = (LocalizedString) propertyValue; + String ldapAttributeName = ((AttributeName) ldapAttribute).name(); - LocalizedString localizedString = (LocalizedString) propertyValue; - String ldapAttributeName = ((AttributeName) ldapAttribute).name(); + AttributeData attributeDataLocalized = getAttributeDataFromLocalizedString(ldapAttributeName, localizedString); + if (attributeDataLocalized != null) { + attributes.add(attributeDataLocalized); + } + } - return getAttributeDataFromLocalizedString(ldapAttributeName, localizedString); - } + protected AttributeData getAttributeDataFromLocalizedString(String ldapAttributeName, LocalizedString localizedString) { + AttributeData attributeData = new AttributeData(ldapAttributeName, new String[1]); - protected List getAttributeDataFromLocalizedString(String ldapAttributeName, LocalizedString localizedString) { - List listAttributes = new ArrayList<>(); + JSONObject jsonObject = new JSONObject(); - AttributeData attributeData = new AttributeData(ldapAttributeName, localizedString.getValues()); - attributeData.setMultiValued(true); - listAttributes.add(attributeData); + localizedString.getLanguageTags().forEach(languageTag -> { + String key = localizedString.addLdapLanguageTag(ldapAttributeName, languageTag); + String value = localizedString.getValue(languageTag); - return listAttributes; - } + jsonObject.put(key, value); + }); + + attributeData.getValues()[0] = jsonObject.toString(); + + return attributeData; + } public List getAttributeDataListFromCustomAttributesList(Object entry, AttributesList attributesList, String propertyName) { diff --git a/jans-orm/ldap/src/main/java/io/jans/orm/ldap/impl/LdapEntryManager.java b/jans-orm/ldap/src/main/java/io/jans/orm/ldap/impl/LdapEntryManager.java index 45ebd5196ea..4d43c15cafb 100644 --- a/jans-orm/ldap/src/main/java/io/jans/orm/ldap/impl/LdapEntryManager.java +++ b/jans-orm/ldap/src/main/java/io/jans/orm/ldap/impl/LdapEntryManager.java @@ -6,36 +6,10 @@ package io.jans.orm.ldap.impl; -import java.io.Serializable; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.codec.binary.Base64; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.unboundid.ldap.sdk.Attribute; -import com.unboundid.ldap.sdk.LDAPConnection; -import com.unboundid.ldap.sdk.Modification; -import com.unboundid.ldap.sdk.ModificationType; -import com.unboundid.ldap.sdk.ResultCode; -import com.unboundid.ldap.sdk.SearchResult; -import com.unboundid.ldap.sdk.SearchResultEntry; +import com.unboundid.ldap.sdk.*; import com.unboundid.util.StaticUtils; - import io.jans.orm.PersistenceEntryManager; +import io.jans.orm.annotation.AttributeName; import io.jans.orm.event.DeleteNotifier; import io.jans.orm.exception.AuthenticationException; import io.jans.orm.exception.EntryDeleteException; @@ -47,19 +21,23 @@ import io.jans.orm.impl.BaseEntryManager; import io.jans.orm.ldap.operation.LdapOperationService; import io.jans.orm.ldap.operation.impl.LdapOperationServiceImpl; -import io.jans.orm.model.AttributeData; -import io.jans.orm.model.AttributeDataModification; -import io.jans.orm.model.BatchOperation; -import io.jans.orm.model.DefaultBatchOperation; -import io.jans.orm.model.PagedResult; +import io.jans.orm.model.*; import io.jans.orm.model.SearchScope; -import io.jans.orm.model.SortOrder; -import io.jans.orm.model.base.LocalizedString; import io.jans.orm.model.AttributeDataModification.AttributeModificationType; +import io.jans.orm.model.base.LocalizedString; +import io.jans.orm.reflect.property.Getter; import io.jans.orm.reflect.property.PropertyAnnotation; import io.jans.orm.search.filter.Filter; import io.jans.orm.util.ArrayHelper; import io.jans.orm.util.StringHelper; +import org.apache.commons.codec.binary.Base64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.text.ParseException; +import java.util.*; import static io.jans.orm.model.base.LocalizedString.*; @@ -657,13 +635,13 @@ private List createEntitiesVirtualListView(Class entryClass, List getAttributeDataFromLocalizedString(String ldapAttributeName, LocalizedString localizedString) { + protected List getAttributeDataListFromLocalizedString(String ldapAttributeName, LocalizedString localizedString) { List listAttributes = new ArrayList<>(); localizedString.getLanguageTags().forEach(languageTag -> { String value = localizedString.getValue(languageTag); - String key = localizedString.addLdapLanguageTag(ldapAttributeName, languageTag); + String ldapAttributeNameLocalized = ldapAttributeName.replace(LOCALIZED, EMPTY_LANG_TAG); + String key = localizedString.addLdapLanguageTag(ldapAttributeNameLocalized, languageTag); AttributeData attributeData = new AttributeData(key, value); listAttributes.add(attributeData); @@ -993,6 +971,33 @@ protected Object getNativeDateAttributeValue(Date dateValue) { return encodeTime(dateValue); } + @Override + protected void addAttributeDataFromLocalizedString(Object entry, Annotation ldapAttribute, String propertyName, List attributes) { + Class entryClass = entry.getClass(); + + Getter getter = getGetter(entryClass, propertyName); + if (getter == null) { + throw new MappingException("Entry should has getter for property " + propertyName); + } + + Object propertyValue = getter.get(entry); + if (propertyValue == null) { + return; + } + + if (!(propertyValue instanceof LocalizedString)) { + throw new MappingException("Entry property should be LocalizedString"); + } + + LocalizedString localizedString = (LocalizedString) propertyValue; + String ldapAttributeName = ((AttributeName) ldapAttribute).name(); + + List listAttributes = getAttributeDataListFromLocalizedString(ldapAttributeName, localizedString); + if (listAttributes != null) { + attributes.addAll(listAttributes); + } + } + private static class CountBatchOperation extends DefaultBatchOperation { private int countEntries = 0; diff --git a/jans-orm/model/src/main/java/io/jans/orm/model/base/LocalizedString.java b/jans-orm/model/src/main/java/io/jans/orm/model/base/LocalizedString.java index f392f1f0c2e..4b5e3a87da1 100644 --- a/jans-orm/model/src/main/java/io/jans/orm/model/base/LocalizedString.java +++ b/jans-orm/model/src/main/java/io/jans/orm/model/base/LocalizedString.java @@ -18,7 +18,7 @@ /** * @author Javier Rojas Blum - * @version April 26, 2022 + * @version October 17, 2022 */ public class LocalizedString implements Serializable { @@ -32,6 +32,8 @@ public class LocalizedString implements Serializable { public static final String LANG_PREFIX = "lang"; public static final String LANG_JOINER = "-"; + public static final String LOCALIZED = "Localized"; + public LocalizedString() { values = new HashMap<>(); } @@ -69,6 +71,11 @@ public String addLdapLanguageTag(String ldapAttributeName, String languageTag) { LANG_SEPARATOR + LANG_PREFIX + LANG_JOINER + languageTag : EMPTY_LANG_TAG); } + public String removeLdapLanguageTag(String value, String ldapAttributeName) { + return value.replaceAll("(?i)" + ldapAttributeName, "") + .replace(LANG_SEPARATOR + LANG_PREFIX + LANG_JOINER, ""); + } + private String getLanguageTag(Locale locale) { List keyParts = new ArrayList<>(); keyParts.add(locale.getLanguage()); @@ -105,6 +112,17 @@ public void addToJSON(JSONObject jsonObj, String claimName) { }); } + public void loadFromJson(JSONObject jsonObject, String ldapAttributeName) { + if (jsonObject == null) { + return; + } + + jsonObject.keySet().forEach((localeStr) -> { + String languageTag = removeLdapLanguageTag(localeStr, ldapAttributeName); + setValue(jsonObject.getString(localeStr), Locale.forLanguageTag(languageTag)); + }); + } + @Override public String toString() { return values.toString();