@@ -88,20 +88,50 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
8888 mc .writeTimeout = mc .cfg .WriteTimeout
8989
9090 // Reading Handshake Initialization Packet
91- cipher , err := mc .readInitPacket ()
91+ authPluginName , authData , err := mc .readInitPacket ()
9292 if err != nil {
9393 mc .cleanup ()
9494 return nil , err
9595 }
9696
97+ // save the old auth data in case the server
98+ // needs to use the old password scheme.
99+ oldCipher := make ([]byte , len (authData ))
100+ copy (oldCipher , authData )
101+
102+ // Handle pluggable authentication
103+ if authPluginName == "" {
104+ // assume that without a name, we are using
105+ // the default.
106+ authPluginName = defaultAuthPluginName
107+ }
108+
109+ var authPlugin AuthPlugin
110+ if apf , ok := authPluginFactories [authPluginName ]; ok {
111+ authPlugin = apf (mc .cfg )
112+ authData , err = authPlugin .Next (authData )
113+ if err != nil {
114+ return nil , err
115+ }
116+ } else {
117+ // we'll tell the server in response that we are switching to our
118+ // default plugin because we didn't recognize the one they sent us.
119+ authPluginName = defaultAuthPluginName
120+ authPlugin = authPluginFactories [authPluginName ](mc .cfg )
121+
122+ // zero-out the authData because the current authData was for
123+ // a plugin we don't know about.
124+ authData = make ([]byte , 0 )
125+ }
126+
97127 // Send Client Authentication Packet
98- if err = mc .writeAuthPacket (cipher ); err != nil {
128+ if err = mc .writeAuthPacket (authPluginName , authData ); err != nil {
99129 mc .cleanup ()
100130 return nil , err
101131 }
102132
103133 // Handle response to auth packet, switch methods if possible
104- if err = handleAuthResult (mc , cipher ); err != nil {
134+ if err = handleAuthResult (mc , authPlugin , oldCipher ); err != nil {
105135 // Authentication failed and MySQL has already closed the connection
106136 // (https://dev.mysql.com/doc/internals/en/authentication-fails.html).
107137 // Do not send COM_QUIT, just cleanup and return the error.
@@ -134,50 +164,6 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
134164 return mc , nil
135165}
136166
137- func handleAuthResult (mc * mysqlConn , oldCipher []byte ) error {
138- // Read Result Packet
139- cipher , err := mc .readResultOK ()
140- if err == nil {
141- return nil // auth successful
142- }
143-
144- if mc .cfg == nil {
145- return err // auth failed and retry not possible
146- }
147-
148- // Retry auth if configured to do so.
149- if mc .cfg .AllowOldPasswords && err == ErrOldPassword {
150- // Retry with old authentication method. Note: there are edge cases
151- // where this should work but doesn't; this is currently "wontfix":
152- // https://github.com/go-sql-driver/mysql/issues/184
153-
154- // If CLIENT_PLUGIN_AUTH capability is not supported, no new cipher is
155- // sent and we have to keep using the cipher sent in the init packet.
156- if cipher == nil {
157- cipher = oldCipher
158- }
159-
160- if err = mc .writeOldAuthPacket (cipher ); err != nil {
161- return err
162- }
163- _ , err = mc .readResultOK ()
164- } else if mc .cfg .AllowCleartextPasswords && err == ErrCleartextPassword {
165- // Retry with clear text password for
166- // http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html
167- // http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html
168- if err = mc .writeClearAuthPacket (); err != nil {
169- return err
170- }
171- _ , err = mc .readResultOK ()
172- } else if mc .cfg .AllowNativePasswords && err == ErrNativePassword {
173- if err = mc .writeNativeAuthPacket (cipher ); err != nil {
174- return err
175- }
176- _ , err = mc .readResultOK ()
177- }
178- return err
179- }
180-
181167func init () {
182168 sql .Register ("mysql" , & MySQLDriver {})
183169}
0 commit comments