Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@

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

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
Expand Down Expand Up @@ -91,6 +88,13 @@
import org.wso2.carbon.identity.api.server.common.ContextLoader;
import org.wso2.carbon.identity.api.server.common.Util;
import org.wso2.carbon.identity.api.server.common.error.APIError;
import org.wso2.carbon.identity.api.server.common.file.FileContent;
import org.wso2.carbon.identity.api.server.common.file.FileSerializationConfig;
import org.wso2.carbon.identity.api.server.common.file.FileSerializationException;
import org.wso2.carbon.identity.api.server.common.file.FileSerializationUtil;
import org.wso2.carbon.identity.api.server.common.file.JsonConfig;
import org.wso2.carbon.identity.api.server.common.file.XmlConfig;
import org.wso2.carbon.identity.api.server.common.file.YamlConfig;
import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants;
import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants.StandardInboundProtocols;
import org.wso2.carbon.identity.application.common.IdentityApplicationManagementClientException;
Expand Down Expand Up @@ -147,19 +151,10 @@
import org.wso2.carbon.identity.template.mgt.model.Template;
import org.wso2.carbon.user.core.common.AbstractUserStoreManager;
import org.wso2.carbon.user.core.service.RealmService;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.inspector.TagInspector;
import org.yaml.snakeyaml.inspector.TrustedPrefixesTagInspector;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
Expand All @@ -179,10 +174,7 @@

import javax.activation.MimeType;
import javax.activation.MimeTypeParseException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

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

static {
SUPPORTED_FILTER_ATTRIBUTES.add(NAME);
Expand Down Expand Up @@ -586,90 +580,68 @@ private TransferResource generateFileFromModel(String fileType, ServiceProvider
log.debug("Generating file content from model for application: " + serviceProvider.getApplicationName());
}

StringBuilder fileNameSB = new StringBuilder(serviceProvider.getApplicationName());
String fileContent;

if (Arrays.asList(VALID_MEDIA_TYPES_XML).contains(fileType)) {
fileContent = parseXmlFromServiceProvider(serviceProvider);
fileNameSB.append(XML_FILE_EXTENSION);
} else if (Arrays.asList(VALID_MEDIA_TYPES_YAML).contains(fileType)) {
fileContent = parseYamlFromServiceProvider(serviceProvider);
fileNameSB.append(YML_FILE_EXTENSION);
} else if (Arrays.asList(VALID_MEDIA_TYPES_JSON).contains(fileType)) {
fileContent = parseJsonFromServiceProvider(serviceProvider);
fileNameSB.append(JSON_FILE_EXTENSION);
} else {
throw Utils.buildServerError("Unsupported media type: " + fileType + "."
+ " Supported media types are " + Arrays.toString(VALID_MEDIA_TYPES_XML) + ", "
+ Arrays.toString(VALID_MEDIA_TYPES_YAML) + ", " + Arrays.toString(VALID_MEDIA_TYPES_JSON));
}

try {
FileContent fileContent =
FileSerializationUtil.serialize(
serviceProvider,
serviceProvider.getApplicationName(),
fileType,
buildSerializationConfig()
);

return new TransferResource(
fileNameSB.toString(),
fileContent.getBytes(StandardCharsets.UTF_8),
fileContent.getFileName(),
fileContent.getContent().getBytes(StandardCharsets.UTF_8),
new MimeType("application/octet-stream")
);
} catch (FileSerializationException e) {
throw Utils.buildServerError("Error exporting application from file.", e);
} catch (MimeTypeParseException e) {
throw new RuntimeException("Failed to parse MIME type", e);
}
}

private String parseXmlFromServiceProvider(ServiceProvider serviceProvider) {
private FileSerializationConfig buildSerializationConfig() {

JAXBContext jaxbContext;
try {
jaxbContext = JAXBContext.newInstance(INBOUND_CONFIG_PROTOCOLS);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
FileSerializationConfig config = new FileSerializationConfig();

XmlConfig xmlConfig = new XmlConfig();
xmlConfig.setAdditionalJaxbClasses(ADDITIONAL_INBOUND_CONFIG_PROTOCOLS);
xmlConfig.setMarshallerCustomizer(marshaller -> {
marshaller.setListener(new Marshaller.Listener() {
@Override
public void beforeMarshal(Object source) {
if (source instanceof InboundAuthenticationConfig) {
InboundAuthenticationConfig config = (InboundAuthenticationConfig) source;
InboundAuthenticationConfig authConfig = (InboundAuthenticationConfig) source;
for (InboundAuthenticationRequestConfig requestConfig
: config.getInboundAuthenticationRequestConfigs()) {
: authConfig.getInboundAuthenticationRequestConfigs()) {
requestConfig.setInboundConfiguration(null);
}
}
}
});
StringWriter stringWriter = new StringWriter();
marshaller.marshal(serviceProvider, stringWriter);
return stringWriter.toString();
} catch (JAXBException e) {
throw Utils.buildServerError("Error exporting application from XML file.", e);
}
}

private String parseYamlFromServiceProvider(ServiceProvider serviceProvider) {
});
config.setXmlConfig(xmlConfig);

Constructor constructor = new Constructor(new LoaderOptions());
CustomRepresenter representer = new CustomRepresenter(new DumperOptions());

for (Class<?> protocol : INBOUND_CONFIG_PROTOCOLS) {
TypeDescription description = new TypeDescription(InboundConfigurationProtocol.class);
description.addPropertyParameters("type", protocol);
constructor.addTypeDescription(description);
}
YamlConfig yamlConfig = new YamlConfig();
yamlConfig.setConstructorCustomizer(constructor -> {
for (Class<?> protocol : INBOUND_CONFIG_PROTOCOLS) {
TypeDescription description = new TypeDescription(InboundConfigurationProtocol.class);
description.addPropertyParameters("type", protocol);
constructor.addTypeDescription(description);
}
});
yamlConfig.setRepresenterFactory(CustomRepresenter::new);
config.setYamlConfig(yamlConfig);

Yaml yaml = new Yaml(constructor, representer);
try {
return yaml.dump(serviceProvider);
} catch (YAMLException e) {
throw Utils.buildServerError("Error exporting application from YAML file.", e);
}
}
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setSubtypes(INBOUND_CONFIG_PROTOCOLS);
config.setJsonConfig(jsonConfig);

private String parseJsonFromServiceProvider(ServiceProvider serviceProvider) {
config.setSerializeDefault(FileSerializationConfig.DefaultFormat.ERROR);
config.setDeserializeDefault(FileSerializationConfig.DefaultFormat.XML);

ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
objectMapper.registerSubtypes(INBOUND_CONFIG_PROTOCOLS);
try {
return objectMapper.writeValueAsString(serviceProvider);
} catch (JsonProcessingException e) {
throw Utils.buildServerError("Error exporting application from JSON file.", e);
}
return config;
}

/**
Expand Down Expand Up @@ -758,74 +730,42 @@ private ServiceProvider parseSP(SpFileContent spFileContent, String fileType, St
spFileContent.getFileName(), tenantDomain));
}

if (containsValidMediaType(fileType, VALID_MEDIA_TYPES_XML)) {
return parseServiceProviderFromXml(spFileContent, tenantDomain);
} else if (containsValidMediaType(fileType, VALID_MEDIA_TYPES_YAML)) {
return parseServiceProviderFromYaml(spFileContent, tenantDomain);
} else if (containsValidMediaType(fileType, VALID_MEDIA_TYPES_JSON)) {
return parseServiceProviderFromJson(spFileContent, tenantDomain);
} else {
log.warn("Unsupported file type " + fileType + " for file " + spFileContent.getFileName() + " . " +
"Defaulting to XML parsing");
return parseServiceProviderFromXml(spFileContent, tenantDomain);
}
}

private boolean containsValidMediaType(String fileType, String[] mediaTypes) {

for (String mediaType : mediaTypes) {
if (fileType.contains(mediaType)) {
return true;
}
}
return false;
}

private ServiceProvider parseServiceProviderFromXml(SpFileContent spFileContent, String tenantDomain)
throws IdentityApplicationManagementException {

try {
JAXBContext jaxbContext = JAXBContext.newInstance(INBOUND_CONFIG_PROTOCOLS);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
return (ServiceProvider) unmarshaller.unmarshal(new StringReader(spFileContent.getContent()));
} catch (JAXBException e) {
throw new IdentityApplicationManagementException(String.format("Error in reading XML Service Provider " +
FileContent fileContent =
new FileContent(
spFileContent.getFileName(),
fileType,
spFileContent.getContent()
);

return FileSerializationUtil.deserialize(
fileContent,
ServiceProvider.class,
buildDeserializationConfig()
);
} catch (FileSerializationException e) {
throw new IdentityApplicationManagementException(String.format("Error in reading Service Provider " +
"configuration file %s uploaded by tenant: %s", spFileContent.getFileName(), tenantDomain), e);
}
}

private ServiceProvider parseServiceProviderFromYaml(SpFileContent spFileContent, String tenantDomain)
throws IdentityApplicationManagementException {
private FileSerializationConfig buildDeserializationConfig() {

try {
// Add trusted tags included in the SP YAML file.
List<String> trustedTagList = new ArrayList<>();
trustedTagList.add(ServiceProvider.class.getName());
trustedTagList.add(OAuthAppDO.class.getName());
trustedTagList.add(SAMLSSOServiceProviderDTO.class.getName());

LoaderOptions loaderOptions = new LoaderOptions();
TagInspector tagInspector = new TrustedPrefixesTagInspector(trustedTagList);
loaderOptions.setTagInspector(tagInspector);
Yaml yaml = new Yaml(new Constructor(ServiceProvider.class, loaderOptions));
return yaml.loadAs(spFileContent.getContent(), ServiceProvider.class);
} catch (YAMLException e) {
throw new IdentityApplicationManagementException(String.format("Error in reading YAML Service Provider " +
"configuration file %s uploaded by tenant: %s", spFileContent.getFileName(), tenantDomain), e);
}
}
FileSerializationConfig config = new FileSerializationConfig();

private ServiceProvider parseServiceProviderFromJson(SpFileContent spFileContent, String tenantDomain)
throws IdentityApplicationManagementException {
XmlConfig xmlConfig = new XmlConfig();
xmlConfig.setAdditionalJaxbClasses(ADDITIONAL_INBOUND_CONFIG_PROTOCOLS);
config.setXmlConfig(xmlConfig);

try {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerSubtypes(INBOUND_CONFIG_PROTOCOLS);
return objectMapper.readValue(spFileContent.getContent(), ServiceProvider.class);
} catch (JsonProcessingException e) {
throw new IdentityApplicationManagementException(String.format("Error in reading JSON Service Provider " +
"configuration file %s uploaded by tenant: %s", spFileContent.getFileName(), tenantDomain), e);
}
YamlConfig yamlConfig = new YamlConfig();
yamlConfig.setAdditionalTrustedClasses(OAuthAppDO.class, SAMLSSOServiceProviderDTO.class);
config.setYamlConfig(yamlConfig);

JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setSubtypes(INBOUND_CONFIG_PROTOCOLS);
config.setJsonConfig(jsonConfig);

return config;
}

private SpFileContent buildSpFileContent(InputStream fileInputStream, Attachment fileDetail) throws IOException {
Expand Down
Loading