summaryrefslogtreecommitdiffstats
path: root/security-utils/src/main/java/com/yahoo/security/tls/TransportSecurityOptions.java
blob: bc124b4fe2d159e531c9c00f5584765978623789 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// 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;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * Generic TLS configuration for Vespa
 *
 * @author bjorncs
 */
// TODO Add builder
public class TransportSecurityOptions {

    private static final ObjectMapper mapper = new ObjectMapper();

    private final Path privateKeyFile;
    private final Path certificatesFile;
    private final Path caCertificatesFile;
    private final List<String> acceptedCiphers;

    public TransportSecurityOptions(String privateKeyFile, String certificatesFile, String caCertificatesFile) {
        this(Paths.get(privateKeyFile), Paths.get(certificatesFile), Paths.get(caCertificatesFile));
    }

    public TransportSecurityOptions(Path privateKeyFile, Path certificatesFile, Path caCertificatesFile) {
        this(privateKeyFile, certificatesFile, caCertificatesFile, Collections.emptyList());
    }

    public TransportSecurityOptions(String privateKeyFile, String certificatesFile, String caCertificatesFile, List<String> acceptedCiphers) {
        this(Paths.get(privateKeyFile), Paths.get(certificatesFile), Paths.get(caCertificatesFile), acceptedCiphers);
    }

    public TransportSecurityOptions(Path privateKeyFile, Path certificatesFile, Path caCertificatesFile, List<String> acceptedCiphers) {
        this.privateKeyFile = privateKeyFile;
        this.certificatesFile = certificatesFile;
        this.caCertificatesFile = caCertificatesFile;
        this.acceptedCiphers = acceptedCiphers;
    }

    public Path getPrivateKeyFile() {
        return privateKeyFile;
    }

    public Path getCertificatesFile() {
        return certificatesFile;
    }

    public Path getCaCertificatesFile() {
        return caCertificatesFile;
    }

    public List<String> getAcceptedCiphers() {
        return acceptedCiphers;
    }

    public static TransportSecurityOptions fromJsonFile(Path file) {
        try {
            return fromJsonNode(mapper.readTree(file.toFile()));
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public static TransportSecurityOptions fromJson(String json) {
        try {
            return fromJsonNode(mapper.readTree(json));
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    private static TransportSecurityOptions fromJsonNode(JsonNode root) {
        JsonNode filesNode = getFieldOrThrow(root, "files");
        List<String> acceptedCiphers = getField(root, "accepted-ciphers")
                .map(TransportSecurityOptions::toCipherList)
                .orElse(Collections.emptyList());
        String privateKeyFile = getFieldOrThrow(filesNode, "private-key").asText();
        String certificatesFile = getFieldOrThrow(filesNode, "certificates").asText();
        String caCertificatesFile = getFieldOrThrow(filesNode, "ca-certificates").asText();
        return new TransportSecurityOptions(privateKeyFile, certificatesFile, caCertificatesFile, acceptedCiphers);
    }

    private static List<String> toCipherList(JsonNode ciphersNode) {
        List<String> ciphers = new ArrayList<>();
        for (JsonNode cipherNode : ciphersNode) {
            ciphers.add(cipherNode.asText());
        }
        return ciphers;
    }

    private static Optional<JsonNode> getField(JsonNode root, String fieldName) {
        return Optional.ofNullable(root.get(fieldName));
    }

    private static JsonNode getFieldOrThrow(JsonNode root, String fieldName) {
        return getField(root, fieldName)
                .orElseThrow(() -> new IllegalArgumentException(String.format("'%s' field missing", fieldName)));
    }

    @Override
    public String toString() {
        return "TransportSecurityOptions{" +
                "privateKeyFile=" + privateKeyFile +
                ", certificatesFile=" + certificatesFile +
                ", caCertificatesFile=" + caCertificatesFile +
                ", acceptedCiphers=" + acceptedCiphers +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        TransportSecurityOptions that = (TransportSecurityOptions) o;
        return Objects.equals(privateKeyFile, that.privateKeyFile) &&
                Objects.equals(certificatesFile, that.certificatesFile) &&
                Objects.equals(caCertificatesFile, that.caCertificatesFile) &&
                Objects.equals(acceptedCiphers, that.acceptedCiphers);
    }

    @Override
    public int hashCode() {
        return Objects.hash(privateKeyFile, certificatesFile, caCertificatesFile, acceptedCiphers);
    }
}