mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-06 18:24:26 +08:00
Support GRANT .. REQUIRE syntax in user manager with a new "SSL options" tab. Fixes issue #2671.
This commit is contained in:
@ -161,7 +161,7 @@ const
|
|||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
NSUBEXP = 15; // max number of subexpression //###0.929
|
NSUBEXP = 30; // max number of subexpression //###0.929
|
||||||
// Cannot be more than NSUBEXPMAX
|
// Cannot be more than NSUBEXPMAX
|
||||||
// Be carefull - don't use values which overflow CLOSE opcode
|
// Be carefull - don't use values which overflow CLOSE opcode
|
||||||
// (in this case you'll get compiler erorr).
|
// (in this case you'll get compiler erorr).
|
||||||
|
@ -456,6 +456,89 @@ object UserManagerForm: TUserManagerForm
|
|||||||
Thousands = False
|
Thousands = False
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
object tabSSL: TTabSheet
|
||||||
|
Caption = 'SSL options'
|
||||||
|
ImageIndex = 2
|
||||||
|
DesignSize = (
|
||||||
|
278
|
||||||
|
117)
|
||||||
|
object lblCipher: TLabel
|
||||||
|
Left = 3
|
||||||
|
Top = 36
|
||||||
|
Width = 35
|
||||||
|
Height = 13
|
||||||
|
Caption = '&Cipher:'
|
||||||
|
FocusControl = editCipher
|
||||||
|
end
|
||||||
|
object lblIssuer: TLabel
|
||||||
|
Left = 3
|
||||||
|
Top = 62
|
||||||
|
Width = 34
|
||||||
|
Height = 13
|
||||||
|
Caption = '&Issuer:'
|
||||||
|
FocusControl = editIssuer
|
||||||
|
end
|
||||||
|
object lblSubject: TLabel
|
||||||
|
Left = 3
|
||||||
|
Top = 89
|
||||||
|
Width = 40
|
||||||
|
Height = 13
|
||||||
|
Caption = '&Subject:'
|
||||||
|
FocusControl = editSubject
|
||||||
|
end
|
||||||
|
object lblSSL: TLabel
|
||||||
|
Left = 3
|
||||||
|
Top = 9
|
||||||
|
Width = 61
|
||||||
|
Height = 13
|
||||||
|
Caption = '&Require SSL:'
|
||||||
|
end
|
||||||
|
object editCipher: TEdit
|
||||||
|
Left = 106
|
||||||
|
Top = 33
|
||||||
|
Width = 169
|
||||||
|
Height = 21
|
||||||
|
Anchors = [akLeft, akTop, akRight]
|
||||||
|
TabOrder = 1
|
||||||
|
Text = 'editCipher'
|
||||||
|
OnChange = Modification
|
||||||
|
end
|
||||||
|
object editIssuer: TEdit
|
||||||
|
Left = 106
|
||||||
|
Top = 59
|
||||||
|
Width = 169
|
||||||
|
Height = 21
|
||||||
|
Anchors = [akLeft, akTop, akRight]
|
||||||
|
TabOrder = 2
|
||||||
|
Text = 'editIssuer'
|
||||||
|
OnChange = Modification
|
||||||
|
end
|
||||||
|
object editSubject: TEdit
|
||||||
|
Left = 106
|
||||||
|
Top = 86
|
||||||
|
Width = 169
|
||||||
|
Height = 21
|
||||||
|
Anchors = [akLeft, akTop, akRight]
|
||||||
|
TabOrder = 3
|
||||||
|
Text = 'editSubject'
|
||||||
|
OnChange = Modification
|
||||||
|
end
|
||||||
|
object comboSSL: TComboBox
|
||||||
|
Left = 106
|
||||||
|
Top = 6
|
||||||
|
Width = 169
|
||||||
|
Height = 21
|
||||||
|
Style = csDropDownList
|
||||||
|
Anchors = [akLeft, akTop, akRight]
|
||||||
|
TabOrder = 0
|
||||||
|
OnChange = comboSSLChange
|
||||||
|
Items.Strings = (
|
||||||
|
'No SSL or X509 requirements'
|
||||||
|
'Only permit SSL-encrypted connections'
|
||||||
|
'X509 (certificate, issuer and subject do not matter)'
|
||||||
|
'Specify requirements...')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
object btnDiscard: TButton
|
object btnDiscard: TButton
|
||||||
|
@ -13,8 +13,8 @@ uses
|
|||||||
|
|
||||||
type
|
type
|
||||||
TUser = class(TObject)
|
TUser = class(TObject)
|
||||||
Username, Host, Password: String;
|
Username, Host, Password, Cipher, Issuer, Subject: String;
|
||||||
MaxQueries, MaxUpdates, MaxConnections, MaxUserConnections: Integer;
|
MaxQueries, MaxUpdates, MaxConnections, MaxUserConnections, SSL: Integer;
|
||||||
end;
|
end;
|
||||||
PUser = ^TUser;
|
PUser = ^TUser;
|
||||||
TUserList = TObjectList<TUser>;
|
TUserList = TObjectList<TUser>;
|
||||||
@ -94,6 +94,15 @@ type
|
|||||||
udMaxUpdates: TUpDown;
|
udMaxUpdates: TUpDown;
|
||||||
udMaxConnections: TUpDown;
|
udMaxConnections: TUpDown;
|
||||||
udMaxUserConnections: TUpDown;
|
udMaxUserConnections: TUpDown;
|
||||||
|
tabSSL: TTabSheet;
|
||||||
|
lblCipher: TLabel;
|
||||||
|
editCipher: TEdit;
|
||||||
|
lblIssuer: TLabel;
|
||||||
|
lblSubject: TLabel;
|
||||||
|
editIssuer: TEdit;
|
||||||
|
editSubject: TEdit;
|
||||||
|
comboSSL: TComboBox;
|
||||||
|
lblSSL: TLabel;
|
||||||
procedure FormCreate(Sender: TObject);
|
procedure FormCreate(Sender: TObject);
|
||||||
procedure FormDestroy(Sender: TObject);
|
procedure FormDestroy(Sender: TObject);
|
||||||
procedure FormShow(Sender: TObject);
|
procedure FormShow(Sender: TObject);
|
||||||
@ -139,6 +148,7 @@ type
|
|||||||
procedure editPasswordChange(Sender: TObject);
|
procedure editPasswordChange(Sender: TObject);
|
||||||
procedure listUsersHotChange(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode);
|
procedure listUsersHotChange(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode);
|
||||||
procedure udMaxQueriesClick(Sender: TObject; Button: TUDBtnType);
|
procedure udMaxQueriesClick(Sender: TObject; Button: TUDBtnType);
|
||||||
|
procedure comboSSLChange(Sender: TObject);
|
||||||
private
|
private
|
||||||
{ Private declarations }
|
{ Private declarations }
|
||||||
FUsers: TUserList;
|
FUsers: TUserList;
|
||||||
@ -427,7 +437,7 @@ procedure TUserManagerForm.listUsersFocusChanged(Sender: TBaseVirtualTree; Node:
|
|||||||
var
|
var
|
||||||
P, Ptmp, PCol: TPrivObj;
|
P, Ptmp, PCol: TPrivObj;
|
||||||
User: PUser;
|
User: PUser;
|
||||||
UserHost, WithClause: String;
|
UserHost, RequireClause, WithClause: String;
|
||||||
Grants, AllPNames, Cols: TStringList;
|
Grants, AllPNames, Cols: TStringList;
|
||||||
rxA, rxB: TRegExpr;
|
rxA, rxB: TRegExpr;
|
||||||
i, j: Integer;
|
i, j: Integer;
|
||||||
@ -446,6 +456,10 @@ begin
|
|||||||
udMaxUpdates.Position := 0;
|
udMaxUpdates.Position := 0;
|
||||||
udMaxConnections.Position := 0;
|
udMaxConnections.Position := 0;
|
||||||
udMaxUserConnections.Position := 0;
|
udMaxUserConnections.Position := 0;
|
||||||
|
comboSSL.ItemIndex := 0;
|
||||||
|
editCipher.Clear;
|
||||||
|
editIssuer.Clear;
|
||||||
|
editSubject.Clear;
|
||||||
|
|
||||||
if UserSelected then begin
|
if UserSelected then begin
|
||||||
User := Sender.GetNodeData(Node);
|
User := Sender.GetNodeData(Node);
|
||||||
@ -480,11 +494,11 @@ begin
|
|||||||
|
|
||||||
for i:=0 to Grants.Count-1 do begin
|
for i:=0 to Grants.Count-1 do begin
|
||||||
// Find selected priv objects via regular expression
|
// Find selected priv objects via regular expression
|
||||||
{ GRANT USAGE ON *.* TO 'newbie'@'%' IDENTIFIED BY PASSWORD '*99D8973ECC09819DF81624F051BFF4FC6695140B' WITH GRANT OPTION
|
{ GRANT USAGE ON *.* TO 'newbie'@'%' IDENTIFIED BY PASSWORD '*99D8973ECC09819DF81624F051BFF4FC6695140B' REQUIRE (NONE | ssl_option [[AND] ssl_option] ...) WITH GRANT OPTION
|
||||||
GRANT SELECT ON `avtoserver`.* TO 'newbie'@'%'
|
GRANT SELECT ON `avtoserver`.* TO 'newbie'@'%'
|
||||||
GRANT SELECT, SELECT (Enter (column) name), INSERT, INSERT (Enter (column) name), UPDATE, UPDATE (Enter (column) name), DELETE, CREATE ON `avtoserver`.`avtomodel` TO 'newbie'@'%'
|
GRANT SELECT, SELECT (Enter (column) name), INSERT, INSERT (Enter (column) name), UPDATE, UPDATE (Enter (column) name), DELETE, CREATE ON `avtoserver`.`avtomodel` TO 'newbie'@'%'
|
||||||
GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `pulle`.`f_procedure` TO 'newbie'@'%' }
|
GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `pulle`.`f_procedure` TO 'newbie'@'%' }
|
||||||
rxA.Expression := '^GRANT\s+(.+)\s+ON\s+((TABLE|FUNCTION|PROCEDURE)\s+)?`?([^`.]+)`?\.`?([^`]+)`?\s+TO\s+\S+(\s+IDENTIFIED\s+BY\s+(PASSWORD)?\s+''?([^'']+)''?)?(\s+WITH.+GRANT\s+OPTION)?(.*)$';
|
rxA.Expression := '^GRANT\s+(.+)\s+ON\s+((TABLE|FUNCTION|PROCEDURE)\s+)?`?([^`.]+)`?\.`?([^`]+)`?\s+TO\s+\S+(\s+IDENTIFIED\s+BY\s+(PASSWORD)?\s+''?([^'']+)''?)?(\s+REQUIRE\s+((NONE|SSL|X509|CIPHER|ISSUER|SUBJECT)(\s+''[^'']*'')?(\s+AND)?\s+)+)?(\s+WITH\s+GRANT\s+OPTION)?(.*)$';
|
||||||
if rxA.Exec(Grants[i]) then begin
|
if rxA.Exec(Grants[i]) then begin
|
||||||
P := TPrivObj.Create;
|
P := TPrivObj.Create;
|
||||||
P.GrantCode := Grants[i];
|
P.GrantCode := Grants[i];
|
||||||
@ -563,8 +577,40 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// REQUIRE SSL X509 ISSUER '456' SUBJECT '789' CIPHER '123' NONE
|
||||||
|
RequireClause := rxA.Match[9];
|
||||||
|
if RequireClause <> '' then begin
|
||||||
|
User.SSL := 0;
|
||||||
|
User.Cipher := '';
|
||||||
|
User.Issuer := '';
|
||||||
|
User.Subject := '';
|
||||||
|
rxB.Expression := '\bSSL\b';
|
||||||
|
if rxB.Exec(RequireClause) then
|
||||||
|
User.SSL := 1;
|
||||||
|
rxB.Expression := '\bX509\b';
|
||||||
|
if rxB.Exec(RequireClause) then
|
||||||
|
User.SSL := 2;
|
||||||
|
rxB.Expression := '\bCIPHER\s+''([^'']+)';
|
||||||
|
if rxB.Exec(RequireClause) then
|
||||||
|
User.Cipher := rxB.Match[1];
|
||||||
|
rxB.Expression := '\bISSUER\s+''([^'']+)';
|
||||||
|
if rxB.Exec(RequireClause) then
|
||||||
|
User.Issuer := rxB.Match[1];
|
||||||
|
rxB.Expression := '\bSUBJECT\s+''([^'']+)';
|
||||||
|
if rxB.Exec(RequireClause) then
|
||||||
|
User.Subject := rxB.Match[1];
|
||||||
|
if IsNotEmpty(User.Cipher) or IsNotEmpty(User.Issuer) or IsNotEmpty(User.Subject) then
|
||||||
|
User.SSL := 3;
|
||||||
|
comboSSL.ItemIndex := User.SSL;
|
||||||
|
comboSSL.OnChange(Sender);
|
||||||
|
editCipher.Text := User.Cipher;
|
||||||
|
editIssuer.Text := User.Issuer;
|
||||||
|
editSubject.Text := User.Subject;
|
||||||
|
end;
|
||||||
|
|
||||||
// WITH .. GRANT OPTION ?
|
// WITH .. GRANT OPTION ?
|
||||||
if rxA.Match[9] <> '' then
|
if rxA.Match[15] <> '' then
|
||||||
P.OrgPrivs.Add('GRANT');
|
P.OrgPrivs.Add('GRANT');
|
||||||
if (P.OrgPrivs.Count = 0) and (P.DBObj.NodeType = lntTable) then
|
if (P.OrgPrivs.Count = 0) and (P.DBObj.NodeType = lntTable) then
|
||||||
FPrivObjects.Remove(P);
|
FPrivObjects.Remove(P);
|
||||||
@ -573,24 +619,24 @@ begin
|
|||||||
// MAX_UPDATES_PER_HOUR 10
|
// MAX_UPDATES_PER_HOUR 10
|
||||||
// MAX_CONNECTIONS_PER_HOUR 5
|
// MAX_CONNECTIONS_PER_HOUR 5
|
||||||
// MAX_USER_CONNECTIONS 2;
|
// MAX_USER_CONNECTIONS 2;
|
||||||
WithClause := rxA.Match[10];
|
WithClause := rxA.Match[16];
|
||||||
if WithClause <> '' then begin
|
if WithClause <> '' then begin
|
||||||
User.MaxQueries := 0;
|
User.MaxQueries := 0;
|
||||||
User.MaxUpdates := 0;
|
User.MaxUpdates := 0;
|
||||||
User.MaxConnections := 0;
|
User.MaxConnections := 0;
|
||||||
User.MaxUserConnections := 0;
|
User.MaxUserConnections := 0;
|
||||||
rxA.Expression := '\bMAX_QUERIES_PER_HOUR\s+(\d+)\b';
|
rxB.Expression := '\bMAX_QUERIES_PER_HOUR\s+(\d+)\b';
|
||||||
if rxA.Exec(WithClause) then
|
if rxB.Exec(WithClause) then
|
||||||
User.MaxQueries := MakeInt(rxA.Match[1]);
|
User.MaxQueries := MakeInt(rxB.Match[1]);
|
||||||
rxA.Expression := '\bMAX_UPDATES_PER_HOUR\s+(\d+)\b';
|
rxB.Expression := '\bMAX_UPDATES_PER_HOUR\s+(\d+)\b';
|
||||||
if rxA.Exec(WithClause) then
|
if rxB.Exec(WithClause) then
|
||||||
User.MaxUpdates := MakeInt(rxA.Match[1]);
|
User.MaxUpdates := MakeInt(rxB.Match[1]);
|
||||||
rxA.Expression := '\bMAX_CONNECTIONS_PER_HOUR\s+(\d+)\b';
|
rxB.Expression := '\bMAX_CONNECTIONS_PER_HOUR\s+(\d+)\b';
|
||||||
if rxA.Exec(WithClause) then
|
if rxB.Exec(WithClause) then
|
||||||
User.MaxConnections := MakeInt(rxA.Match[1]);
|
User.MaxConnections := MakeInt(rxB.Match[1]);
|
||||||
rxA.Expression := '\bMAX_USER_CONNECTIONS\s+(\d+)\b';
|
rxB.Expression := '\bMAX_USER_CONNECTIONS\s+(\d+)\b';
|
||||||
if rxA.Exec(WithClause) then
|
if rxB.Exec(WithClause) then
|
||||||
User.MaxUserConnections := MakeInt(rxA.Match[1]);
|
User.MaxUserConnections := MakeInt(rxB.Match[1]);
|
||||||
udMaxQueries.Position := User.MaxQueries;
|
udMaxQueries.Position := User.MaxQueries;
|
||||||
udMaxUpdates.Position := User.MaxUpdates;
|
udMaxUpdates.Position := User.MaxUpdates;
|
||||||
udMaxConnections.Position := User.MaxConnections;
|
udMaxConnections.Position := User.MaxConnections;
|
||||||
@ -654,6 +700,9 @@ begin
|
|||||||
editMaxUserConnections.Enabled := lblMaxUserConnections.Enabled;
|
editMaxUserConnections.Enabled := lblMaxUserConnections.Enabled;
|
||||||
udMaxUserConnections.Enabled := lblMaxUserConnections.Enabled;
|
udMaxUserConnections.Enabled := lblMaxUserConnections.Enabled;
|
||||||
|
|
||||||
|
tabSSL.Enabled := UserSelected;
|
||||||
|
comboSSL.Enabled := UserSelected;
|
||||||
|
|
||||||
btnAddObject.Enabled := UserSelected;
|
btnAddObject.Enabled := UserSelected;
|
||||||
btnDeleteUser.Enabled := UserSelected;
|
btnDeleteUser.Enabled := UserSelected;
|
||||||
btnCloneUser.Enabled := UserSelected and (not FAdded);
|
btnCloneUser.Enabled := UserSelected and (not FAdded);
|
||||||
@ -998,7 +1047,7 @@ end;
|
|||||||
|
|
||||||
procedure TUserManagerForm.btnSaveClick(Sender: TObject);
|
procedure TUserManagerForm.btnSaveClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
UserHost, OrgUserHost, Create, Table, Revoke, Grant, OnObj: String;
|
UserHost, OrgUserHost, Create, Table, Revoke, Grant, OnObj, RequireClause: String;
|
||||||
User: TUser;
|
User: TUser;
|
||||||
FocusedUser: PUser;
|
FocusedUser: PUser;
|
||||||
Tables, WithClauses: TStringList;
|
Tables, WithClauses: TStringList;
|
||||||
@ -1094,6 +1143,24 @@ begin
|
|||||||
Grant := 'USAGE';
|
Grant := 'USAGE';
|
||||||
Grant := 'GRANT ' + Grant + ' ON ' + OnObj + ' TO ' + OrgUserHost;
|
Grant := 'GRANT ' + Grant + ' ON ' + OnObj + ' TO ' + OrgUserHost;
|
||||||
|
|
||||||
|
// SSL options
|
||||||
|
if P.DBObj.NodeType = lntNone then begin
|
||||||
|
RequireClause := ' REQUIRE ';
|
||||||
|
case comboSSL.ItemIndex of
|
||||||
|
0: RequireClause := RequireClause + 'NONE';
|
||||||
|
1: RequireClause := RequireClause + 'SSL';
|
||||||
|
2: RequireClause := RequireClause + 'X509';
|
||||||
|
3: RequireClause := RequireClause + 'CIPHER '+esc(editCipher.Text)+' ISSUER '+esc(editIssuer.Text)+' SUBJECT '+esc(editSubject.Text);
|
||||||
|
end;
|
||||||
|
if (FocusedUser.SSL = comboSSL.ItemIndex)
|
||||||
|
and (FocusedUser.Cipher = editCipher.Text)
|
||||||
|
and (FocusedUser.Issuer = editIssuer.Text)
|
||||||
|
and (FocusedUser.Subject = editSubject.Text)
|
||||||
|
then
|
||||||
|
RequireClause := '';
|
||||||
|
Grant := Grant + RequireClause;
|
||||||
|
end;
|
||||||
|
|
||||||
WithClauses := TStringList.Create;
|
WithClauses := TStringList.Create;
|
||||||
if P.AddedPrivs.IndexOf('GRANT') > -1 then
|
if P.AddedPrivs.IndexOf('GRANT') > -1 then
|
||||||
WithClauses.Add('GRANT OPTION');
|
WithClauses.Add('GRANT OPTION');
|
||||||
@ -1111,7 +1178,7 @@ begin
|
|||||||
if WithClauses.Count > 0 then
|
if WithClauses.Count > 0 then
|
||||||
Grant := Grant + ' WITH ' + ImplodeStr(' ', WithClauses);
|
Grant := Grant + ' WITH ' + ImplodeStr(' ', WithClauses);
|
||||||
|
|
||||||
if P.Added or (P.AddedPrivs.Count > 0) or (WithClauses.Count > 0) then
|
if P.Added or (P.AddedPrivs.Count > 0) or (WithClauses.Count > 0) or (RequireClause <> '') then
|
||||||
FConnection.Query(Grant);
|
FConnection.Query(Grant);
|
||||||
|
|
||||||
WithClauses.Free;
|
WithClauses.Free;
|
||||||
@ -1145,6 +1212,10 @@ begin
|
|||||||
FocusedUser.Host := editFromHost.Text;
|
FocusedUser.Host := editFromHost.Text;
|
||||||
if editPassword.Modified then
|
if editPassword.Modified then
|
||||||
FocusedUser.Password := editPassword.Text;
|
FocusedUser.Password := editPassword.Text;
|
||||||
|
FocusedUser.SSL := comboSSL.ItemIndex;
|
||||||
|
FocusedUser.Cipher := editCipher.Text;
|
||||||
|
FocusedUser.Issuer := editIssuer.Text;
|
||||||
|
FocusedUser.Subject := editSubject.Text;
|
||||||
listUsers.OnFocusChanged(listUsers, listUsers.FocusedNode, listUsers.FocusedColumn);
|
listUsers.OnFocusChanged(listUsers, listUsers.FocusedNode, listUsers.FocusedColumn);
|
||||||
except
|
except
|
||||||
on E:EDatabaseError do
|
on E:EDatabaseError do
|
||||||
@ -1156,6 +1227,19 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TUserManagerForm.comboSSLChange(Sender: TObject);
|
||||||
|
begin
|
||||||
|
// Enable custom SSL settings
|
||||||
|
lblCipher.Enabled := (comboSSL.ItemIndex = 3) and Assigned(listUsers.FocusedNode);
|
||||||
|
editCipher.Enabled := lblCipher.Enabled;
|
||||||
|
lblIssuer.Enabled := lblCipher.Enabled;
|
||||||
|
editIssuer.Enabled := lblCipher.Enabled;
|
||||||
|
lblSubject.Enabled := lblCipher.Enabled;
|
||||||
|
editSubject.Enabled := lblCipher.Enabled;
|
||||||
|
Modification(Sender);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TUserManagerForm.btnDeleteUserClick(Sender: TObject);
|
procedure TUserManagerForm.btnDeleteUserClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
UserHost: String;
|
UserHost: String;
|
||||||
|
Reference in New Issue
Block a user