Skip to content

Commit ac7d4c6

Browse files
committed
Refactor file serialization logic in import and export APIs
1 parent dfffde3 commit ac7d4c6

File tree

14 files changed

+726
-543
lines changed

14 files changed

+726
-543
lines changed

components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java

Lines changed: 72 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@
1818

1919
package org.wso2.carbon.identity.api.server.application.management.v1.core;
2020

21-
import com.fasterxml.jackson.core.JsonFactory;
22-
import com.fasterxml.jackson.core.JsonProcessingException;
23-
import com.fasterxml.jackson.databind.ObjectMapper;
2421
import org.apache.commons.collections.CollectionUtils;
2522
import org.apache.commons.io.IOUtils;
2623
import org.apache.commons.lang.ArrayUtils;
@@ -91,6 +88,13 @@
9188
import org.wso2.carbon.identity.api.server.common.ContextLoader;
9289
import org.wso2.carbon.identity.api.server.common.Util;
9390
import org.wso2.carbon.identity.api.server.common.error.APIError;
91+
import org.wso2.carbon.identity.api.server.common.file.FileContent;
92+
import org.wso2.carbon.identity.api.server.common.file.FileSerializationConfig;
93+
import org.wso2.carbon.identity.api.server.common.file.FileSerializationException;
94+
import org.wso2.carbon.identity.api.server.common.file.FileSerializationUtil;
95+
import org.wso2.carbon.identity.api.server.common.file.JsonConfig;
96+
import org.wso2.carbon.identity.api.server.common.file.XmlConfig;
97+
import org.wso2.carbon.identity.api.server.common.file.YamlConfig;
9498
import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants;
9599
import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.StandardInboundProtocols;
96100
import org.wso2.carbon.identity.application.common.IdentityApplicationManagementClientException;
@@ -147,19 +151,10 @@
147151
import org.wso2.carbon.identity.template.mgt.model.Template;
148152
import org.wso2.carbon.user.core.common.AbstractUserStoreManager;
149153
import org.wso2.carbon.user.core.service.RealmService;
150-
import org.yaml.snakeyaml.DumperOptions;
151-
import org.yaml.snakeyaml.LoaderOptions;
152154
import org.yaml.snakeyaml.TypeDescription;
153-
import org.yaml.snakeyaml.Yaml;
154-
import org.yaml.snakeyaml.constructor.Constructor;
155-
import org.yaml.snakeyaml.error.YAMLException;
156-
import org.yaml.snakeyaml.inspector.TagInspector;
157-
import org.yaml.snakeyaml.inspector.TrustedPrefixesTagInspector;
158155

159156
import java.io.IOException;
160157
import java.io.InputStream;
161-
import java.io.StringReader;
162-
import java.io.StringWriter;
163158
import java.net.MalformedURLException;
164159
import java.net.URISyntaxException;
165160
import java.net.URL;
@@ -179,10 +174,7 @@
179174

180175
import javax.activation.MimeType;
181176
import javax.activation.MimeTypeParseException;
182-
import javax.xml.bind.JAXBContext;
183-
import javax.xml.bind.JAXBException;
184177
import javax.xml.bind.Marshaller;
185-
import javax.xml.bind.Unmarshaller;
186178

187179
import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.ADVANCED_CONFIGURATIONS;
188180
import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.APPLICATION_BASED_OUTBOUND_PROVISIONING_ENABLED;
@@ -267,6 +259,8 @@ public ServerApplicationManagementService(ApplicationManagementService applicati
267259
private static final String[] VALID_MEDIA_TYPES_JSON = {"application/json", "text/json"};
268260
private static final Class<?>[] INBOUND_CONFIG_PROTOCOLS = new Class<?>[]{ServiceProvider.class,
269261
SAMLSSOServiceProviderDTO.class, OAuthAppDO.class};
262+
private static final Class<?>[] ADDITIONAL_INBOUND_CONFIG_PROTOCOLS = new Class<?>[]{
263+
SAMLSSOServiceProviderDTO.class, OAuthAppDO.class};
270264

271265
static {
272266
SUPPORTED_FILTER_ATTRIBUTES.add(NAME);
@@ -586,90 +580,64 @@ private TransferResource generateFileFromModel(String fileType, ServiceProvider
586580
log.debug("Generating file content from model for application: " + serviceProvider.getApplicationName());
587581
}
588582

589-
StringBuilder fileNameSB = new StringBuilder(serviceProvider.getApplicationName());
590-
String fileContent;
591-
592-
if (Arrays.asList(VALID_MEDIA_TYPES_XML).contains(fileType)) {
593-
fileContent = parseXmlFromServiceProvider(serviceProvider);
594-
fileNameSB.append(XML_FILE_EXTENSION);
595-
} else if (Arrays.asList(VALID_MEDIA_TYPES_YAML).contains(fileType)) {
596-
fileContent = parseYamlFromServiceProvider(serviceProvider);
597-
fileNameSB.append(YML_FILE_EXTENSION);
598-
} else if (Arrays.asList(VALID_MEDIA_TYPES_JSON).contains(fileType)) {
599-
fileContent = parseJsonFromServiceProvider(serviceProvider);
600-
fileNameSB.append(JSON_FILE_EXTENSION);
601-
} else {
602-
throw Utils.buildServerError("Unsupported media type: " + fileType + "."
603-
+ " Supported media types are " + Arrays.toString(VALID_MEDIA_TYPES_XML) + ", "
604-
+ Arrays.toString(VALID_MEDIA_TYPES_YAML) + ", " + Arrays.toString(VALID_MEDIA_TYPES_JSON));
605-
}
606-
607583
try {
584+
FileContent fileContent =
585+
FileSerializationUtil.serialize(
586+
serviceProvider,
587+
serviceProvider.getApplicationName(),
588+
fileType,
589+
buildSerializationConfig()
590+
);
591+
608592
return new TransferResource(
609-
fileNameSB.toString(),
610-
fileContent.getBytes(StandardCharsets.UTF_8),
593+
fileContent.getFileName(),
594+
fileContent.getContent().getBytes(StandardCharsets.UTF_8),
611595
new MimeType("application/octet-stream")
612596
);
597+
} catch (FileSerializationException e) {
598+
throw Utils.buildServerError("Error exporting application from file.", e);
613599
} catch (MimeTypeParseException e) {
614600
throw new RuntimeException("Failed to parse MIME type", e);
615601
}
616602
}
617603

618-
private String parseXmlFromServiceProvider(ServiceProvider serviceProvider) {
604+
private FileSerializationConfig buildSerializationConfig() {
619605

620-
JAXBContext jaxbContext;
621-
try {
622-
jaxbContext = JAXBContext.newInstance(INBOUND_CONFIG_PROTOCOLS);
623-
Marshaller marshaller = jaxbContext.createMarshaller();
624-
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
606+
FileSerializationConfig config = new FileSerializationConfig();
607+
608+
XmlConfig xmlConfig = new XmlConfig();
609+
xmlConfig.setAdditionalJaxbClasses(ADDITIONAL_INBOUND_CONFIG_PROTOCOLS);
610+
xmlConfig.setMarshallerCustomizer(marshaller -> {
625611
marshaller.setListener(new Marshaller.Listener() {
626612
@Override
627613
public void beforeMarshal(Object source) {
628614
if (source instanceof InboundAuthenticationConfig) {
629-
InboundAuthenticationConfig config = (InboundAuthenticationConfig) source;
615+
InboundAuthenticationConfig authConfig = (InboundAuthenticationConfig) source;
630616
for (InboundAuthenticationRequestConfig requestConfig
631-
: config.getInboundAuthenticationRequestConfigs()) {
617+
: authConfig.getInboundAuthenticationRequestConfigs()) {
632618
requestConfig.setInboundConfiguration(null);
633619
}
634620
}
635621
}
636622
});
637-
StringWriter stringWriter = new StringWriter();
638-
marshaller.marshal(serviceProvider, stringWriter);
639-
return stringWriter.toString();
640-
} catch (JAXBException e) {
641-
throw Utils.buildServerError("Error exporting application from XML file.", e);
642-
}
643-
}
644-
645-
private String parseYamlFromServiceProvider(ServiceProvider serviceProvider) {
623+
});
624+
config.setXmlConfig(xmlConfig);
646625

647-
Constructor constructor = new Constructor(new LoaderOptions());
648-
CustomRepresenter representer = new CustomRepresenter(new DumperOptions());
649-
650-
for (Class<?> protocol : INBOUND_CONFIG_PROTOCOLS) {
651-
TypeDescription description = new TypeDescription(InboundConfigurationProtocol.class);
652-
description.addPropertyParameters("type", protocol);
653-
constructor.addTypeDescription(description);
654-
}
655-
656-
Yaml yaml = new Yaml(constructor, representer);
657-
try {
658-
return yaml.dump(serviceProvider);
659-
} catch (YAMLException e) {
660-
throw Utils.buildServerError("Error exporting application from YAML file.", e);
661-
}
662-
}
626+
YamlConfig yamlConfig = new YamlConfig();
627+
yamlConfig.setConstructorCustomizer(constructor -> {
628+
for (Class<?> protocol : INBOUND_CONFIG_PROTOCOLS) {
629+
TypeDescription description = new TypeDescription(InboundConfigurationProtocol.class);
630+
description.addPropertyParameters("type", protocol);
631+
constructor.addTypeDescription(description);
632+
}
633+
});
634+
config.setYamlConfig(yamlConfig);
663635

664-
private String parseJsonFromServiceProvider(ServiceProvider serviceProvider) {
636+
JsonConfig jsonConfig = new JsonConfig();
637+
jsonConfig.setSubtypes(INBOUND_CONFIG_PROTOCOLS);
638+
config.setJsonConfig(jsonConfig);
665639

666-
ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
667-
objectMapper.registerSubtypes(INBOUND_CONFIG_PROTOCOLS);
668-
try {
669-
return objectMapper.writeValueAsString(serviceProvider);
670-
} catch (JsonProcessingException e) {
671-
throw Utils.buildServerError("Error exporting application from JSON file.", e);
672-
}
640+
return config;
673641
}
674642

675643
/**
@@ -758,74 +726,42 @@ private ServiceProvider parseSP(SpFileContent spFileContent, String fileType, St
758726
spFileContent.getFileName(), tenantDomain));
759727
}
760728

761-
if (containsValidMediaType(fileType, VALID_MEDIA_TYPES_XML)) {
762-
return parseServiceProviderFromXml(spFileContent, tenantDomain);
763-
} else if (containsValidMediaType(fileType, VALID_MEDIA_TYPES_YAML)) {
764-
return parseServiceProviderFromYaml(spFileContent, tenantDomain);
765-
} else if (containsValidMediaType(fileType, VALID_MEDIA_TYPES_JSON)) {
766-
return parseServiceProviderFromJson(spFileContent, tenantDomain);
767-
} else {
768-
log.warn("Unsupported file type " + fileType + " for file " + spFileContent.getFileName() + " . " +
769-
"Defaulting to XML parsing");
770-
return parseServiceProviderFromXml(spFileContent, tenantDomain);
771-
}
772-
}
773-
774-
private boolean containsValidMediaType(String fileType, String[] mediaTypes) {
775-
776-
for (String mediaType : mediaTypes) {
777-
if (fileType.contains(mediaType)) {
778-
return true;
779-
}
780-
}
781-
return false;
782-
}
783-
784-
private ServiceProvider parseServiceProviderFromXml(SpFileContent spFileContent, String tenantDomain)
785-
throws IdentityApplicationManagementException {
786-
787729
try {
788-
JAXBContext jaxbContext = JAXBContext.newInstance(INBOUND_CONFIG_PROTOCOLS);
789-
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
790-
return (ServiceProvider) unmarshaller.unmarshal(new StringReader(spFileContent.getContent()));
791-
} catch (JAXBException e) {
792-
throw new IdentityApplicationManagementException(String.format("Error in reading XML Service Provider " +
730+
FileContent fileContent =
731+
new FileContent(
732+
spFileContent.getFileName(),
733+
fileType,
734+
spFileContent.getContent()
735+
);
736+
737+
return FileSerializationUtil.deserialize(
738+
fileContent,
739+
ServiceProvider.class,
740+
buildDeserializationConfig()
741+
);
742+
} catch (FileSerializationException e) {
743+
throw new IdentityApplicationManagementException(String.format("Error in reading Service Provider " +
793744
"configuration file %s uploaded by tenant: %s", spFileContent.getFileName(), tenantDomain), e);
794745
}
795746
}
796747

797-
private ServiceProvider parseServiceProviderFromYaml(SpFileContent spFileContent, String tenantDomain)
798-
throws IdentityApplicationManagementException {
748+
private FileSerializationConfig buildDeserializationConfig() {
799749

800-
try {
801-
// Add trusted tags included in the SP YAML file.
802-
List<String> trustedTagList = new ArrayList<>();
803-
trustedTagList.add(ServiceProvider.class.getName());
804-
trustedTagList.add(OAuthAppDO.class.getName());
805-
trustedTagList.add(SAMLSSOServiceProviderDTO.class.getName());
806-
807-
LoaderOptions loaderOptions = new LoaderOptions();
808-
TagInspector tagInspector = new TrustedPrefixesTagInspector(trustedTagList);
809-
loaderOptions.setTagInspector(tagInspector);
810-
Yaml yaml = new Yaml(new Constructor(ServiceProvider.class, loaderOptions));
811-
return yaml.loadAs(spFileContent.getContent(), ServiceProvider.class);
812-
} catch (YAMLException e) {
813-
throw new IdentityApplicationManagementException(String.format("Error in reading YAML Service Provider " +
814-
"configuration file %s uploaded by tenant: %s", spFileContent.getFileName(), tenantDomain), e);
815-
}
816-
}
750+
FileSerializationConfig config = new FileSerializationConfig();
817751

818-
private ServiceProvider parseServiceProviderFromJson(SpFileContent spFileContent, String tenantDomain)
819-
throws IdentityApplicationManagementException {
752+
XmlConfig xmlConfig = new XmlConfig();
753+
xmlConfig.setAdditionalJaxbClasses(ADDITIONAL_INBOUND_CONFIG_PROTOCOLS);
754+
config.setXmlConfig(xmlConfig);
820755

821-
try {
822-
ObjectMapper objectMapper = new ObjectMapper();
823-
objectMapper.registerSubtypes(INBOUND_CONFIG_PROTOCOLS);
824-
return objectMapper.readValue(spFileContent.getContent(), ServiceProvider.class);
825-
} catch (JsonProcessingException e) {
826-
throw new IdentityApplicationManagementException(String.format("Error in reading JSON Service Provider " +
827-
"configuration file %s uploaded by tenant: %s", spFileContent.getFileName(), tenantDomain), e);
828-
}
756+
YamlConfig yamlConfig = new YamlConfig();
757+
yamlConfig.setAdditionalTrustedClasses(OAuthAppDO.class, SAMLSSOServiceProviderDTO.class);
758+
config.setYamlConfig(yamlConfig);
759+
760+
JsonConfig jsonConfig = new JsonConfig();
761+
jsonConfig.setSubtypes(INBOUND_CONFIG_PROTOCOLS);
762+
config.setJsonConfig(jsonConfig);
763+
764+
return config;
829765
}
830766

831767
private SpFileContent buildSpFileContent(InputStream fileInputStream, Attachment fileDetail) throws IOException {

0 commit comments

Comments
 (0)