@@ -32,7 +32,7 @@ TPrivComparer = class(TComparer<TPrivObj>)
3232 TUserProblem = (upNone, upEmptyPassword, upInvalidPasswordLen, upSkipNameResolve, upUnknown);
3333
3434 TUser = class (TObject)
35- Username, Host, Password, Cipher, Issuer, Subject, DefaultRole: String;
35+ Username, Host, Password, Cipher, Issuer, Subject, DefaultRole, Plugin : String;
3636 MaxQueries, MaxUpdates, MaxConnections, MaxUserConnections, SSL: Integer;
3737 Problem: TUserProblem;
3838 IsRole: Boolean;
@@ -61,6 +61,8 @@ EInputError = class(Exception);
6161 TUserManagerForm = class (TExtForm)
6262 btnCancel: TButton;
6363 btnSave: TButton;
64+ comboPlugins: TComboBox;
65+ lblPlugin: TLabel;
6466 pnlLeft: TPanel;
6567 listUsers: TVirtualStringTree;
6668 Splitter1: TSplitter;
@@ -192,11 +194,14 @@ TUserManagerForm = class(TExtForm)
192194 FUsers: TUserList;
193195 FModified, FAdded: Boolean;
194196 FHasIsRole, FHasDefaultRole: Boolean;
197+ FHasPlugin: Boolean;
198+ FPlugins: TStringList;
195199 FCloneGrants: TStringList;
196200 FPrivObjects: TPrivObjList;
197201 FPrivsGlobal, FPrivsDb, FPrivsTable, FPrivsRoutine, FPrivsColumn: TStringList;
198202 FConnection: TDBConnection;
199203 FColorReadPriv, FColorWritePriv, FColorAdminPriv: TColor;
204+ FSQLPluginPrefix, FSQLPluginPassPrefix: String;
200205 procedure SetModified (Value : Boolean);
201206 property Modified: Boolean read FModified write SetModified;
202207 function GetPrivByNode (Node: PVirtualNode): TPrivObj;
@@ -265,10 +270,10 @@ procedure TUserManagerForm.FormShow(Sender: TObject);
265270 Version, i: Integer;
266271 Users: TDBQuery;
267272 U: TUser;
268- tmp, PasswordExpr, IsRoleExpr, DefaultRoleExpr: String;
273+ tmp, PasswordExpr, IsRoleExpr, DefaultRoleExpr, PluginExpr : String;
269274 SkipNameResolve,
270275 HasPassword, HasAuthString: Boolean;
271- PasswordLengthMatters: Boolean;
276+ PasswordLengthMatters, PasswordLengthValid : Boolean;
272277 UserTableColumns: TStringList;
273278
274279 function InitPrivList (Values: String): TStringList;
@@ -299,7 +304,8 @@ procedure TUserManagerForm.FormShow(Sender: TObject);
299304 FPrivsTable := InitPrivList(' ALTER,CREATE,DELETE,DROP,GRANT,INDEX' );
300305 FPrivsRoutine := InitPrivList(' GRANT' );
301306 FPrivsColumn := InitPrivList(' INSERT,SELECT,UPDATE,REFERENCES' );
302- PasswordLengthMatters := True;
307+ FSQLPluginPrefix := IfThen(FConnection.Parameters.IsMariaDB, ' VIA' , ' WITH' );
308+ FSQLPluginPassPrefix := IfThen(FConnection.Parameters.IsMariaDB, ' USING' , ' BY' );
303309
304310 if Version >= 40002 then begin
305311 FPrivsGlobal.Add(' REPLICATION CLIENT' );
@@ -332,11 +338,6 @@ procedure TUserManagerForm.FormShow(Sender: TObject);
332338 PrivsDb.Add('PROXY');
333339 end;
334340 }
335- if Version >= 80000 then begin
336- // MySQL 8 has predefined length of hashed passwords only with
337- // mysql_native_password plugin enabled users
338- PasswordLengthMatters := False;
339- end ;
340341 // See https://mariadb.com/kb/en/changes-improvements-in-mariadb-105/#privileges-made-more-granular
341342 if FConnection.Parameters.IsMariaDB then begin
342343 if Version > 100502 then begin
@@ -391,6 +392,7 @@ procedure TUserManagerForm.FormShow(Sender: TObject);
391392 HasAuthString := UserTableColumns.IndexOf(' authentication_string' ) > -1 ;
392393 FHasIsRole := UserTableColumns.IndexOf(' is_role' ) > -1 ;
393394 FHasDefaultRole := UserTableColumns.IndexOf(' default_role' ) > -1 ;
395+ FHasPlugin := UserTableColumns.IndexOf(' plugin' ) > -1 ;
394396 if HasPassword and (not HasAuthString) then
395397 PasswordExpr := ' password'
396398 else if (not HasPassword) and HasAuthString then
@@ -402,14 +404,20 @@ procedure TUserManagerForm.FormShow(Sender: TObject);
402404 PasswordExpr := PasswordExpr + ' AS ' + FConnection.QuoteIdent(' password' );
403405 IsRoleExpr := IfThen(FHasIsRole, ' is_role' , FConnection.EscapeString(' N' )+' AS is_role' );
404406 DefaultRoleExpr := IfThen(FHasDefaultRole, ' default_role' , FConnection.EscapeString(' ' )+' AS default_role' );
407+ PluginExpr := IfThen(FHasPlugin, ' plugin' , FConnection.EscapeString(' ' )+' AS plugin' );
408+ if FConnection.SqlProvider.Has(qGetAuthPlugins) then
409+ FPlugins := FConnection.GetCol(FConnection.SqlProvider.GetSql(qGetAuthPlugins))
410+ else
411+ FPlugins := TStringList.Create;
405412
406413 Users := FConnection.GetResults(
407414 ' SELECT ' +
408415 FConnection.QuoteIdent(' user' ) + ' , ' +
409416 FConnection.QuoteIdent(' host' ) + ' , ' +
410417 PasswordExpr + ' , ' +
411418 IsRoleExpr + ' , ' +
412- DefaultRoleExpr + ' ' +
419+ DefaultRoleExpr + ' , ' +
420+ PluginExpr + ' ' +
413421 ' FROM ' +FConnection.QuoteIdent(' mysql' )+' .' +FConnection.QuoteIdent(' user' )
414422 );
415423 FUsers := TUserList.Create(True);
@@ -421,11 +429,14 @@ procedure TUserManagerForm.FormShow(Sender: TObject);
421429 U.Password := Users.Col(' password' );
422430 U.IsRole := UpperCase(Users.Col(' is_role' )) = ' Y' ;
423431 U.DefaultRole := Users.Col(' default_role' );
432+ U.Plugin := Users.Col(' plugin' );
424433 U.Problem := upNone;
425434 if U.IsUser then begin
426435 if Length(U.Password) = 0 then
427436 U.Problem := upEmptyPassword;
428- if PasswordLengthMatters and (not (Length(U.Password) in [0 , 16 , 41 ])) then
437+ PasswordLengthMatters := ExecRegExpr(' (mysql_native_password|mysql_old_password)' , U.Plugin) or (not FHasPlugin);
438+ PasswordLengthValid := Byte(Length(U.Password)) in [0 , 16 , 41 ];
439+ if PasswordLengthMatters and (not PasswordLengthValid) then
429440 U.Problem := upInvalidPasswordLen
430441 else if SkipNameResolve and U.HostRequiresNameResolve then
431442 U.Problem := upSkipNameResolve;
@@ -594,26 +605,35 @@ procedure TUserManagerForm.listUsersFocusChanged(Sender: TBaseVirtualTree; Node:
594605 User := nil ;
595606 FPrivObjects.Clear;
596607 Caption := MainForm.actUserManager.Caption;
608+ // Credentials tab
597609 editUsername.Clear;
598610 editFromHost.Clear;
599611 editPassword.Clear;
600612 editPassword.TextHint := ' ' ;
601613 editRepeatPassword.Clear;
614+ comboPlugins.Items.Clear;
615+ comboPlugins.Items.Add(_(' None' ));
616+ comboPlugins.Items.AddStrings(FPlugins);
617+ comboPlugins.ItemIndex := 0 ;
602618 comboDefaultRole.Items.Clear;
603619 comboDefaultRole.Items.Add(_(' None' ));
604620 FUsers.GetRoleNames(comboDefaultRole.Items);
605621 comboDefaultRole.ItemIndex := 0 ;
622+ // Limitations tab
606623 udMaxQueries.Position := 0 ;
607624 udMaxUpdates.Position := 0 ;
608625 udMaxConnections.Position := 0 ;
609626 udMaxUserConnections.Position := 0 ;
627+ // SSL tab
610628 comboSSL.ItemIndex := 0 ;
611629 comboSSL.OnChange(Sender);
612630 editCipher.Clear;
613631 editIssuer.Clear;
614632 editSubject.Clear;
633+ // Page control
615634 tabPrivileges.Caption := _(' Privileges' );
616635 tabRoles.Caption := _(' Roles' );
636+
617637 // All possible quote chars, escaped for RegExpr. Todo: use in all relevant expressions.
618638 RxQuotes := ' [' +QuoteRegExprMetaChars(FConnection.QuoteChars + FConnection.StringQuoteChar)+' ]' ;
619639
@@ -627,6 +647,9 @@ procedure TUserManagerForm.listUsersFocusChanged(Sender: TBaseVirtualTree; Node:
627647 end ;
628648 editUsername.Text := User.Username;
629649 editFromHost.Text := User.Host;
650+ i := comboPlugins.Items.IndexOf(User.Plugin);
651+ if i > -1 then
652+ comboPlugins.ItemIndex := i;
630653 i := comboDefaultRole.Items.IndexOf(User.DefaultRole);
631654 if i > -1 then
632655 comboDefaultRole.ItemIndex := i;
@@ -872,6 +895,8 @@ procedure TUserManagerForm.listUsersFocusChanged(Sender: TBaseVirtualTree; Node:
872895 editPassword.Enabled := UserSelected and User.IsUser;
873896 lblRepeatPassword.Enabled := UserSelected and User.IsUser;
874897 editRepeatPassword.Enabled := UserSelected and User.IsUser;
898+ comboPlugins.Enabled := UserSelected and User.IsUser and FHasPlugin;
899+ lblPlugin.Enabled := comboPlugins.Enabled;
875900 comboDefaultRole.Enabled := UserSelected and User.IsUser and FHasDefaultRole;
876901 lblDefaultRole.Enabled := comboDefaultRole.Enabled;
877902 tabCredentials.Enabled := UserSelected;
@@ -945,6 +970,7 @@ procedure TUserManagerForm.listUsersGetText(Sender: TBaseVirtualTree; Node: PVir
945970 case Column of
946971 0 : CellText := User.Username;
947972 1 : CellText := User.Host;
973+ 2 : CellText := User.Plugin;
948974 end ;
949975end ;
950976
@@ -1371,13 +1397,18 @@ procedure TUserManagerForm.btnSaveClick(Sender: TObject);
13711397 // Create added user
13721398 PasswordSet := False;
13731399 if FAdded and (FConnection.ServerVersionInt >= 50002 ) then begin
1374- Create := ' CREATE USER ' +UserHost;
1400+ Create := ' CREATE USER ' +UserHost+ ' ' ;
13751401 if editPassword.Modified then begin
1402+ // Insert authentication plugin with minor MariaDB/MySQL difference
1403+ if comboPlugins.ItemIndex > 0 then
1404+ Create := Create + ' IDENTIFIED ' + FSQLPluginPrefix + ' ' + comboPlugins.Text+' ' + FSQLPluginPassPrefix + ' '
1405+ else
1406+ Create := Create + ' IDENTIFIED BY ' ;
13761407 // Add "PASSWORD" clause when it's a hash already
13771408 if (Copy(editPassword.Text, 1 , 1 ) = ' *' ) and (Length(editPassword.Text) = 41 ) then
1378- Create := Create + ' IDENTIFIED BY PASSWORD ' +FConnection.EscapeString(editPassword.Text)
1409+ Create := Create + ' PASSWORD ' +FConnection.EscapeString(editPassword.Text)
13791410 else
1380- Create := Create + ' IDENTIFIED BY ' + FConnection.EscapeString(editPassword.Text);
1411+ Create := Create + FConnection.EscapeString(editPassword.Text);
13811412 end ;
13821413 FConnection.Query(Create);
13831414 FConnection.ShowWarnings;
@@ -1445,6 +1476,12 @@ procedure TUserManagerForm.btnSaveClick(Sender: TObject);
14451476
14461477 // General user options
14471478 if (P.DBObj.NodeType = lntNone) and FocusedUser.IsUser then begin
1479+ // Plugin
1480+ if comboPlugins.ItemIndex > 0 then begin
1481+ FConnection.Query(' ALTER USER ' + UserHost + ' IDENTIFIED ' + FSQLPluginPrefix + ' ' + comboPlugins.Text);
1482+ FConnection.ShowWarnings;
1483+ end ;
1484+
14481485 // SSL
14491486 case comboSSL.ItemIndex of
14501487 1 : RequireClause := ' SSL' ;
@@ -1542,6 +1579,7 @@ procedure TUserManagerForm.btnSaveClick(Sender: TObject);
15421579 FocusedUser.Host := editFromHost.Text;
15431580 if editPassword.Modified then
15441581 FocusedUser.Password := editPassword.Text;
1582+ FocusedUser.Plugin := IfThen(comboPlugins.ItemIndex=0 , ' ' , comboPlugins.Text);
15451583 FocusedUser.DefaultRole := IfThen(comboDefaultRole.ItemIndex=0 , ' ' , comboDefaultRole.Text);
15461584 FocusedUser.SSL := comboSSL.ItemIndex;
15471585 FocusedUser.Cipher := editCipher.Text;
@@ -1782,7 +1820,9 @@ procedure TUser.ParseSettings(GrantOrCreate: String; Priv: TPrivObj);
17821820 rx: TRegExpr;
17831821 RequireClause, WithClause: String;
17841822begin
1785- // REQUIRE SSL X509 ISSUER '456' SUBJECT '789' CIPHER '123' NONE
1823+ // CREATE USER ...
1824+ // mysql: IDENTIFIED WITH 'mysql_native_password' AS '*23AE809DDACAF96AF0FD78ED04B6A265E05AA257' REQUIRE SSL X509 ISSUER '456' SUBJECT '789' CIPHER '123' NONE
1825+ // mariadb: IDENTIFIED BY PASSWORD '23AE809DDACAF96A';
17861826 rx := TRegExpr.Create;
17871827 rx.ModifierI := True;
17881828 rx.Expression := ' \sREQUIRE\s+(.+)' ;
0 commit comments