keywhiz.service.daos.SecretController.java Source code

Java tutorial

Introduction

Here is the source code for keywhiz.service.daos.SecretController.java

Source

/*
 * Copyright (C) 2015 Square, Inc.
 *
 * 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 keywhiz.service.daos;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import keywhiz.api.model.Group;
import keywhiz.api.model.SanitizedSecret;
import keywhiz.api.model.SanitizedSecretWithGroups;
import keywhiz.api.model.Secret;
import keywhiz.api.model.SecretSeriesAndContent;
import keywhiz.service.crypto.ContentCryptographer;
import keywhiz.service.crypto.ContentEncodingException;
import keywhiz.service.crypto.SecretTransformer;

import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static keywhiz.api.model.SanitizedSecretWithGroups.fromSecretSeriesAndContentAndGroups;

public class SecretController {
    private final SecretTransformer transformer;
    private final ContentCryptographer cryptographer;
    private final SecretDAO secretDAO;
    private final AclDAO aclDAO;

    public SecretController(SecretTransformer transformer, ContentCryptographer cryptographer, SecretDAO secretDAO,
            AclDAO aclDAO) {
        this.transformer = transformer;
        this.cryptographer = cryptographer;
        this.secretDAO = secretDAO;
        this.aclDAO = aclDAO;
    }

    /**
     * @param secretId external secret series id to look up secrets by.
     * @return Secret matching input parameters or Optional.absent().
     */
    public Optional<Secret> getSecretById(long secretId) {
        return secretDAO.getSecretById(secretId).map(transformer::transform);
    }

    /**
     * @param name of secret series to look up secrets by.
     * @return Secret matching input parameters or Optional.absent().
     */
    public Optional<Secret> getSecretByName(String name) {
        return secretDAO.getSecretByName(name).map(transformer::transform);
    }

    /**
     * @param expireMaxTime timestamp for farthest expiry to include
     * @param group limit results to secrets assigned to this group, if provided.
     * @return all existing sanitized secrets matching criteria.
     * */
    public List<SanitizedSecret> getSanitizedSecrets(@Nullable Long expireMaxTime, Group group) {
        return secretDAO.getSecrets(expireMaxTime, group).stream().map(SanitizedSecret::fromSecretSeriesAndContent)
                .collect(toList());
    }

    /**
     * @param expireMaxTime timestamp for farthest expiry to include
     * @return all existing sanitized secrets and their groups matching criteria.
     * */
    public List<SanitizedSecretWithGroups> getExpiringSanitizedSecrets(@Nullable Long expireMaxTime) {
        ImmutableList<SecretSeriesAndContent> secrets = secretDAO.getSecrets(expireMaxTime, null);

        Map<Long, SecretSeriesAndContent> secretIds = secrets.stream().collect(toMap(s -> s.series().id(), s -> s));

        Map<Long, List<Group>> groupsForSecrets = aclDAO.getGroupsForSecrets(secretIds.keySet());

        return secrets.stream().map(s -> {
            List<Group> groups = groupsForSecrets.get(s.series().id());
            if (groups == null) {
                groups = ImmutableList.of();
            }
            return fromSecretSeriesAndContentAndGroups(s, groups);
        }).collect(toList());
    }

    /** @return names of all existing sanitized secrets. */
    public List<SanitizedSecret> getSecretsNameOnly() {
        return secretDAO.getSecretsNameOnly().stream().map(s -> SanitizedSecret.of(s.getKey(), s.getValue()))
                .collect(toList());
    }

    /**
     * @param idx the first index to select in a list of secrets sorted by creation time
     * @param num the number of secrets after idx to select in the list of secrets
     * @param newestFirst if true, order the secrets from newest creation time to oldest
     * @return A list of secret names
     */
    public List<SanitizedSecret> getSecretsBatched(int idx, int num, boolean newestFirst) {
        checkArgument(idx >= 0, "Index must be positive when getting batched secret names!");
        checkArgument(num >= 0, "Num must be positive when getting batched secret names!");
        return secretDAO.getSecretsBatched(idx, num, newestFirst).stream()
                .map(SanitizedSecret::fromSecretSeriesAndContent).collect(toList());
    }

    public SecretBuilder builder(String name, String secret, String creator, long expiry) {
        checkArgument(!name.isEmpty());
        checkArgument(!secret.isEmpty());
        checkArgument(!creator.isEmpty());
        String hmac = cryptographer.computeHmac(secret.getBytes(UTF_8)); // Compute HMAC on base64 encoded data
        if (hmac == null) {
            throw new ContentEncodingException("Error encoding content for SecretBuilder!");
        }
        String encryptedSecret = cryptographer.encryptionKeyDerivedFrom(name).encrypt(secret);
        return new SecretBuilder(transformer, secretDAO, name, encryptedSecret, hmac, creator, expiry);
    }

    /** Builder to generate new secret series or versions with. */
    public static class SecretBuilder {
        private final SecretTransformer transformer;
        private final SecretDAO secretDAO;
        private final String name;
        private final String encryptedSecret;
        private final String hmac;
        private final String creator;
        private String description = "";
        private Map<String, String> metadata = ImmutableMap.of();
        private long expiry = 0;
        private String type;
        private Map<String, String> generationOptions = ImmutableMap.of();

        /**
         * @param transformer
         * @param secretDAO
         * @param name of secret series.
         * @param encryptedSecret encrypted content of secret version
         * @param creator username responsible for creating this secret version.
         */
        private SecretBuilder(SecretTransformer transformer, SecretDAO secretDAO, String name,
                String encryptedSecret, String hmac, String creator, long expiry) {
            this.transformer = transformer;
            this.secretDAO = secretDAO;
            this.name = name;
            this.encryptedSecret = encryptedSecret;
            this.hmac = hmac;
            this.creator = creator;
            this.expiry = expiry;
        }

        /**
         * Supply an optional description of the secret.
         * @param description description of secret
         * @return the builder
         */
        public SecretBuilder withDescription(String description) {
            this.description = checkNotNull(description);
            return this;
        }

        /**
         * Supply optional map of metadata properties for the secret.
         * @param metadata metadata of secret
         * @return the builder
         */
        public SecretBuilder withMetadata(Map<String, String> metadata) {
            this.metadata = checkNotNull(metadata);
            return this;
        }

        /**
         * Supply a secret type, otherwise the default '' is used.
         * @param type type of secret
         * @return the builder
         */
        public SecretBuilder withType(String type) {
            this.type = checkNotNull(type);
            return this;
        }

        /**
         * Finalizes creation of a new secret.
         *
         * @return an instance of the newly created secret.
         */
        public Secret create() {
            secretDAO.createSecret(name, encryptedSecret, hmac, creator, metadata, expiry, description, type,
                    generationOptions);
            return transformer.transform(secretDAO.getSecretByName(name).get());
        }

        public Secret createOrUpdate() {
            secretDAO.createOrUpdateSecret(name, encryptedSecret, hmac, creator, metadata, expiry, description,
                    type, generationOptions);
            return transformer.transform(secretDAO.getSecretByName(name).get());
        }
    }
}