Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for sys.server_permissions and sys.sql_logins views. #3538

Open
wants to merge 21 commits into
base: BABEL_5_X_DEV
Choose a base branch
from

Conversation

shreyeah38
Copy link
Contributor

Description

This PR adds full support for sys.server_permissions and sys.sql_logins views, addressing a current limitation in Babelfish. The implementation includes essential system views sys.server_permissions and sys.sql_logins required for comprehensive login export capabilities. This enhancement enables users to view server permissions and details about the logins in Babelfish, maintaining compatibility with TSQL Server syntax.

Added Components

Views:

sys.server_permissions: For managing server-level permissions
sys.sql_logins: For managing SQL Server authentication logins

BABEL-5654

Signed-off-by: Shreya Rai [email protected]

Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
@coveralls
Copy link
Collaborator

coveralls commented Feb 28, 2025

Pull Request Test Coverage Report for Build 13915600009

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • 729 unchanged lines in 4 files lost coverage.
  • Overall coverage increased (+0.009%) to 75.034%

Files with Coverage Reduction New Missed Lines %
contrib/babelfishpg_tsql/src/tsql_for/forjson.c 18 90.49%
contrib/babelfishpg_tsql/src/collation.c 147 72.9%
contrib/babelfishpg_tsql/src/pl_handler.c 212 90.34%
contrib/babelfishpg_tsql/src/tsqlIface.cpp 352 90.14%
Totals Coverage Status
Change from base Build 13793050061: 0.009%
Covered Lines: 47373
Relevant Lines: 63135

💛 - Coveralls

Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
WHERE datname = CURRENT_DATABASE() COLLATE sys.database_default
)
)
CROSS JOIN
Copy link
Contributor

@shalinilohia50 shalinilohia50 Mar 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These joins could be simplified as suggested offline.

Copy link
Contributor Author

@shreyeah38 shreyeah38 Mar 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will fix this in next commit.

Signed-off-by: Shreya Rai <[email protected]>
@@ -1,18 +1,22 @@
USE master
-- tsql
CREATE LOGIN sys_server_permissions_vu_login1 with password = '123'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add tests with window login.

CREATE LOGIN [ad\Aduser] from windows;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, adding.

OR pg_has_role(sys.suser_id(), 'securityadmin'::TEXT, 'MEMBER')
OR Ext.orig_loginname = sys.suser_name()
OR Ext.orig_loginname = (SELECT pg_get_userbyid(datdba) FROM pg_database WHERE datname = CURRENT_DATABASE()) COLLATE sys.database_default)
AND Ext.type IN ('S');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

 AND Ext.type = 'S';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll make these changes

Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
WHERE (pg_has_role(sys.suser_id(), 'sysadmin'::TEXT, 'MEMBER')
OR pg_has_role(sys.suser_id(), 'securityadmin'::TEXT, 'MEMBER')
OR Base.rolname = sys.suser_name() COLLATE sys.database_default
OR Base.rolname = Master.rolname)
Copy link
Contributor

@shalinilohia50 shalinilohia50 Mar 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

 OR Base.rolname = Master.rolname)

This means when grantee and grantor are same. Why is this check needed? Which case do we cover with this check?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CREATE OR REPLACE VIEW sys.server_permissions 
AS 
SELECT 
   CAST(100 AS sys.tinyint) AS class,
   CAST('SERVER' AS sys.nvarchar(60)) AS class_desc,
   CAST(0 AS int) AS major_id,
   CAST(0 AS int) AS minor_id,
   CAST(Base.oid AS INT) AS grantee_principal_id,
   CAST((SELECT oid FROM pg_catalog.pg_roles WHERE rolname = 
        (SELECT pg_get_userbyid(datdba) FROM pg_database WHERE datname = CURRENT_DATABASE())
   ) AS INT) AS grantor_principal_id,
   CAST('COSQ' AS sys.BPCHAR(4)) AS type,
   CAST('CONNECT SQL' AS sys.nvarchar(128)) AS permission_name,
   CAST('G' AS sys.BPCHAR(1)) AS state,
   CAST('GRANT' AS sys.nvarchar(60)) AS state_desc 
FROM pg_catalog.pg_roles AS Base 
INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname 
WHERE (pg_has_role(sys.suser_id(), 'sysadmin'::TEXT, 'MEMBER')
    OR pg_has_role(sys.suser_id(), 'securityadmin'::TEXT, 'MEMBER')
    OR Base.rolname = sys.suser_name() COLLATE sys.database_default 
    OR Base.rolname = (SELECT pg_get_userbyid(datdba) FROM pg_database WHERE datname = CURRENT_DATABASE()))

I think we can get rid of an INNER JOIN for Grantor information.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, fixed that.


-- tsql user=sys_sql_logins_vu_login1 password=123
SELECT * FROM dbo.sys_sql_logins_vu_prepare_view
GO
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests to check other columns of the view like is_policy_checked, is_expiration_checked etc.

SELECT * FROM sys_server_permissions_vu_prepare_view
GO
~~START~~
varchar#!#nvarchar#!#nvarchar#!#nvarchar
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add tests to cover all the columns in the view.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added few more columns in the test files.

Comment on lines 3346 to 3351
CASE
WHEN Ext.type = 'S' THEN 'SQL_LOGIN'
WHEN Ext.type = 'R' THEN 'SERVER_ROLE'
WHEN Ext.type = 'U' THEN 'WINDOWS_LOGIN'
ELSE NULL
END
Copy link
Contributor

@shalinilohia50 shalinilohia50 Mar 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a condition below AND Ext.type = 'S', so these cases are invalid. type_desc can only be SQL_LOGIN

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, fixed it.

Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
@@ -1,31 +1,99 @@
USE master
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reset the passoward of logins at the top.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

AS
SELECT
CAST(100 AS sys.tinyint) AS class,
CAST('SERVER' AS sys.nvarchar(60)) AS class_desc,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the value of class_desc is SERVER for windows logins as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

CAST(Ext.credential_id AS INT) AS credential_id,
CAST(
CASE
WHEN Ext.orig_loginname = (SELECT pg_get_userbyid(datdba) FROM pg_database WHERE datname = CURRENT_DATABASE()) COLLATE sys.database_default THEN 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repetitive call of SELECT pg_get_userbyid(datdba) FROM pg_database WHERE datname = CURRENT_DATABASE()) optimize it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made the required changes.

@@ -0,0 +1,51 @@
-- tsql
Copy link
Contributor

@anju15bharti anju15bharti Mar 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Add cases for scenarios where login is member of multiple fixed server roles for both the testfiles.
  2. Add negative testcases to show server roles are not being displayed in sql_logins view.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
Signed-off-by: Shreya Rai <[email protected]>
ELSE NULL
END
AS sys.varbinary(256)) AS password_hash
FROM sys.server_principals AS Base
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from performance pov I think we should not fetch columns from view server_principals rather it should be fetched from base catalog itself. Let's get @HarshLunagariya's opinion on this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please provide the execution plan for both variations for analyze?

CREATE OR REPLACE VIEW sys.server_permissions AS
WITH super_user AS (SELECT datdba AS super_user FROM pg_database WHERE datname = CURRENT_DATABASE())
SELECT
CAST(100 AS sys.tinyint) AS class,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When does it return 101 class id server permission?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100 = Server, 101 = Server-principal, 105 = Endpoint, 108 = Availability Group

CAST('COSQ' AS sys.BPCHAR(4)) AS type,
CAST('CONNECT SQL' AS sys.nvarchar(128)) AS permission_name,
CAST('G' AS sys.BPCHAR(1)) AS state,
CAST('GRANT' AS sys.nvarchar(60)) AS state_desc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For super_user, Shouldn't it show GRANT_WITH_GRANT_OPTION ? Since super_user can grant this privilege to others as per ideal T-SQL behaviour, Although we don't support it granting.

Copy link
Contributor Author

@shreyeah38 shreyeah38 Mar 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I compared it against TSQL behaviour, for super_user, it shows GRANT permission only.

WHERE(pg_has_role(sys.suser_id(), 'sysadmin'::TEXT, 'MEMBER')
OR pg_has_role(sys.suser_id(), 'securityadmin'::TEXT, 'MEMBER')
OR Base.rolname = sys.suser_name() COLLATE sys.database_default
OR Base.rolname = (SELECT pg_get_userbyid(super_user) FROM super_user))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need OR Base.rolname = (SELECT pg_get_userbyid(super_user) FROM super_user)) , if we have (pg_has_role(sys.suser_id(), 'sysadmin'::TEXT, 'MEMBER') already? Won't it cover super_user as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it doesn't, we have to use Base.rolname = (SELECT pg_get_userbyid(super_user) FROM super_user)

CAST('CO' AS sys.BPCHAR(4)) AS type,
CAST('CONNECT' AS sys.nvarchar(128)) AS permission_name,
CAST('G' AS sys.BPCHAR(1)) AS state,
CAST('GRANT' AS sys.nvarchar(60)) AS state_desc;
GRANT SELECT ON sys.server_permissions TO PUBLIC;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any other permission which needs to be supported? have we analysed all of them if they are supported in Babelfish?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since GRANT permission is not supported in Babelfish, I have only incorporated the default permissions which exist by default i.e. CONNECT SQL for each SQL and WINDOW logins and CONNECT for public via TSQL Default TCP endpoint.

WHERE(pg_has_role(sys.suser_id(), 'sysadmin'::TEXT, 'MEMBER')
OR pg_has_role(sys.suser_id(), 'securityadmin'::TEXT, 'MEMBER')
OR Base.name = sys.suser_name()
OR Base.name = (SELECT super_user FROM super_user))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as

Do we really need OR Base.rolname = (SELECT pg_get_userbyid(super_user) FROM super_user)) , if we have (pg_has_role(sys.suser_id(), 'sysadmin'::TEXT, 'MEMBER') already? Won't it cover super_user as well?

Comment on lines 3363 to 3368
CAST(
CASE
WHEN Base.name = (SELECT super_user FROM super_user) THEN 0
ELSE 1
END
AS sys.BIT) AS is_policy_checked,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just asking out of curiosity, Why does is_policy_checked column return 0 for superuser, Although password is checked for superuser as well.

Copy link
Contributor Author

@shreyeah38 shreyeah38 Mar 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is as per TSQL, is_policy_checked column returns 0 for superuser.

ELSE NULL
END
AS sys.varbinary(256)) AS password_hash
FROM sys.server_principals AS Base
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please provide the execution plan for both variations for analyze?

Signed-off-by: Shreya Rai <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants