org.forgerock.openidm.security.impl.KeystoreResourceProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.forgerock.openidm.security.impl.KeystoreResourceProvider.java

Source

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2013-2015 ForgeRock AS. All Rights Reserved
 *
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the License). You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the License at
 * http://forgerock.org/license/CDDLv1.0.html
 * See the License for the specific language governing
 * permission and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at http://forgerock.org/license/CDDLv1.0.html
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 */

package org.forgerock.openidm.security.impl;

import static org.forgerock.json.resource.Responses.newResourceResponse;

import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;

import org.apache.commons.lang3.tuple.Pair;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.forgerock.json.JsonValueException;
import org.forgerock.services.context.Context;
import org.forgerock.json.JsonValue;
import org.forgerock.json.resource.ActionRequest;
import org.forgerock.json.resource.ActionResponse;
import org.forgerock.json.resource.BadRequestException;
import org.forgerock.json.resource.ConflictException;
import org.forgerock.json.resource.InternalServerErrorException;
import org.forgerock.json.resource.NotSupportedException;
import org.forgerock.json.resource.PatchRequest;
import org.forgerock.json.resource.ReadRequest;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.ResourceResponse;
import org.forgerock.json.resource.Responses;
import org.forgerock.json.resource.SingletonResourceProvider;
import org.forgerock.json.resource.UpdateRequest;
import org.forgerock.openidm.repo.RepositoryService;
import org.forgerock.openidm.security.KeyStoreHandler;
import org.forgerock.openidm.security.KeyStoreManager;
import org.forgerock.openidm.util.ResourceUtil;
import org.forgerock.util.promise.Promise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Services requests on a specific keystore.
 */
public class KeystoreResourceProvider extends SecurityResourceProvider implements SingletonResourceProvider {

    /**
     * Setup logging for the {@link SecurityManager}.
     */
    private final static Logger logger = LoggerFactory.getLogger(KeystoreResourceProvider.class);

    public KeystoreResourceProvider(String resourceName, KeyStoreHandler store, KeyStoreManager manager,
            RepositoryService repoService) {
        super(resourceName, store, manager, repoService);
    }

    @Override
    public Promise<ActionResponse, ResourceException> actionInstance(Context context, ActionRequest request) {
        try {
            String alias = request.getContent().get("alias").asString();
            if (ACTION_GENERATE_CERT.equalsIgnoreCase(request.getAction())
                    || ACTION_GENERATE_CSR.equalsIgnoreCase(request.getAction())) {
                if (alias == null) {
                    return new BadRequestException("A valid resource ID must be specified in the request")
                            .asPromise();
                }
                String algorithm = request.getContent().get("algorithm").defaultTo(DEFAULT_ALGORITHM).asString();
                String signatureAlgorithm = request.getContent().get("signatureAlgorithm")
                        .defaultTo(DEFAULT_SIGNATURE_ALGORITHM).asString();
                int keySize = request.getContent().get("keySize").defaultTo(DEFAULT_KEY_SIZE).asInteger();
                JsonValue result = null;
                if (ACTION_GENERATE_CERT.equalsIgnoreCase(request.getAction())) {
                    // Generate self-signed certificate
                    if (store.getStore().containsAlias(alias)) {
                        return new ConflictException("The resource with ID '" + alias
                                + "' could not be created because there is already another resource with the same ID")
                                        .asPromise();
                    } else {
                        logger.info("Generating a new self-signed certificate with the alias {}", alias);
                        String domainName = request.getContent().get("domainName").required().asString();
                        String validFrom = request.getContent().get("validFrom").asString();
                        String validTo = request.getContent().get("validTo").asString();

                        // Generate the cert
                        Pair<X509Certificate, PrivateKey> pair = generateCertificate(domainName, algorithm, keySize,
                                signatureAlgorithm, validFrom, validTo);
                        Certificate cert = pair.getKey();
                        PrivateKey key = pair.getValue();

                        // Add it to the store and reload
                        logger.debug("Adding certificate entry under the alias {}", alias);
                        store.getStore().setEntry(alias,
                                new KeyStore.PrivateKeyEntry(key, new Certificate[] { cert }),
                                new KeyStore.PasswordProtection(store.getPassword().toCharArray()));
                        store.store();
                        manager.reload();
                        // Save the store to the repo (if clustered)
                        saveStore();

                        result = returnCertificate(alias, cert);
                        if (request.getContent().get("returnPrivateKey").defaultTo(false).asBoolean()) {
                            result.put("privateKey", getKeyMap(key));
                        }
                    }
                } else {
                    // Generate CSR
                    Pair<PKCS10CertificationRequest, PrivateKey> csr = generateCSR(alias, algorithm,
                            signatureAlgorithm, keySize, request.getContent());
                    result = returnCertificateRequest(alias, csr.getKey());
                    if (request.getContent().get("returnPrivateKey").defaultTo(false).asBoolean()) {
                        result.put("privateKey", getKeyMap(csr.getRight()));
                    }
                }
                return Responses.newActionResponse(result).asPromise();
            } else {
                return new BadRequestException("Unsupported action " + request.getAction()).asPromise();
            }
        } catch (JsonValueException e) {
            return new BadRequestException(e.getMessage(), e).asPromise();
        } catch (Exception e) {
            return new InternalServerErrorException(e).asPromise();
        }
    }

    @Override
    public Promise<ResourceResponse, ResourceException> patchInstance(Context context, PatchRequest request) {
        return new NotSupportedException("Patch operations are not supported").asPromise();
    }

    @Override
    public Promise<ResourceResponse, ResourceException> readInstance(final Context context,
            final ReadRequest request) {
        try {
            JsonValue content = new JsonValue(new LinkedHashMap<String, Object>(5));
            content.put("type", store.getStore().getType());
            content.put("provider", store.getStore().getProvider());
            Enumeration<String> aliases = store.getStore().aliases();
            List<String> aliasList = new ArrayList<>();
            while (aliases.hasMoreElements()) {
                aliasList.add(aliases.nextElement());
            }
            content.put("aliases", aliasList);
            return newResourceResponse(resourceName, null, content).asPromise();
        } catch (KeyStoreException e) {
            return new InternalServerErrorException(e).asPromise();
        }
    }

    @Override
    public Promise<ResourceResponse, ResourceException> updateInstance(Context context, UpdateRequest request) {
        return new NotSupportedException("Update operations are not supported").asPromise();
    }
}