001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2014-2015 ForgeRock AS.
015 */
016
017package org.forgerock.openig.security;
018
019import static java.lang.String.*;
020import static org.forgerock.openig.util.JsonValues.*;
021import static org.forgerock.util.Utils.*;
022
023import java.io.InputStream;
024import java.net.URL;
025import java.security.KeyStore;
026
027import org.forgerock.json.JsonValue;
028import org.forgerock.openig.heap.GenericHeaplet;
029import org.forgerock.openig.heap.HeapException;
030
031/**
032 * Represents a loaded Java {@link KeyStore}.
033 * <pre>
034 *     {@code
035 *     {
036 *         "name": "LocalKeyStore",
037 *         "type": "KeyStore",
038 *         "config": {
039 *             "url": "file://${env['HOME']}/keystore.jks",
040 *             "password": "secret",
041 *             "type": "JKS"
042 *         }
043 *     }
044 *     }
045 * </pre>
046 * <ul>
047 *     <li>{@literal url}: URL to the target key store file (expression, required).</li>
048 *     <li>{@literal type}: key store type (defaults to platform's default type) (string, optional).</li>
049 *     <li>{@literal password}: credential required to read private keys from the key store (expression, optional),
050 *     not needed when the key store is used for a trust store.</li>
051 * </ul>
052 * @since 3.1
053 */
054public class KeyStoreHeaplet extends GenericHeaplet {
055
056    @Override
057    public Object create() throws HeapException {
058        JsonValue urlString = config.get("url").required();
059        URL url = evaluateJsonStaticExpression(urlString).asURL();
060        String password = evaluate(config.get("password"));
061        String type = config.get("type").defaultTo(KeyStore.getDefaultType()).asString().toUpperCase();
062
063        KeyStore keyStore = null;
064        InputStream keyInput = null;
065        try {
066            keyStore = KeyStore.getInstance(type);
067            keyInput = url.openStream();
068            char[] credentials = (password == null) ? null : password.toCharArray();
069            keyStore.load(keyInput, credentials);
070        } catch (Exception e) {
071            throw new HeapException(format("Cannot load %S KeyStore from %s", type, urlString.asString()), e);
072        } finally {
073            closeSilently(keyInput);
074        }
075        return keyStore;
076    }
077}