Activator.java 14.3 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  javax.jcr.Binary
 *  javax.jcr.Node
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.ValueFactory
 *  org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils
 *  org.apache.sling.jcr.api.SlingRepository
 *  org.osgi.framework.Bundle
 *  org.osgi.framework.BundleActivator
 *  org.osgi.framework.BundleContext
 *  org.osgi.framework.ServiceEvent
 *  org.osgi.framework.ServiceFactory
 *  org.osgi.framework.ServiceListener
 *  org.osgi.framework.ServiceReference
 *  org.osgi.framework.ServiceRegistration
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.granite.crypto.internal;

import com.adobe.granite.crypto.CryptoSupport;
import com.adobe.granite.crypto.internal.CryptoSupportImpl;
import com.adobe.granite.crypto.internal.InternalClassLoaderWrapper;
import com.adobe.granite.crypto.internal.SecureDataWebConsolePlugin;
import com.adobe.granite.keystore.internal.GraniteSecurityProvider;
import com.adobe.granite.keystore.internal.KeyStoreServiceImpl;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.security.Security;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.concurrent.atomic.AtomicInteger;
import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.ValueFactory;
import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Activator
implements BundleActivator {
    static final String WEB_CONSOLE_LABEL = "crypto";
    private static final String JSAFE_CRYPTO_SUPPORT = "com.adobe.granite.crypto.internal.jsafe.JSafeCryptoSupport";
    private static final String REPO_SERVICE = "org.apache.sling.jcr.api.SlingRepository";
    private static final String GRANITE_KEYSTORE_ENABLED = "granite.keystore.enabled";
    private static final String keyPathParent = "/etc";
    private static final String keyPath = "/etc/key";
    private static final String keyProperty = "master";
    private static final String hmac_keyProperty = "hmac";
    private static final String keyPropertyPath = "/etc/key/master";
    private static final String hmac_keyPropertyPath = "/etc/key/hmac";
    private final Logger log;
    private BundleContext bundleContext;
    private CryptoSupportImpl cryptoSupportImpl;
    private KeyStoreServiceImpl keyStoreServiceImpl;
    private ServiceRegistration configurationPlugin;
    private ServiceRegistration webConsolePlugin;
    private ServiceRegistration cryptoSupportService;
    private ServiceRegistration keyStoreService;
    private ClassLoader classLoader;
    private boolean enableKeyStoreService;

    public Activator() {
        this.log = LoggerFactory.getLogger(this.getClass());
    }

    public void start(BundleContext context) throws Exception {
        this.bundleContext = context;
        this.log.info("Starting Crypto Support ({}, {})", new Object[]{context.getBundle().getSymbolicName(), context.getBundle().getHeaders().get("Bundle-Version")});
        String graniteKeyStoreEnabled = this.bundleContext.getProperty("granite.keystore.enabled");
        this.enableKeyStoreService = !"false".equalsIgnoreCase(graniteKeyStoreEnabled);
        InternalClassLoaderWrapper.init(this.bundleContext);
        this.classLoader = InternalClassLoaderWrapper.getInstance().getClassLoader();
        this.registerGraniteSecurityProvider();
        System.setProperty("com.rsa.crypto.default.random", "FIPS186PRNG");
        System.setProperty("com.rsa.cryptoj.jce.kat.strategy", "on.demand");
        ServiceListener listener = new ServiceListener(){
            private final AtomicInteger repositoryCounter;

            public void serviceChanged(ServiceEvent event) {
                if (event.getType() == 1 && this.repositoryCounter.getAndIncrement() == 0) {
                    Activator.this.startCryptoSupport(event.getServiceReference());
                } else if (event.getType() == 4) {
                    this.repositoryCounter.decrementAndGet();
                }
            }
        };
        this.bundleContext.addServiceListener(listener, "(objectClass=org.apache.sling.jcr.api.SlingRepository)");
        ServiceReference repoService = this.bundleContext.getServiceReference("org.apache.sling.jcr.api.SlingRepository");
        if (repoService != null) {
            listener.serviceChanged(new ServiceEvent(1, repoService));
        }
    }

    public void stop(BundleContext context) throws Exception {
        if (this.configurationPlugin != null) {
            this.configurationPlugin.unregister();
            this.configurationPlugin = null;
        }
        this.stopCryptoSupport();
        this.bundleContext = null;
        this.unregisterGraniteSecurityProvider();
        System.clearProperty("com.rsa.crypto.default.random");
        System.clearProperty("com.rsa.cryptoj.jce.kat.strategy");
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    void startCryptoSupport(ServiceReference repositoryRef) {
        SlingRepository repository = (SlingRepository)this.bundleContext.getService(repositoryRef);
        if (repository != null) {
            try {
                CryptoSupportImpl cryptoSupportImpl = this.getOrCreateCryptoSupport();
                this.loadOrCreateKey(repository, cryptoSupportImpl);
                if (this.cryptoSupportService == null) {
                    this.cryptoSupportService = this.bundleContext.registerService("com.adobe.granite.crypto.CryptoSupport", (Object)this.cryptoSupportImpl, null);
                }
                if (this.enableKeyStoreService) {
                    this.moveTrustStoreIfNeeded(repository);
                    this.keyStoreServiceImpl = this.getOrCreateKeyStoreService(cryptoSupportImpl);
                    if (this.keyStoreService == null) {
                        this.keyStoreService = this.bundleContext.registerService("com.adobe.granite.keystore.KeyStoreService", (Object)this.keyStoreServiceImpl, null);
                    }
                }
                if (this.webConsolePlugin == null) {
                    SecureDataWebConsolePluginFactory consoleFactory = new SecureDataWebConsolePluginFactory();
                    Hashtable<String, String> consoleProps = new Hashtable<String, String>();
                    consoleProps.put("felix.webconsole.label", "crypto");
                    this.webConsolePlugin = this.bundleContext.registerService("javax.servlet.Servlet", (Object)consoleFactory, consoleProps);
                }
            }
            catch (Exception e) {
                this.log.error("setupCryptoSupport: Failed creating CryptoSupport Implementation: ", (Throwable)e);
            }
            finally {
                this.bundleContext.ungetService(repositoryRef);
            }
        }
    }

    private void stopCryptoSupport() {
        if (this.webConsolePlugin != null) {
            this.webConsolePlugin.unregister();
            this.webConsolePlugin = null;
        }
        if (this.cryptoSupportImpl != null) {
            this.cryptoSupportImpl.dispose();
            this.cryptoSupportImpl = null;
        }
        if (this.cryptoSupportService != null) {
            this.cryptoSupportService.unregister();
            this.cryptoSupportService = null;
        }
        if (this.keyStoreService != null) {
            this.keyStoreService.unregister();
            this.keyStoreService = null;
        }
        this.unregisterGraniteSecurityProvider();
    }

    private CryptoSupportImpl getOrCreateCryptoSupport() throws Exception {
        if (this.cryptoSupportImpl == null) {
            Class cryptoImplClass = this.classLoader.loadClass("com.adobe.granite.crypto.internal.jsafe.JSafeCryptoSupport");
            Constructor cryptoImplConstructor = cryptoImplClass.getDeclaredConstructor(null);
            this.cryptoSupportImpl = (CryptoSupportImpl)cryptoImplConstructor.newInstance(null);
        }
        return this.cryptoSupportImpl;
    }

    private KeyStoreServiceImpl getOrCreateKeyStoreService(CryptoSupportImpl cryptoSupportImpl) throws Exception {
        KeyStoreServiceImpl keyStoreServiceImpl = this.keyStoreServiceImpl == null ? new KeyStoreServiceImpl(cryptoSupportImpl) : this.keyStoreServiceImpl;
        return keyStoreServiceImpl;
    }

    private void registerGraniteSecurityProvider() throws Exception {
        this.unregisterGraniteSecurityProvider();
        if (this.enableKeyStoreService) {
            Security.addProvider(GraniteSecurityProvider.getInstance());
        }
    }

    private void unregisterGraniteSecurityProvider() {
        Security.removeProvider("AdobeGraniteSecurityProvider");
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void loadOrCreateKey(SlingRepository repository, CryptoSupportImpl cryptoSupport) throws Exception {
        block7 : {
            Session session = null;
            try {
                session = repository.loginService(null, null);
                byte[] key = this.readKey(session, "/etc/key/master");
                if (key == null) {
                    key = cryptoSupport.init();
                    this.writeKey(session, key, "master");
                } else {
                    cryptoSupport.init(key);
                }
                byte[] hmac_key = this.readKey(session, "/etc/key/hmac");
                if (hmac_key == null) {
                    hmac_key = cryptoSupport.init_hmac();
                    this.writeKey(session, hmac_key, "hmac");
                    break block7;
                }
                cryptoSupport.init_hmac(hmac_key);
            }
            finally {
                if (session != null) {
                    session.logout();
                }
            }
        }
    }

    private static Node getOrCreateKeyNode(Session session) throws RepositoryException {
        if (session.nodeExists("/etc/key")) {
            return session.getNode("/etc/key");
        }
        if (!session.nodeExists("/etc")) {
            session.getRootNode().addNode("/etc".substring(1), "sling:Folder");
        }
        Node keyNode = session.getRootNode().addNode("/etc/key".substring(1), "sling:Folder");
        keyNode.setProperty("hidden", true);
        return keyNode;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private byte[] readKey(Session session, String propertyPath) throws Exception {
        if (session.propertyExists(propertyPath)) {
            Binary keyBinary = session.getProperty(propertyPath).getBinary();
            try {
                long size = keyBinary.getSize();
                if (size < Integer.MAX_VALUE) {
                    byte[] bytes = new byte[(int)size];
                    keyBinary.read(bytes, 0);
                    byte[] arrby = bytes;
                    return arrby;
                }
                this.log.error("loadOrCreateKey: Cannot handle key property larger than Integer.MAX_SIZE bytes!");
            }
            finally {
                keyBinary.dispose();
            }
        }
        return null;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void writeKey(Session session, byte[] key, String property) throws Exception {
        Node keyNode = Activator.getOrCreateKeyNode(session);
        ByteArrayInputStream bin = new ByteArrayInputStream(key);
        Binary keyBinary = keyNode.getSession().getValueFactory().createBinary((InputStream)bin);
        try {
            keyNode.setProperty(property, keyBinary);
        }
        finally {
            keyBinary.dispose();
        }
        this.limitKeyAccess(session);
        session.save();
    }

    private void limitKeyAccess(Session session) throws RepositoryException {
        AccessControlUtils.denyAllToEveryone((Session)session, (String)"/etc/key");
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void moveTrustStoreIfNeeded(SlingRepository repository) throws Exception {
        String[] oldLocations = new String[]{"/etc/key/truststore.p12", "/etc/security/truststore.p12"};
        Session session = null;
        try {
            session = repository.loginService(null, null);
            for (String oldLocation : oldLocations) {
                if (!session.nodeExists(oldLocation)) continue;
                this.log.info("Detected truststore at {}", (Object)oldLocation);
                if (!session.nodeExists("/etc/truststore")) {
                    session.getNode("/etc").addNode("truststore", "sling:Folder");
                }
                session.move(oldLocation, "/etc/truststore/truststore.p12");
                this.log.info("Moved truststore to {}", (Object)"/etc/truststore/truststore.p12");
                String oldPath = oldLocation.substring(0, oldLocation.lastIndexOf(47));
                if (session.getNode(oldPath).hasProperty("keystorePassword")) {
                    Property oldPassword = session.getNode(oldPath).getProperty("keystorePassword");
                    session.getNode("/etc/truststore").setProperty("keystorePassword", oldPassword.getString());
                    oldPassword.remove();
                }
                KeyStoreServiceImpl.protectTrustStore(session);
                this.limitKeyAccess(session);
            }
            session.save();
        }
        finally {
            if (session != null) {
                session.logout();
            }
        }
    }

    public class SecureDataWebConsolePluginFactory
    implements ServiceFactory {
        public Object getService(Bundle bundle, ServiceRegistration registration) {
            return new SecureDataWebConsolePlugin(Activator.this.cryptoSupportImpl);
        }

        public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
        }
    }

}