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  }