org.wso2.carbon.ndatasource.core.utils.DataSourceUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.ndatasource.core.utils.DataSourceUtils.java

Source

/**
 *  Copyright (c) 2012, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.wso2.carbon.ndatasource.core.utils;

import org.apache.axiom.om.OMElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.core.util.CryptoException;
import org.wso2.carbon.core.util.CryptoUtil;
import org.wso2.carbon.ndatasource.common.DataSourceConstants;
import org.wso2.carbon.ndatasource.common.DataSourceException;
import org.wso2.carbon.ndatasource.core.DataSourceMetaInfo;
import org.wso2.carbon.ndatasource.core.internal.DataSourceServiceComponent;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.securevault.SecretResolver;
import org.wso2.securevault.SecretResolverFactory;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;

/**
 * Data Sources utility class.
 */
public class DataSourceUtils {

    private static Log log = LogFactory.getLog(DataSourceUtils.class);

    private static SecretResolver secretResolver;
    private static final String XML_DECLARATION = "xml-declaration";

    private static ThreadLocal<String> dataSourceId = new ThreadLocal<String>() {
        protected synchronized String initialValue() {
            return null;
        }
    };

    public static void setCurrentDataSourceId(String dsId) {
        dataSourceId.set(dsId);
    }

    public static String getCurrentDataSourceId() {
        return dataSourceId.get();
    }

    public static Registry getConfRegistryForTenant(int tenantId) throws DataSourceException {
        try {
            /* be super tenant to retrieve the registry of a given tenant id */
            PrivilegedCarbonContext.startTenantFlow();
            PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(MultitenantConstants.SUPER_TENANT_ID);
            PrivilegedCarbonContext.getThreadLocalCarbonContext()
                    .setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
            return DataSourceServiceComponent.getRegistryService().getConfigSystemRegistry(tenantId);
        } catch (RegistryException e) {
            throw new DataSourceException("Error in retrieving conf registry instance: " + e.getMessage(), e);
        } finally {
            /* go out of being super tenant */
            PrivilegedCarbonContext.endTenantFlow();
        }
    }

    public static Registry getGovRegistryForTenant(int tenantId) throws DataSourceException {
        try {
            /* be super tenant to retrieve the registry of a given tenant id */
            PrivilegedCarbonContext.startTenantFlow();
            PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(MultitenantConstants.SUPER_TENANT_ID);
            return DataSourceServiceComponent.getRegistryService().getGovernanceSystemRegistry(tenantId);
        } catch (RegistryException e) {
            throw new DataSourceException("Error in retrieving gov registry instance: " + e.getMessage(), e);
        } finally {
            /* go out of being super tenant */
            PrivilegedCarbonContext.endTenantFlow();
        }
    }

    public static boolean nullAllowEquals(Object lhs, Object rhs) {
        if (lhs == null && rhs == null) {
            return true;
        }
        if ((lhs == null && rhs != null) || (lhs != null && rhs == null)) {
            return false;
        }
        return lhs.equals(rhs);
    }

    public static String elementToString(Element element) {
        try {
            if (element == null) {
                /* return an empty string because, the other way around works the same,
                where if we give a empty string as the XML, we get a null element
                from "stringToElement" */
                return "";
            }
            Document document = element.getOwnerDocument();
            DOMImplementationLS domImplLS = (DOMImplementationLS) document.getImplementation();
            LSSerializer serializer = domImplLS.createLSSerializer();
            //by default its true, so set it to false to get String without xml-declaration
            serializer.getDomConfig().setParameter(XML_DECLARATION, false);
            return serializer.writeToString(element);
        } catch (Exception e) {
            log.error("Error while convering element to string: " + e.getMessage(), e);
            return null;
        }
    }

    public static Element stringToElement(String xml) {
        if (xml == null || xml.trim().length() == 0) {
            return null;
        }
        try {
            DocumentBuilder db = getSecuredDocumentBuilder(false);
            return db.parse(new ByteArrayInputStream(xml.getBytes())).getDocumentElement();
        } catch (Exception e) {
            log.error("Error while converting string to element: " + e.getMessage(), e);
            return null;
        }
    }

    private static synchronized String loadFromSecureVault(String alias) {
        if (secretResolver == null) {
            secretResolver = SecretResolverFactory.create((OMElement) null, false);
            secretResolver
                    .init(DataSourceServiceComponent.getSecretCallbackHandlerService().getSecretCallbackHandler());
        }
        return secretResolver.resolve(alias);
    }

    private static void secureLoadElement(Element element, boolean checkSecureVault) throws CryptoException {
        if (checkSecureVault) {
            Attr secureAttr = element.getAttributeNodeNS(DataSourceConstants.SECURE_VAULT_NS,
                    DataSourceConstants.SECRET_ALIAS_ATTR_NAME);
            if (secureAttr != null) {
                element.setTextContent(loadFromSecureVault(secureAttr.getValue()));
                element.removeAttributeNode(secureAttr);
            }
        } else {
            String encryptedStr = element.getAttribute(DataSourceConstants.ENCRYPTED_ATTR_NAME);
            if (encryptedStr != null) {
                boolean encrypted = Boolean.parseBoolean(encryptedStr);
                if (encrypted) {
                    element.setTextContent(new String(CryptoUtil
                            .getDefaultCryptoUtil(DataSourceServiceComponent.getServerConfigurationService(),
                                    DataSourceServiceComponent.getRegistryService())
                            .base64DecodeAndDecrypt(element.getTextContent())));
                }
            }
        }
        NodeList childNodes = element.getChildNodes();
        int count = childNodes.getLength();
        Node tmpNode;
        for (int i = 0; i < count; i++) {
            tmpNode = childNodes.item(i);
            if (tmpNode instanceof Element) {
                secureLoadElement((Element) tmpNode, checkSecureVault);
            }
        }
    }

    public static void secureSaveElement(Element element) throws CryptoException {
        String encryptedStr = element.getAttribute(DataSourceConstants.ENCRYPTED_ATTR_NAME);
        if (encryptedStr != null) {
            boolean encrypted = Boolean.parseBoolean(encryptedStr);
            if (encrypted) {
                element.setTextContent(CryptoUtil
                        .getDefaultCryptoUtil(DataSourceServiceComponent.getServerConfigurationService(),
                                DataSourceServiceComponent.getRegistryService())
                        .encryptAndBase64Encode(element.getTextContent().getBytes()));
            }
        }
        NodeList childNodes = element.getChildNodes();
        int count = childNodes.getLength();
        Node tmpNode;
        for (int i = 0; i < count; i++) {
            tmpNode = childNodes.item(i);
            if (tmpNode instanceof Element) {
                secureSaveElement((Element) tmpNode);
            }
        }
    }

    public static void secureResolveDocument(Document doc, boolean checkSecureVault) throws DataSourceException {
        Element element = doc.getDocumentElement();
        if (element != null) {
            try {
                secureLoadElement(element, checkSecureVault);
            } catch (CryptoException e) {
                throw new DataSourceException("Error in secure load of data source meta info: " + e.getMessage(),
                        e);
            }
        }
    }

    public static Document convertToDocument(File file) throws DataSourceException {
        try {
            return getSecuredDocumentBuilder(false).parse(file);
        } catch (Exception e) {
            throw new DataSourceException("Error in creating an XML document from file: " + e.getMessage(), e);
        }
    }

    public static Document convertToDocument(InputStream in) throws DataSourceException {
        try {
            return getSecuredDocumentBuilder(false).parse(in);
        } catch (Exception e) {
            throw new DataSourceException("Error in creating an XML document from stream: " + e.getMessage(), e);
        }
    }

    public static InputStream elementToInputStream(Element element) {
        try {
            if (element == null) {
                return null;
            }
            String xmlString = elementToString(element);
            InputStream stream = new ByteArrayInputStream(xmlString.getBytes());
            return stream;
        } catch (Exception e) {
            log.error("Error while convering element to InputStream: " + e.getMessage(), e);
            return null;
        }
    }

    public static Element convertDataSourceMetaInfoToElement(DataSourceMetaInfo dsmInfo, Marshaller dsmMarshaller)
            throws DataSourceException {
        Element element;
        try {
            Document document = getSecuredDocumentBuilder(false).newDocument();
            dsmMarshaller.marshal(dsmInfo, document);
            element = document.getDocumentElement();
        } catch (Exception e) {
            throw new DataSourceException("Error in creating an XML document from stream: " + e.getMessage(), e);
        }
        return element;
    }

    /**
     * This method provides a secured document builder which will secure XXE attacks.
     *
     * @param setIgnoreComments whether to set setIgnoringComments in DocumentBuilderFactory.
     * @return DocumentBuilder
     * @throws ParserConfigurationException
     */
    private static DocumentBuilder getSecuredDocumentBuilder(boolean setIgnoreComments)
            throws ParserConfigurationException {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setIgnoringComments(setIgnoreComments);
        documentBuilderFactory.setNamespaceAware(true);
        documentBuilderFactory.setExpandEntityReferences(false);
        documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        documentBuilder.setEntityResolver(new EntityResolver() {
            @Override
            public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
                throw new SAXException("Possible XML External Entity (XXE) attack. Skip resolving entity");
            }
        });
        return documentBuilder;
    }
}