Skip to content

sql: introduce SET ROLE #68973

Merged
craig[bot] merged 1 commit intocockroachdb:masterfrom
otan-cockroach:simulate_set_role
Aug 24, 2021
Merged

sql: introduce SET ROLE #68973
craig[bot] merged 1 commit intocockroachdb:masterfrom
otan-cockroach:simulate_set_role

Conversation

@otan
Copy link
Copy Markdown
Contributor

@otan otan commented Aug 16, 2021

Release justification: low risk, high reward change

Release note (sql change): This commit introduces SET ROLE, which
allows users with certain permissions to assume the identity of another
user. It is worth noting that due to cross-version compatibility,
session_user will always return the same as current_user until
v22.1. Instead, use session_user() if you require this information.

Resolves #15005

@otan otan requested a review from rafiss August 16, 2021 05:44
@cockroach-teamcity
Copy link
Copy Markdown
Member

This change is Reviewable

@otan
Copy link
Copy Markdown
Contributor Author

otan commented Aug 17, 2021

hmm, i have the permissions checks for these all wrong. will fix it later.

it is fixed!

@otan otan force-pushed the simulate_set_role branch 2 times, most recently from 1fd2a9b to eef2d9b Compare August 18, 2021 03:44
@otan otan marked this pull request as ready for review August 18, 2021 03:47
@otan otan requested a review from a team August 18, 2021 03:47
@otan
Copy link
Copy Markdown
Contributor Author

otan commented Aug 18, 2021

this is good to review.

@otan otan force-pushed the simulate_set_role branch from eef2d9b to d46cae0 Compare August 18, 2021 04:08
Copy link
Copy Markdown
Collaborator

@rafiss rafiss left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @otan)


pkg/sql/exec_util.go, line 2422 at r3 (raw file):

}

func (m *sessionDataMutator) SetRole(ctx context.Context, pc permissionsChecker, s string) error {

can s be a security.SQLUsername so that it's normalzed earlier?

specifically, what happens if the value of s is NoNe? the if s == security.NoneRole check will fail it seems


pkg/sql/exec_util.go, line 2454 at r3 (raw file):

		if !exists {
			return pgerror.Newf(
				pgcode.UndefinedObject,

postgres returns InvalidParameterValue for this


pkg/sql/vars.go, line 1000 at r3 (raw file):

	},

	// See https://www.postgresql.org/docs/current/sql-set-role.html.

do you think we should modify the SetVar formatting logic so that it capitalizes ROLE? if so, add a ParseDataDriven test

also, just curious about the decision to implement this as a session variable rather than as a separate command (it seems Postgres has a separate SET ROLE command?)


pkg/sql/vars.go, line 1001 at r3 (raw file):

	// See https://www.postgresql.org/docs/current/sql-set-role.html.
	`role`: {

could you add role as one of the variables disallowed to be configured using ALTER ROLE ... SET

here:

// The "database" setting can't be configured here, since the
// default settings are stored per-database.
if varName == "database" {
return unknown, "", sessionVar{}, nil, newCannotChangeParameterError(varName)
}


pkg/sql/logictest/testdata/logic_test/set_role, line 200 at r3 (raw file):

# Revoke admin but give testuser privileges for testuser2.
# Make a testrole role.
# Check testuser2 can become testuser and testrole as they are still

maybe too edge casey to worry about ... but what happens if user_a is an admin, then becomes user_b, and then admin is revoked from user_a. i'm guessing PG doesn't auto-undo the SET ROLE? but then at this point can you still do SET ROLE user_a` successfully?

@otan otan force-pushed the simulate_set_role branch from d46cae0 to 6e1ace7 Compare August 19, 2021 23:37
@otan otan requested a review from a team August 19, 2021 23:37
Copy link
Copy Markdown
Contributor Author

@otan otan left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rafiss)


pkg/sql/exec_util.go, line 2422 at r3 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

can s be a security.SQLUsername so that it's normalzed earlier?

specifically, what happens if the value of s is NoNe? the if s == security.NoneRole check will fail it seems

Done.


pkg/sql/exec_util.go, line 2454 at r3 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

postgres returns InvalidParameterValue for this

Done.


pkg/sql/vars.go, line 1000 at r3 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

do you think we should modify the SetVar formatting logic so that it capitalizes ROLE? if so, add a ParseDataDriven test

also, just curious about the decision to implement this as a session variable rather than as a separate command (it seems Postgres has a separate SET ROLE command?)

i'm not sure it does.
i don't think postgres has a separate SET ROLE command, it treats it like a var.


pkg/sql/vars.go, line 1001 at r3 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

could you add role as one of the variables disallowed to be configured using ALTER ROLE ... SET

here:

// The "database" setting can't be configured here, since the
// default settings are stored per-database.
if varName == "database" {
return unknown, "", sessionVar{}, nil, newCannotChangeParameterError(varName)
}

Done.


pkg/sql/logictest/testdata/logic_test/set_role, line 200 at r3 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

maybe too edge casey to worry about ... but what happens if user_a is an admin, then becomes user_b, and then admin is revoked from user_a. i'm guessing PG doesn't auto-undo the SET ROLE? but then at this point can you still do SET ROLE user_a` successfully?

just tested, pg doesn't reset the role, and you can no longer do set role user_a. added a test.

Copy link
Copy Markdown
Contributor

@ajwerner ajwerner left a comment

Choose a reason for hiding this comment

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

Nothing major from me.

Reviewed 2 of 5 files at r2, 1 of 16 files at r3, 1 of 5 files at r4.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @otan and @rafiss)


pkg/sql/exec_util.go, line 2422 at r4 (raw file):

}

func (m *sessionDataMutator) SetRole(

Could I request some commentary here that talks about the SessionUserProto and its relationship to UserProto?


pkg/sql/exec_util.go, line 2502 at r4 (raw file):


	if sessionUser.IsRootUser() {

does this let you become node? That thing is more powerful than root. I'm not sure how I feel about making it easy for root to become node.


pkg/sql/vars.go, line 59 at r4 (raw file):

// permissionsCheck contains permissions checks which are needed for SET ROLE.
type permissionsChecker interface {
	MemberOfWithAdminOption(

do y'all ever dream of package boundaries around these sorts of things?

@otan otan force-pushed the simulate_set_role branch 2 times, most recently from 1ff937b to 9cbf57b Compare August 20, 2021 01:50
Copy link
Copy Markdown
Contributor Author

@otan otan left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner and @rafiss)


pkg/sql/exec_util.go, line 2422 at r4 (raw file):

Previously, ajwerner wrote…

Could I request some commentary here that talks about the SessionUserProto and its relationship to UserProto?

added a comment here, the protobuf variable has more commentary.


pkg/sql/exec_util.go, line 2502 at r4 (raw file):

Previously, ajwerner wrote…

	if sessionUser.IsRootUser() {

does this let you become node? That thing is more powerful than root. I'm not sure how I feel about making it easy for root to become node.

does node exist? i don't see it in system.roles

root@127.0.0.1:26257/movr> set role node;
ERROR: role node does not exist
SQLSTATE: 22023

pkg/sql/vars.go, line 59 at r4 (raw file):

Previously, ajwerner wrote…
// permissionsCheck contains permissions checks which are needed for SET ROLE.
type permissionsChecker interface {
	MemberOfWithAdminOption(

do y'all ever dream of package boundaries around these sorts of things?

🙃

@otan otan force-pushed the simulate_set_role branch 3 times, most recently from 4b3031e to 88f8dfc Compare August 23, 2021 05:20
@otan
Copy link
Copy Markdown
Contributor Author

otan commented Aug 23, 2021

found a way of doing this without needing that new permissionsChecker interface.

@otan otan force-pushed the simulate_set_role branch from 88f8dfc to 8f99178 Compare August 23, 2021 08:16
Copy link
Copy Markdown
Collaborator

@rafiss rafiss left a comment

Choose a reason for hiding this comment

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

just a small comment but this looks good!

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner, @otan, and @rafiss)


pkg/sql/exec_util.go, line 2502 at r4 (raw file):

Previously, otan (Oliver Tan) wrote…

does node exist? i don't see it in system.roles

root@127.0.0.1:26257/movr> set role node;
ERROR: role node does not exist
SQLSTATE: 22023

node is a magic pseudo-role, and so is public.

const PublicRole = "public"

as long as the set role implementation works by consulting the system table, it wouldn't allow you to become those roles, but maybe worth adding a test or special-casing them.

Copy link
Copy Markdown
Collaborator

@rafiss rafiss left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @ajwerner, @otan, and @rafiss)


pkg/sql/vars.go, line 1000 at r3 (raw file):

Previously, otan (Oliver Tan) wrote…

i'm not sure it does.
i don't think postgres has a separate SET ROLE command, it treats it like a var.

i see. i just saw that it got its own page: https://www.postgresql.org/docs/current/sql-set-role.html

so from the parser perspective, i think it still would be useful to add a ParseDataDriven test for:

  • the ROLE token is capitalized
  • don't need a = or TO token in the SET ROLE username command

Copy link
Copy Markdown
Contributor

@ajwerner ajwerner left a comment

Choose a reason for hiding this comment

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

Commentary nits from me. Otherwise :lgtm:

Reviewed 3 of 27 files at r6, 2 of 14 files at r7, 1 of 1 files at r8, all commit messages.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @ajwerner, @otan, and @rafiss)


pkg/sql/user.go, line 461 at r8 (raw file):

	// Buffer the ParamStatusUpdate.
	updateStr := "off"
	willBecomeAdmin, err := p.UserHasAdminRole(ctx, becomeUser)

If we're already an admin, should we be sending this?


pkg/sql/user.go, line 470 at r8 (raw file):

	m.paramStatusUpdater.BufferParamStatusUpdate("is_superuser", updateStr)

	// The "none" user does a reset if we are in a SET ROLE.

Is this reset terminology defined anywhere? Could we make it a method on the sessionDataMutator and put some nice commentary on that method?


pkg/sql/user.go, line 478 at r8 (raw file):

		return nil
	}

Should we short-circuit in the case where we're becoming ourself?


pkg/sql/sessiondata/session_data.go, line 129 at r8 (raw file):

}

// SessionUser retrieves the session_user.

This feels like a nice place to reiterate the distinction between SessionUser and User.


pkg/sql/sessiondatapb/session_data.go, line 111 at r8 (raw file):

}

// User retrieves the current user.

Given this change, it's probably worth a sentence pointing out that SessionUser exists and is distinct from this user. I have a feeling that in general you want to use this and not that. Commenting both places with hints feels valuable.

Release justification: low risk, high reward change

Release note (sql change): This commit introduces `SET ROLE`, which
allows users with certain permissions to assume the identity of another
user. It is worth noting that due to cross-version compatibility,
`session_user` will always return the same as `current_user` until
v22.1. Instead, use `session_user()` if you require this information.
@otan otan force-pushed the simulate_set_role branch from 8f99178 to d32a845 Compare August 23, 2021 22:24
@otan
Copy link
Copy Markdown
Contributor Author

otan commented Aug 24, 2021

bors r=rafiss,ajwerner

@craig
Copy link
Copy Markdown
Contributor

craig bot commented Aug 24, 2021

Build succeeded:

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.

sql: enable changing the current user of a session with SET ROLE

4 participants