blob: 3351bf0ee5f8752949b018dca9e201c59c08b2eb [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2 *
3 * Copyright 2014 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19// Package credentials implements various credentials supported by gRPC library,
20// which encapsulate all the state needed by a client to authenticate with a
21// server and make various assertions, e.g., about the client's identity, role,
22// or whether it is authorized to make a particular call.
23package credentials // import "google.golang.org/grpc/credentials"
24
25import (
26 "crypto/tls"
27 "crypto/x509"
28 "errors"
29 "fmt"
30 "io/ioutil"
31 "net"
32 "strings"
33
34 "golang.org/x/net/context"
35)
36
37// alpnProtoStr are the specified application level protocols for gRPC.
38var alpnProtoStr = []string{"h2"}
39
40// PerRPCCredentials defines the common interface for the credentials which need to
41// attach security information to every RPC (e.g., oauth2).
42type PerRPCCredentials interface {
43 // GetRequestMetadata gets the current request metadata, refreshing
44 // tokens if required. This should be called by the transport layer on
45 // each request, and the data should be populated in headers or other
46 // context. If a status code is returned, it will be used as the status
47 // for the RPC. uri is the URI of the entry point for the request.
48 // When supported by the underlying implementation, ctx can be used for
49 // timeout and cancellation.
50 // TODO(zhaoq): Define the set of the qualified keys instead of leaving
51 // it as an arbitrary string.
52 GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
53 // RequireTransportSecurity indicates whether the credentials requires
54 // transport security.
55 RequireTransportSecurity() bool
56}
57
58// ProtocolInfo provides information regarding the gRPC wire protocol version,
59// security protocol, security protocol version in use, server name, etc.
60type ProtocolInfo struct {
61 // ProtocolVersion is the gRPC wire protocol version.
62 ProtocolVersion string
63 // SecurityProtocol is the security protocol in use.
64 SecurityProtocol string
65 // SecurityVersion is the security protocol version.
66 SecurityVersion string
67 // ServerName is the user-configured server name.
68 ServerName string
69}
70
71// AuthInfo defines the common interface for the auth information the users are interested in.
72type AuthInfo interface {
73 AuthType() string
74}
75
76// ErrConnDispatched indicates that rawConn has been dispatched out of gRPC
77// and the caller should not close rawConn.
78var ErrConnDispatched = errors.New("credentials: rawConn is dispatched out of gRPC")
79
80// TransportCredentials defines the common interface for all the live gRPC wire
81// protocols and supported transport security protocols (e.g., TLS, SSL).
82type TransportCredentials interface {
83 // ClientHandshake does the authentication handshake specified by the corresponding
84 // authentication protocol on rawConn for clients. It returns the authenticated
85 // connection and the corresponding auth information about the connection.
86 // Implementations must use the provided context to implement timely cancellation.
87 // gRPC will try to reconnect if the error returned is a temporary error
88 // (io.EOF, context.DeadlineExceeded or err.Temporary() == true).
89 // If the returned error is a wrapper error, implementations should make sure that
90 // the error implements Temporary() to have the correct retry behaviors.
91 //
92 // If the returned net.Conn is closed, it MUST close the net.Conn provided.
93 ClientHandshake(context.Context, string, net.Conn) (net.Conn, AuthInfo, error)
94 // ServerHandshake does the authentication handshake for servers. It returns
95 // the authenticated connection and the corresponding auth information about
96 // the connection.
97 //
98 // If the returned net.Conn is closed, it MUST close the net.Conn provided.
99 ServerHandshake(net.Conn) (net.Conn, AuthInfo, error)
100 // Info provides the ProtocolInfo of this TransportCredentials.
101 Info() ProtocolInfo
102 // Clone makes a copy of this TransportCredentials.
103 Clone() TransportCredentials
104 // OverrideServerName overrides the server name used to verify the hostname on the returned certificates from the server.
105 // gRPC internals also use it to override the virtual hosting name if it is set.
106 // It must be called before dialing. Currently, this is only used by grpclb.
107 OverrideServerName(string) error
108}
109
110// TLSInfo contains the auth information for a TLS authenticated connection.
111// It implements the AuthInfo interface.
112type TLSInfo struct {
113 State tls.ConnectionState
114}
115
116// AuthType returns the type of TLSInfo as a string.
117func (t TLSInfo) AuthType() string {
118 return "tls"
119}
120
121// tlsCreds is the credentials required for authenticating a connection using TLS.
122type tlsCreds struct {
123 // TLS configuration
124 config *tls.Config
125}
126
127func (c tlsCreds) Info() ProtocolInfo {
128 return ProtocolInfo{
129 SecurityProtocol: "tls",
130 SecurityVersion: "1.2",
131 ServerName: c.config.ServerName,
132 }
133}
134
135func (c *tlsCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (_ net.Conn, _ AuthInfo, err error) {
136 // use local cfg to avoid clobbering ServerName if using multiple endpoints
137 cfg := cloneTLSConfig(c.config)
138 if cfg.ServerName == "" {
139 colonPos := strings.LastIndex(authority, ":")
140 if colonPos == -1 {
141 colonPos = len(authority)
142 }
143 cfg.ServerName = authority[:colonPos]
144 }
145 conn := tls.Client(rawConn, cfg)
146 errChannel := make(chan error, 1)
147 go func() {
148 errChannel <- conn.Handshake()
149 }()
150 select {
151 case err := <-errChannel:
152 if err != nil {
153 return nil, nil, err
154 }
155 case <-ctx.Done():
156 return nil, nil, ctx.Err()
157 }
158 return conn, TLSInfo{conn.ConnectionState()}, nil
159}
160
161func (c *tlsCreds) ServerHandshake(rawConn net.Conn) (net.Conn, AuthInfo, error) {
162 conn := tls.Server(rawConn, c.config)
163 if err := conn.Handshake(); err != nil {
164 return nil, nil, err
165 }
166 return conn, TLSInfo{conn.ConnectionState()}, nil
167}
168
169func (c *tlsCreds) Clone() TransportCredentials {
170 return NewTLS(c.config)
171}
172
173func (c *tlsCreds) OverrideServerName(serverNameOverride string) error {
174 c.config.ServerName = serverNameOverride
175 return nil
176}
177
178// NewTLS uses c to construct a TransportCredentials based on TLS.
179func NewTLS(c *tls.Config) TransportCredentials {
180 tc := &tlsCreds{cloneTLSConfig(c)}
181 tc.config.NextProtos = alpnProtoStr
182 return tc
183}
184
185// NewClientTLSFromCert constructs TLS credentials from the input certificate for client.
186// serverNameOverride is for testing only. If set to a non empty string,
187// it will override the virtual host name of authority (e.g. :authority header field) in requests.
188func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) TransportCredentials {
189 return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp})
190}
191
192// NewClientTLSFromFile constructs TLS credentials from the input certificate file for client.
193// serverNameOverride is for testing only. If set to a non empty string,
194// it will override the virtual host name of authority (e.g. :authority header field) in requests.
195func NewClientTLSFromFile(certFile, serverNameOverride string) (TransportCredentials, error) {
196 b, err := ioutil.ReadFile(certFile)
197 if err != nil {
198 return nil, err
199 }
200 cp := x509.NewCertPool()
201 if !cp.AppendCertsFromPEM(b) {
202 return nil, fmt.Errorf("credentials: failed to append certificates")
203 }
204 return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}), nil
205}
206
207// NewServerTLSFromCert constructs TLS credentials from the input certificate for server.
208func NewServerTLSFromCert(cert *tls.Certificate) TransportCredentials {
209 return NewTLS(&tls.Config{Certificates: []tls.Certificate{*cert}})
210}
211
212// NewServerTLSFromFile constructs TLS credentials from the input certificate file and key
213// file for server.
214func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error) {
215 cert, err := tls.LoadX509KeyPair(certFile, keyFile)
216 if err != nil {
217 return nil, err
218 }
219 return NewTLS(&tls.Config{Certificates: []tls.Certificate{cert}}), nil
220}