Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / k8s.io / client-go / transport / transport.go
1 /*
2 Copyright 2015 The Kubernetes Authors.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8     http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 package transport
18
19 import (
20         "crypto/tls"
21         "crypto/x509"
22         "fmt"
23         "io/ioutil"
24         "net/http"
25 )
26
27 // New returns an http.RoundTripper that will provide the authentication
28 // or transport level security defined by the provided Config.
29 func New(config *Config) (http.RoundTripper, error) {
30         // Set transport level security
31         if config.Transport != nil && (config.HasCA() || config.HasCertAuth() || config.HasCertCallback() || config.TLS.Insecure) {
32                 return nil, fmt.Errorf("using a custom transport with TLS certificate options or the insecure flag is not allowed")
33         }
34
35         var (
36                 rt  http.RoundTripper
37                 err error
38         )
39
40         if config.Transport != nil {
41                 rt = config.Transport
42         } else {
43                 rt, err = tlsCache.get(config)
44                 if err != nil {
45                         return nil, err
46                 }
47         }
48
49         return HTTPWrappersForConfig(config, rt)
50 }
51
52 // TLSConfigFor returns a tls.Config that will provide the transport level security defined
53 // by the provided Config. Will return nil if no transport level security is requested.
54 func TLSConfigFor(c *Config) (*tls.Config, error) {
55         if !(c.HasCA() || c.HasCertAuth() || c.HasCertCallback() || c.TLS.Insecure || len(c.TLS.ServerName) > 0) {
56                 return nil, nil
57         }
58         if c.HasCA() && c.TLS.Insecure {
59                 return nil, fmt.Errorf("specifying a root certificates file with the insecure flag is not allowed")
60         }
61         if err := loadTLSFiles(c); err != nil {
62                 return nil, err
63         }
64
65         tlsConfig := &tls.Config{
66                 // Can't use SSLv3 because of POODLE and BEAST
67                 // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher
68                 // Can't use TLSv1.1 because of RC4 cipher usage
69                 MinVersion:         tls.VersionTLS12,
70                 InsecureSkipVerify: c.TLS.Insecure,
71                 ServerName:         c.TLS.ServerName,
72         }
73
74         if c.HasCA() {
75                 tlsConfig.RootCAs = rootCertPool(c.TLS.CAData)
76         }
77
78         var staticCert *tls.Certificate
79         if c.HasCertAuth() {
80                 // If key/cert were provided, verify them before setting up
81                 // tlsConfig.GetClientCertificate.
82                 cert, err := tls.X509KeyPair(c.TLS.CertData, c.TLS.KeyData)
83                 if err != nil {
84                         return nil, err
85                 }
86                 staticCert = &cert
87         }
88
89         if c.HasCertAuth() || c.HasCertCallback() {
90                 tlsConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
91                         // Note: static key/cert data always take precedence over cert
92                         // callback.
93                         if staticCert != nil {
94                                 return staticCert, nil
95                         }
96                         if c.HasCertCallback() {
97                                 cert, err := c.TLS.GetCert()
98                                 if err != nil {
99                                         return nil, err
100                                 }
101                                 // GetCert may return empty value, meaning no cert.
102                                 if cert != nil {
103                                         return cert, nil
104                                 }
105                         }
106
107                         // Both c.TLS.CertData/KeyData were unset and GetCert didn't return
108                         // anything. Return an empty tls.Certificate, no client cert will
109                         // be sent to the server.
110                         return &tls.Certificate{}, nil
111                 }
112         }
113
114         return tlsConfig, nil
115 }
116
117 // loadTLSFiles copies the data from the CertFile, KeyFile, and CAFile fields into the CertData,
118 // KeyData, and CAFile fields, or returns an error. If no error is returned, all three fields are
119 // either populated or were empty to start.
120 func loadTLSFiles(c *Config) error {
121         var err error
122         c.TLS.CAData, err = dataFromSliceOrFile(c.TLS.CAData, c.TLS.CAFile)
123         if err != nil {
124                 return err
125         }
126
127         c.TLS.CertData, err = dataFromSliceOrFile(c.TLS.CertData, c.TLS.CertFile)
128         if err != nil {
129                 return err
130         }
131
132         c.TLS.KeyData, err = dataFromSliceOrFile(c.TLS.KeyData, c.TLS.KeyFile)
133         if err != nil {
134                 return err
135         }
136         return nil
137 }
138
139 // dataFromSliceOrFile returns data from the slice (if non-empty), or from the file,
140 // or an error if an error occurred reading the file
141 func dataFromSliceOrFile(data []byte, file string) ([]byte, error) {
142         if len(data) > 0 {
143                 return data, nil
144         }
145         if len(file) > 0 {
146                 fileData, err := ioutil.ReadFile(file)
147                 if err != nil {
148                         return []byte{}, err
149                 }
150                 return fileData, nil
151         }
152         return nil, nil
153 }
154
155 // rootCertPool returns nil if caData is empty.  When passed along, this will mean "use system CAs".
156 // When caData is not empty, it will be the ONLY information used in the CertPool.
157 func rootCertPool(caData []byte) *x509.CertPool {
158         // What we really want is a copy of x509.systemRootsPool, but that isn't exposed.  It's difficult to build (see the go
159         // code for a look at the platform specific insanity), so we'll use the fact that RootCAs == nil gives us the system values
160         // It doesn't allow trusting either/or, but hopefully that won't be an issue
161         if len(caData) == 0 {
162                 return nil
163         }
164
165         // if we have caData, use it
166         certPool := x509.NewCertPool()
167         certPool.AppendCertsFromPEM(caData)
168         return certPool
169 }