vitess.io/vitess@v0.16.2/go/mysql/auth_server_clientcert.go (about) 1 /* 2 Copyright 2019 The Vitess 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 mysql 18 19 import ( 20 "fmt" 21 "net" 22 23 "github.com/spf13/pflag" 24 25 "vitess.io/vitess/go/vt/log" 26 "vitess.io/vitess/go/vt/servenv" 27 ) 28 29 var clientcertAuthMethod string 30 31 func init() { 32 servenv.OnParseFor("vtgate", func(fs *pflag.FlagSet) { 33 fs.StringVar(&clientcertAuthMethod, "mysql_clientcert_auth_method", string(MysqlClearPassword), "client-side authentication method to use. Supported values: mysql_clear_password, dialog.") 34 }) 35 } 36 37 // AuthServerClientCert implements AuthServer which enforces client side certificates 38 type AuthServerClientCert struct { 39 methods []AuthMethod 40 Method AuthMethodDescription 41 } 42 43 // InitAuthServerClientCert is public so it can be called from plugin_auth_clientcert.go (go/cmd/vtgate) 44 func InitAuthServerClientCert() { 45 if pflag.CommandLine.Lookup("mysql_server_ssl_ca").Value.String() == "" { 46 log.Info("Not configuring AuthServerClientCert because mysql_server_ssl_ca is empty") 47 return 48 } 49 if clientcertAuthMethod != string(MysqlClearPassword) && clientcertAuthMethod != string(MysqlDialog) { 50 log.Exitf("Invalid mysql_clientcert_auth_method value: only support mysql_clear_password or dialog") 51 } 52 53 ascc := newAuthServerClientCert() 54 RegisterAuthServer("clientcert", ascc) 55 } 56 57 func newAuthServerClientCert() *AuthServerClientCert { 58 ascc := &AuthServerClientCert{ 59 Method: AuthMethodDescription(clientcertAuthMethod), 60 } 61 62 var authMethod AuthMethod 63 switch AuthMethodDescription(clientcertAuthMethod) { 64 case MysqlClearPassword: 65 authMethod = NewMysqlClearAuthMethod(ascc, ascc) 66 case MysqlDialog: 67 authMethod = NewMysqlDialogAuthMethod(ascc, ascc, "") 68 default: 69 log.Exitf("Invalid mysql_clientcert_auth_method value: only support mysql_clear_password or dialog") 70 } 71 72 ascc.methods = []AuthMethod{authMethod} 73 return ascc 74 } 75 76 // AuthMethods returns the implement auth methods for the client 77 // certificate authentication setup. 78 func (asl *AuthServerClientCert) AuthMethods() []AuthMethod { 79 return asl.methods 80 } 81 82 // DefaultAuthMethodDescription returns always MysqlNativePassword 83 // for the client certificate authentication setup. 84 func (asl *AuthServerClientCert) DefaultAuthMethodDescription() AuthMethodDescription { 85 return MysqlNativePassword 86 } 87 88 // HandleUser is part of the UserValidator interface. We 89 // handle any user here since we don't check up front. 90 func (asl *AuthServerClientCert) HandleUser(user string) bool { 91 return true 92 } 93 94 // UserEntryWithPassword is part of the PlaintextStorage interface 95 func (asl *AuthServerClientCert) UserEntryWithPassword(conn *Conn, user string, password string, remoteAddr net.Addr) (Getter, error) { 96 userCerts := conn.GetTLSClientCerts() 97 if len(userCerts) == 0 { 98 return nil, fmt.Errorf("no client certs for connection") 99 } 100 commonName := userCerts[0].Subject.CommonName 101 102 if user != commonName { 103 return nil, fmt.Errorf("MySQL connection username '%v' does not match client cert common name '%v'", user, commonName) 104 } 105 106 return &StaticUserData{ 107 Username: commonName, 108 Groups: userCerts[0].DNSNames, 109 }, nil 110 }