All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yahoo.security.tls.json.TransportSecurityOptionsJsonSerializer Maven / Gradle / Ivy

There is a newer version: 8.411.13
Show newest version
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.security.tls.json;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yahoo.security.tls.TransportSecurityOptions;
import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.AuthorizedPeer;
import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.CredentialField;
import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.Files;
import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.RequiredCredential;
import com.yahoo.security.tls.policy.AuthorizedPeers;
import com.yahoo.security.tls.policy.HostGlobPattern;
import com.yahoo.security.tls.policy.PeerPolicy;
import com.yahoo.security.tls.policy.RequiredPeerCredential;
import com.yahoo.security.tls.policy.Role;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

/**
 * @author bjorncs
 */
public class TransportSecurityOptionsJsonSerializer {

    private static final ObjectMapper mapper = new ObjectMapper();

    public TransportSecurityOptions deserialize(InputStream in) {
        try {
            TransportSecurityOptionsEntity entity = mapper.readValue(in, TransportSecurityOptionsEntity.class);
            return toTransportSecurityOptions(entity);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public void serialize(OutputStream out, TransportSecurityOptions options) {
        try {
            mapper.writerWithDefaultPrettyPrinter().writeValue(out, toTransportSecurityOptionsEntity(options));
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    private static TransportSecurityOptions toTransportSecurityOptions(TransportSecurityOptionsEntity entity) {
        TransportSecurityOptions.Builder builder = new TransportSecurityOptions.Builder();
        Files files = entity.files;
        if (files != null) {
            if (files.certificatesFile != null && files.privateKeyFile != null) {
                builder.withCertificates(Paths.get(files.certificatesFile), Paths.get(files.privateKeyFile));
            } else if (files.certificatesFile != null || files.privateKeyFile != null) {
                throw new IllegalArgumentException("Both 'private-key' and 'certificates' must be configured together");
            }
            if (files.caCertificatesFile != null) {
                builder.withCaCertificates(Paths.get(files.caCertificatesFile));
            }
        }
        List authorizedPeersEntity = entity.authorizedPeers;
        if (authorizedPeersEntity != null) {
            if (authorizedPeersEntity.size() == 0) {
                throw new IllegalArgumentException("'authorized-peers' cannot be empty");
            }
            builder.withAuthorizedPeers(new AuthorizedPeers(toPeerPolicies(authorizedPeersEntity)));
        }
        if (entity.acceptedCiphers != null) {
            if (entity.acceptedCiphers.isEmpty()) {
                throw new IllegalArgumentException("'accepted-ciphers' cannot be empty");
            }
            builder.withAcceptedCiphers(entity.acceptedCiphers);
        }
        return builder.build();
    }

    private static Set toPeerPolicies(List authorizedPeersEntity) {
        return authorizedPeersEntity.stream()
                .map(TransportSecurityOptionsJsonSerializer::toPeerPolicy)
                .collect(toSet());
    }

    private static PeerPolicy toPeerPolicy(AuthorizedPeer authorizedPeer) {
        if (authorizedPeer.name == null) {
            throw missingFieldException("name");
        }
        if (authorizedPeer.requiredCredentials == null) {
            throw missingFieldException("required-credentials");
        }
        return new PeerPolicy(authorizedPeer.name, toRoles(authorizedPeer.roles), toRequestPeerCredentials(authorizedPeer.requiredCredentials));
    }

    private static Set toRoles(List roles) {
        if (roles == null) return Collections.emptySet();
        return roles.stream()
                .map(Role::new)
                .collect(toSet());
    }

    private static List toRequestPeerCredentials(List requiredCredentials) {
        return requiredCredentials.stream()
                .map(TransportSecurityOptionsJsonSerializer::toRequiredPeerCredential)
                .collect(toList());
    }

    private static RequiredPeerCredential toRequiredPeerCredential(RequiredCredential requiredCredential) {
        if (requiredCredential.field == null) {
            throw missingFieldException("field");
        }
        if (requiredCredential.matchExpression == null) {
            throw missingFieldException("must-match");
        }
        return new RequiredPeerCredential(toField(requiredCredential.field), new HostGlobPattern(requiredCredential.matchExpression));
    }

    private static RequiredPeerCredential.Field toField(CredentialField field) {
        switch (field) {
            case CN: return RequiredPeerCredential.Field.CN;
            case SAN_DNS: return RequiredPeerCredential.Field.SAN_DNS;
            default: throw new IllegalArgumentException("Invalid field type: " + field);
        }
    }

    private static TransportSecurityOptionsEntity toTransportSecurityOptionsEntity(TransportSecurityOptions options) {
        TransportSecurityOptionsEntity entity = new TransportSecurityOptionsEntity();
        entity.files = new Files();
        options.getCaCertificatesFile().ifPresent(value -> entity.files.caCertificatesFile = value.toString());
        options.getCertificatesFile().ifPresent(value -> entity.files.certificatesFile = value.toString());
        options.getPrivateKeyFile().ifPresent(value -> entity.files.privateKeyFile = value.toString());
        options.getAuthorizedPeers().ifPresent( authorizedPeers -> {
            entity.authorizedPeers = new ArrayList<>();
            for (PeerPolicy peerPolicy : authorizedPeers.peerPolicies()) {
                AuthorizedPeer authorizedPeer = new AuthorizedPeer();
                authorizedPeer.name = peerPolicy.policyName();
                authorizedPeer.requiredCredentials = new ArrayList<>();
                for (RequiredPeerCredential requiredPeerCredential : peerPolicy.requiredCredentials()) {
                    RequiredCredential requiredCredential = new RequiredCredential();
                    requiredCredential.field = toField(requiredPeerCredential.field());
                    requiredCredential.matchExpression = requiredPeerCredential.pattern().asString();
                    authorizedPeer.requiredCredentials.add(requiredCredential);
                }
                if (!peerPolicy.assumedRoles().isEmpty()) {
                    authorizedPeer.roles = new ArrayList<>();
                    peerPolicy.assumedRoles().forEach(role -> authorizedPeer.roles.add(role.name()));
                }
                entity.authorizedPeers.add(authorizedPeer);
            }
        });
        if (!options.getAcceptedCiphers().isEmpty()) {
            entity.acceptedCiphers = options.getAcceptedCiphers();
        }
        return entity;
    }

    private static CredentialField toField(RequiredPeerCredential.Field field) {
        switch (field) {
            case CN: return CredentialField.CN;
            case SAN_DNS: return CredentialField.SAN_DNS;
            default: throw new IllegalArgumentException("Invalid field type: " + field);
        }
    }

    private static IllegalArgumentException missingFieldException(String fieldName) {
        return new IllegalArgumentException(String.format("'%s' missing", fieldName));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy