com.atlassian.jira.security.auth.trustedapps.TestDefaultCurrentApplicationStore.java Source code

Java tutorial

Introduction

Here is the source code for com.atlassian.jira.security.auth.trustedapps.TestDefaultCurrentApplicationStore.java

Source

package com.atlassian.jira.security.auth.trustedapps;

import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;

import javax.annotation.Nullable;

import com.atlassian.beehive.simple.SimpleClusterLockService;
import com.atlassian.cache.memory.MemoryCacheManager;
import com.atlassian.jira.bc.license.JiraLicenseService;
import com.atlassian.jira.config.properties.ApplicationProperties;
import com.atlassian.security.auth.trustedapps.CurrentApplication;
import com.atlassian.security.auth.trustedapps.EncryptedCertificate;

import com.google.common.collect.Maps;
import com.google.common.util.concurrent.UncheckedExecutionException;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

public class TestDefaultCurrentApplicationStore {
    public static final String PRIVATE_KEY_VALUE = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCimjWtUnZ+ABlXM5QooZOcn/Qw4ZyZqMOeaq/GHEDcqiEThCWjEgkdoleRFDC/x+nst4weK4SBzVeYTnadRh5CbDNDTMjoutkjd39NefLH+b8vA4STU7F43C7sUPxe+proi2lYxRdsvGCE56VYfIEfYH9U0dvE1iEUi91MtMBtEBbhxKmoyG9NkFEcDBJmLYwRozYIuLS81xd1mEfVnyUNhbOfcLm+pG+vktCdlQZDcPBb7H7raFZCSjma8JvY3aby+iZu7A4Al0hlFVxLV/Qk+ac3XwQ8pZo79ua+D9K4e5ea22D4yELz9Tt2QxistjLsmaop1HEj5jqVMP0iNL/RAgMBAAECggEBAJ7z5Tkz/cWazyrhrxoxKZ3Y99u5EV9dDS4V2RLvl7CfV4o+ipRpEyQ3CSc395fjFBhmLcFohTZmyBSJz4Zbf0UrhMlrjJOF5LK5JGdWqTE4Qd7xr25eSIV/qRc27B7lGP3vGuK+ePHBDRGfaZGg1JEZwh/mrtIzCU+Okp1jrSBvJG/f/B3i3/4eotJkxJMQcfcET7kmcIuf2+kk9tSOQ4/S3z6zfcW2SX+S7wodXHYFno/s8jra2iA9oSR10zpo3z17kqkjFthy3DigC8kPUL+IFJ47eMhr77Sr4y7vSQgXhIzHTa/NDkRQv/FXFu8DuL8maNAwA4+MtCDrCDh9CckCgYEA2LQ4qxKNXcoS+Mx6Hhj+q/IMKOTJn4HEKmLsDb1oNAKlj7lv0jAq+kPVFPvH6zqqAsDK/dnIkQJKP3pWE86Sz95W7o2L6S70gIeEJjAPKOUNrvALwC2tAN+ecoL28MfYcRd1Ou4776m3t+74fDnoQwITUqagD88irjQxs/kJ82cCgYEAwBZ/NzeKWN45vSmmoAdxZQ96QQp+2Q+AUbFzE/W3wqBBeb9kdLnkuB7h9xIPUKU9SKRU053Tws7isp3i9kL4MNe2kNVz7nX2rO9xmCUiQB4nPHJyzBpEwISV7V3cBoVQVEwAMBkxrrv1fbO+15hUxF+floRkXyi6bE0uVjKBKAcCgYEAs+5wXxs4ZfezaQHfI759NyfzEMFm6BpHVypr9byfGRBZh8zhHBUCmmpYMuQcSySapU6PPdfmwQC1xZ8+eZO8MvzaEZlV4ngqa84Z29truvj1M5v9JcTHMUJ7vXkgsSw+eyiPHi9RdN3mvcKecAdk4r6GbMoNfRLwKNUNr/HIYWECgYEAgQ9cgDwH7ze4cZlHg+QcUzt397VWjv60R69DU5jX06Oa+nMWyrqPqwnM5xUyRwwOxfzrpZc4TX51oG8mrDFI0oBNALj6ALEvgPgMSZ5BifT4hcubx/iqUvOCTI6wo4z08P5zbd2vnOhaxA993RtTcPGSpy3ixnD1+IhO5sleMAcCgYADp0xdt8bS5uTtKU47h3DJx8ry1c71g2CLEevuTEyyynOLj6EZ+Hiluk97kGpHvaihZEtEPTtwbdx2fcY4MLmgOMrRzZKwZ5xJHxiSg0XeI5ZMDZaeSYMbRo+53JQ90LSGJM0o3pYLIilqiCKMxD1yFvqD5pUFUIuSDaSGRkID2A==";
    public static final String PUBLIC_KEY_VALUE = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCySptbugHAzWUJY3ALWhuSCPhVXnwbUBfsRExYQitBCVny4V1DcU2SAx22bH9dSM0X7NdMObF74r+Wd77QoPAtaySqFLqCeRCbFmhHgVSi+pGeCipTpueefSkz2AX8Aj+9x27tqjBsX1LtNWVLDsinEhBWN68R+iEOmf/6jGWObQIDAQAB";
    public static final KeyPair PAIR = getKeys(PUBLIC_KEY_VALUE, PRIVATE_KEY_VALUE);

    public static final String PRIVATE_KEY_VALUE2 = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCahHmjFeIVy8g80hODVwMeBazdzwscMQVZMQkY/nOkkR1yXr5q3ijeVc9G+fJTSW357ZlHThaajHlaCsB8mGvH3bVnmLjlEAQXPDYFJ7rAcALazPwrmOOeF8jyHhnra3E84My4lzrQKyX7tUOlrMPGuFUiqPaqwZ7R8bKCFBHzDCCjbpIkBCet9adTKb9bMTY+pX/VwEWCkDUUK6+Pilna+CfR7Eyu49ki3cvwpcJpzz2NNVUkdE+WH2jq/0DaltX4KozsxBQ5e0F4JJFow0mToEn7gVpy5jJ6lzpC8HDs7+sEvhsSg5xRrcqoXXBGnOaSFqnN0VA5l5VGFOZ82Vx3AgMBAAECggEAAiQLu2K2Oy8TmyQd+Rffhy708i3ILZ/QPygaxCniWElaaxc89CYX0tzFfmpAHT9LMsdD9GT0kzeXBtRXTmKeO6qqtMC87w+Fvvyqku+1+qySnY1xgPkhTjNuKUyZd1WJwBotO/F8cx3l7NLaGRWHsN0k8NH+eOct2CLNIlg8120yBPVD8qkBLB9aIbWFO6qKVppxmtElBcz64Cp9k0QwFeojY804Bk85PlZXtatc9rftx8rAH0mbR+HYrCjZeSCXbtXLiPpsGsb2zRX3sYfcxzTZ8ah4dYGJ4YETbTfniAc4e1nZxzDK3ZqHYfM6fwo+Nn3cjgX1m+vRpK4CxIMzAQKBgQDlzMqAVx1zfsUQbfIcYaHz/inJel+PFjnV1YfAjqLSdIruKY3zby92FQPxGMe+IzqtDxMndE+v8R1W5CXj79Bd9P1R2t+M/tyNKxoTQeBIpNDdHoHZHYzNRg4BXyqDgOC5MZg2iE5cUAkpvgB8iANiCVAxmZlG3I21ffZXv33iYQKBgQCsImbqWZoQV6QczIE9JHpk48l3+Z2oD0wIFaf0JZ+JEBcl8F+GffFpYWviu+9RgPjLNu90KXP4UTyOpE4wYJt0ynFa/itFeyoZyOCL047mIRmIWX944cFSTaQGnys2vry5jtM/mCThujOTP1YPTHz4fFlYqMvgO+5d8xJO38Nd1wKBgDRMVi29Jbu6NxkVHIuvAI+p4VK0IflLgqASt5FwJMgms9Od62tie3exMrN1A0hXdiwaiS5qfxQ4mIfE5oaodlBbyCcP296XxhPuokGNtYBy2gHoxn5mBjxVXCydvuwssXgUPGL0xHin0l4Ims28mqB+JB0VqteArFOItj6kGv8hAoGBAI47Pt6Vev/V6v0A3ikvYxLKRUalMugS+7gSbN0H2XLfoMDwhX4Tws5YeVS4BV9LOkhv9Bv/xJuCRI94pELFEK7IODH/orGeu4LiwOfIv2LYJsjLatDveVYQYWA3VPW/VSHeKh96D7+Uo9kflHS/tuN7nDfuAcgevS9UEeSqcDuxAoGALtpKwGf/9lNYpop/xDKgI19ZJi4oLtCUK1OPke6Wnv9+ZclNhsoxfxXDD/8C8q5D78oxSEEpr06A6sqsFxjzfdf0mSpo6qjmYnMITtill5TVzqkUPtOZBmxN/jj8nciho2+ghXtebNv11ERDTH9YuA5rmx1nqTse2NonoCzLoR4=";
    public static final String PUBLIC_KEY_VALUE2 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmoR5oxXiFcvIPNITg1cDHgWs3c8LHDEFWTEJGP5zpJEdcl6+at4o3lXPRvnyU0lt+e2ZR04Wmox5WgrAfJhrx921Z5i45RAEFzw2BSe6wHAC2sz8K5jjnhfI8h4Z62txPODMuJc60Csl+7VDpazDxrhVIqj2qsGe0fGyghQR8wwgo26SJAQnrfWnUym/WzE2PqV/1cBFgpA1FCuvj4pZ2vgn0exMruPZIt3L8KXCac89jTVVJHRPlh9o6v9A2pbV+CqM7MQUOXtBeCSRaMNJk6BJ+4FacuYyepc6QvBw7O/rBL4bEoOcUa3KqF1wRpzmkhapzdFQOZeVRhTmfNlcdwIDAQAB";
    public static final KeyPair PAIR2 = getKeys(PUBLIC_KEY_VALUE2, PRIVATE_KEY_VALUE2);

    public static final String TEST_UID = "jira.uid";

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testCreatesPropertiesIfNotThere() throws Exception {
        TrustedApplicationProperties properties = new TrustedApplicationProperties();

        DefaultCurrentApplicationStore factory = new DefaultCurrentApplicationStore(properties,
                stubServerId("THIS.ISNT.AREA.LSID"), new MemoryCacheManager(), new SimpleClusterLockService());

        factory.start();
        final CurrentApplication currentApplication = factory.getCurrentApplication();
        assertNotNull(currentApplication);

        KeyPair newPair = properties.getPair();
        assertNotNull(newPair.getPrivate());
        assertNotNull(newPair.getPublic());
        assertTrue(isNotBlank(properties.getApplicationId()));

        assertState(newPair, properties.getApplicationId(), factory);
    }

    private JiraLicenseService stubServerId(@Nullable final String serverId) {
        JiraLicenseService service = Mockito.mock(JiraLicenseService.class);
        Mockito.stub(service.getServerId()).toReturn(serverId);
        return service;
    }

    @Test
    public void testUsesExistingDodgyProperties() throws Exception {
        TrustedApplicationProperties applicationProperties = new TrustedApplicationProperties(TEST_UID,
                "CRAPPYNOTENCODEDKEYDATA", "CRAPPYNOTENCODEDKEYDATA");

        DefaultCurrentApplicationStore manager = new DefaultCurrentApplicationStore(
                new ReadOnlyApplicationProperties(applicationProperties), stubServerId("THIS.ISNT.AREA.LSID"),
                new MemoryCacheManager(), new SimpleClusterLockService());

        manager.start();
        final CurrentApplication currentApplication = manager.getCurrentApplication();
        assertNotNull(currentApplication);
        assertEquals(TEST_UID, currentApplication.getID());

        final PublicKey key = currentApplication.getPublicKey();
        assertNotNull(key);
        assertTrue(key instanceof KeyFactory.InvalidPublicKey);

        assertTrue(manager.getKeyPair().getPublic() instanceof KeyFactory.InvalidPublicKey);
        assertTrue(manager.getKeyPair().getPrivate() instanceof KeyFactory.InvalidPrivateKey);

        try {
            currentApplication.encode("this little sentence", null);
            fail("RuntimeException expected");
        } catch (UncheckedExecutionException yay) {
            // expected
        }
    }

    @Test
    public void testUsesExistingGoodProperties() throws Exception {
        TrustedApplicationProperties trustedApplicationProperties = new TrustedApplicationProperties(TEST_UID,
                PAIR);
        DefaultCurrentApplicationStore factory = new DefaultCurrentApplicationStore(
                new ReadOnlyApplicationProperties(trustedApplicationProperties),
                stubServerId("THIS.ISNT.AREA.LSID"), new MemoryCacheManager(), new SimpleClusterLockService());
        factory.start();
        assertState(PAIR, TEST_UID, factory);
    }

    @Test
    public void testUsesExistingPropertiesNoServerIdOrUid() throws Exception {
        TrustedApplicationProperties trustedApplicationProperties = new TrustedApplicationProperties(TEST_UID,
                PAIR);
        DefaultCurrentApplicationStore factory = new DefaultCurrentApplicationStore(trustedApplicationProperties,
                stubServerId(null), new MemoryCacheManager(), new SimpleClusterLockService());

        factory.start();
        //need to init the cache.
        factory.getCurrentApplication();

        assertTrue(isNotBlank(trustedApplicationProperties.getApplicationId()));
        assertState(PAIR, trustedApplicationProperties.getApplicationId(), factory);
    }

    @Test
    public void testSetCurrentApplication() throws Exception {
        String ORIG_ID = "orig";
        String NEW_ID = "new";

        TrustedApplicationProperties properties = new TrustedApplicationProperties(ORIG_ID, PAIR);
        DefaultCurrentApplicationStore store = new DefaultCurrentApplicationStore(properties, stubServerId("ABC"),
                new MemoryCacheManager(), new SimpleClusterLockService());

        store.start();
        assertState(PAIR, ORIG_ID, store);

        store.setCurrentApplication(NEW_ID, PAIR2);

        assertEquals(PAIR2.getPrivate(), properties.getPrivateKey());
        assertEquals(PAIR2.getPublic(), properties.getPublicKey());
        assertEquals(NEW_ID, properties.getApplicationId());

        assertState(PAIR2, NEW_ID, store);
    }

    @Test
    public void testSetCurrentApplicationString() throws Exception {
        String ORIG_ID = "orig";
        String NEW_ID = "new";

        TrustedApplicationProperties properties = new TrustedApplicationProperties(ORIG_ID, PAIR);
        DefaultCurrentApplicationStore store = new DefaultCurrentApplicationStore(properties, stubServerId("ABC"),
                new MemoryCacheManager(), new SimpleClusterLockService());

        store.start();
        assertState(PAIR, ORIG_ID, store);

        store.setCurrentApplication(NEW_ID, KeyFactory.encode(PAIR2.getPublic()),
                KeyFactory.encode(PAIR2.getPrivate()));

        assertEquals(PAIR2.getPrivate(), properties.getPrivateKey());
        assertEquals(PAIR2.getPublic(), properties.getPublicKey());
        assertEquals(NEW_ID, properties.getApplicationId());

        assertState(PAIR2, NEW_ID, store);
    }

    @Test
    public void testSetCurrentApplicationStringNoUid() throws Exception {
        String ORIG_ID = "orig";
        String NEW_ID = "new";

        TrustedApplicationProperties properties = new TrustedApplicationProperties(ORIG_ID, PAIR);
        DefaultCurrentApplicationStore store = new DefaultCurrentApplicationStore(properties, stubServerId("ABC"),
                new MemoryCacheManager(), new SimpleClusterLockService());

        store.start();
        assertState(PAIR, ORIG_ID, store);

        store.setCurrentApplication(NEW_ID, PUBLIC_KEY_VALUE2, PRIVATE_KEY_VALUE2);

        assertEquals(PAIR2.getPrivate(), properties.getPrivateKey());
        assertEquals(PAIR2.getPublic(), properties.getPublicKey());
        assertEquals(NEW_ID, properties.getApplicationId());

        assertState(PAIR2, NEW_ID, store);
    }

    @Test
    public void testSetCurrentApplicationNoUid() throws Exception {
        TrustedApplicationProperties properties = new TrustedApplicationProperties(TEST_UID, PAIR);
        DefaultCurrentApplicationStore store = new DefaultCurrentApplicationStore(properties, stubServerId("ABC"),
                new MemoryCacheManager(), new SimpleClusterLockService());

        store.start();
        //Need to init the cache.
        store.getCurrentApplication();
        assertState(PAIR, TEST_UID, store);

        try {
            store.setCurrentApplication(null, PAIR2);
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        try {
            store.setCurrentApplication("", PAIR2);
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        assertState(PAIR, TEST_UID, store);
    }

    @Test
    public void testSetCurrentApplicationNoUidString() throws Exception {
        TrustedApplicationProperties properties = new TrustedApplicationProperties(TEST_UID, PAIR);
        DefaultCurrentApplicationStore store = new DefaultCurrentApplicationStore(properties, stubServerId("ABC"),
                new MemoryCacheManager(), new SimpleClusterLockService());

        store.start();
        //Need to init the cache.
        store.getCurrentApplication();
        assertState(PAIR, TEST_UID, store);

        try {
            store.setCurrentApplication(null, PUBLIC_KEY_VALUE2, PRIVATE_KEY_VALUE2);
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        try {
            store.setCurrentApplication("", PUBLIC_KEY_VALUE2, PRIVATE_KEY_VALUE2);
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        assertState(PAIR, TEST_UID, store);
    }

    @Test
    public void testSetCurrentApplicationBadKeys() throws Exception {
        TrustedApplicationProperties properties = new TrustedApplicationProperties(TEST_UID, PAIR);
        DefaultCurrentApplicationStore store = new DefaultCurrentApplicationStore(properties, stubServerId("ABC"),
                new MemoryCacheManager(), new SimpleClusterLockService());

        store.start();
        //Need to init the cache.
        store.getCurrentApplication();
        assertState(PAIR, TEST_UID, store);

        try {
            store.setCurrentApplication("somethings", null);
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        try {
            store.setCurrentApplication("somethings", new KeyPair(null, PAIR2.getPrivate()));
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        try {
            store.setCurrentApplication("somethings", new KeyPair(PAIR2.getPublic(), null));
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        assertState(PAIR, TEST_UID, store);
    }

    @Test
    public void testSetCurrentApplicationBadKeysString() throws Exception {
        TrustedApplicationProperties properties = new TrustedApplicationProperties(TEST_UID, PAIR);
        DefaultCurrentApplicationStore store = new DefaultCurrentApplicationStore(properties, stubServerId("ABC"),
                new MemoryCacheManager(), new SimpleClusterLockService());

        store.start();
        //Need to init the cache.
        store.getCurrentApplication();
        assertState(PAIR, TEST_UID, store);

        try {
            store.setCurrentApplication("somethings", null, null);
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        try {
            store.setCurrentApplication("somethings", PUBLIC_KEY_VALUE2, null);
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        try {
            store.setCurrentApplication("somethings", null, PRIVATE_KEY_VALUE2);
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        try {
            store.setCurrentApplication("somethings", "AAAAAAA", PRIVATE_KEY_VALUE2);
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        try {
            store.setCurrentApplication("somethings", PUBLIC_KEY_VALUE2, "BBBBBBBB");
            fail("Not Allowed.");
        } catch (IllegalArgumentException good) {
        }

        assertState(PAIR, TEST_UID, store);
    }

    private void assertState(KeyPair pair, String applicationId, CurrentApplicationStore applicationStore) {
        assertState(pair.getPublic(), pair.getPrivate(), applicationId, applicationStore);
    }

    private void assertState(final PublicKey publicKey, final PrivateKey privateKey, final String applicationId,
            final CurrentApplicationStore applicationStore) {
        CurrentApplication currentApplication = applicationStore.getCurrentApplication();
        assertEquals(applicationId, currentApplication.getID());
        assertEquals(publicKey, currentApplication.getPublicKey());

        KeyPair keyPair = applicationStore.getKeyPair();
        assertEquals(publicKey, keyPair.getPublic());
        assertEquals(privateKey, keyPair.getPrivate());

        // just make sure we have a key
        final EncryptedCertificate encoded = currentApplication.encode("this little sentence", null);
        assertNotNull(encoded.getCertificate());
        assertEquals(applicationId, encoded.getID());
        assertNotNull(encoded.getSecretKey());

    }

    private static KeyPair getKeys(String publicKeyString, String privateKeyString) {
        PrivateKey privateKey = KeyFactory.getPrivateKey(privateKeyString);
        PublicKey publicKey = KeyFactory.getPublicKey(publicKeyString);

        return new KeyPair(publicKey, privateKey);
    }

    private static class TrustedApplicationProperties implements ApplicationProperties {
        public static final String PROP_PUBLIC_KEY = "jira.trustedapp.key.public.data";
        public static final String PROP_UID = "jira.trustedapp.uid";
        public static final String PROP_PRIVATE_KEY = "jira.trustedapp.key.private.data";

        private String publicKey;
        private String privateKey;
        private String applicationId;

        private TrustedApplicationProperties() {
        }

        private TrustedApplicationProperties(String applicationId, KeyPair pairs) {
            this.applicationId = applicationId;
            this.privateKey = KeyFactory.encode(pairs.getPrivate());
            this.publicKey = KeyFactory.encode(pairs.getPublic());
        }

        private TrustedApplicationProperties(String applicationId, String publicKey, String privateKey) {
            this.applicationId = applicationId;
            this.privateKey = privateKey;
            this.publicKey = publicKey;
        }

        public String getText(String name) {
            if (name.equals(PROP_PUBLIC_KEY)) {
                return publicKey;
            } else if (name.equals(PROP_PRIVATE_KEY)) {
                return privateKey;
            } else {
                throw new IllegalArgumentException("Not a valid option: " + name);
            }
        }

        public String getDefaultBackedText(String name) {
            throw new RuntimeException("Not implemented.");
        }

        public void setText(String name, String value) {
            if (name.equals(PROP_PUBLIC_KEY)) {
                this.publicKey = value;
            } else if (name.equals(PROP_PRIVATE_KEY)) {
                this.privateKey = value;
            } else {
                throw new IllegalArgumentException("Not a valid option: " + name);
            }
        }

        public String getString(String name) {
            if (name.equals(PROP_UID)) {
                return applicationId;
            } else {
                throw new IllegalArgumentException("Not a valid option: " + name);
            }

        }

        public Collection<String> getDefaultKeys() {
            throw new RuntimeException("Not implemented.");
        }

        public String getDefaultBackedString(String name) {
            throw new RuntimeException("Not implemented.");
        }

        public String getDefaultString(String name) {
            throw new RuntimeException("Not implemented.");
        }

        public void setString(String name, String value) {
            if (name.equals(PROP_UID)) {
                this.applicationId = value;
            } else {
                throw new IllegalArgumentException("Not a valid option: " + name);
            }
        }

        public boolean getOption(String key) {
            throw new RuntimeException("Not implemented.");
        }

        public Collection<String> getKeys() {
            return asMap().keySet();
        }

        public void setOption(String key, boolean value) {
            throw new RuntimeException("Not implemented.");
        }

        public String getEncoding() {
            throw new RuntimeException("Not implemented.");
        }

        public String getMailEncoding() {
            throw new RuntimeException("Not implemented.");
        }

        public String getContentType() {
            throw new RuntimeException("Not implemented.");
        }

        public void refresh() {
            throw new RuntimeException("Not implemented.");
        }

        public Locale getDefaultLocale() {
            throw new RuntimeException("Not implemented.");
        }

        public Collection<String> getStringsWithPrefix(String prefix) {
            throw new RuntimeException("Not implemented.");
        }

        public Map<String, Object> asMap() {
            Map<String, Object> map = Maps.newHashMap();
            if (applicationId != null) {
                map.put(PROP_UID, applicationId);
            }
            if (privateKey != null) {
                map.put(PROP_PRIVATE_KEY, privateKey);
            }
            if (publicKey != null) {
                map.put(PROP_PUBLIC_KEY, publicKey);
            }
            return map;
        }

        public KeyPair getPair() {
            return new KeyPair(getPublicKey(), getPrivateKey());
        }

        public PublicKey getPublicKey() {
            return KeyFactory.getPublicKey(publicKey);
        }

        public PrivateKey getPrivateKey() {
            return KeyFactory.getPrivateKey(privateKey);
        }

        public String getApplicationId() {
            return applicationId;
        }
    }

    private static class ReadOnlyApplicationProperties implements ApplicationProperties {
        private final ApplicationProperties delegate;

        private ReadOnlyApplicationProperties(ApplicationProperties delegate) {
            this.delegate = delegate;
        }

        @Override
        public String getText(String name) {
            return delegate.getText(name);
        }

        @Override
        public String getDefaultBackedText(String name) {
            return delegate.getDefaultBackedText(name);
        }

        @Override
        public void setText(String name, String value) {
            throw new IllegalStateException("Read-Only implementation.");
        }

        @Override
        public String getString(String name) {
            return delegate.getString(name);
        }

        @Override
        public Collection<String> getDefaultKeys() {
            return delegate.getDefaultKeys();
        }

        @Override
        public String getDefaultBackedString(String name) {
            return delegate.getDefaultBackedString(name);
        }

        @Override
        public String getDefaultString(String name) {
            return delegate.getDefaultString(name);
        }

        @Override
        public void setString(String name, String value) {
            throw new IllegalStateException("Read-Only implementation.");
        }

        @Override
        public boolean getOption(String key) {
            return delegate.getOption(key);
        }

        @Override
        public Collection<String> getKeys() {
            return delegate.getKeys();
        }

        @Override
        public void setOption(String key, boolean value) {
            throw new IllegalStateException("Read-Only implementation.");
        }

        @Override
        public String getEncoding() {
            return delegate.getEncoding();
        }

        @Override
        public String getMailEncoding() {
            return delegate.getMailEncoding();
        }

        @Override
        public String getContentType() {
            return delegate.getContentType();
        }

        @Override
        public void refresh() {
            throw new IllegalStateException("Read-Only implementation.");
        }

        @Override
        public Locale getDefaultLocale() {
            return delegate.getDefaultLocale();
        }

        @Override
        public Collection<String> getStringsWithPrefix(String prefix) {
            return delegate.getStringsWithPrefix(prefix);
        }

        @Override
        public Map<String, Object> asMap() {
            return delegate.asMap();
        }
    }
}