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

Fixes #22349: Update user plugin to manage update custom roles #536

Conversation

fanf
Copy link
Member

@fanf fanf commented Feb 8, 2023

https://issues.rudder.io/issues/22349

There is a lot of things to change in the way that plugin works, but in that PR I limited to what is the minimum to make it compatible with Rudder 7.3 changes + an auto-backup of rudder-user.xml file in case of problem - because we didn't have anything for that, and it would make rudder broken.

So, the changes related to API changes in core are:

  • reflect name changes from rudder (RudderRoles)
  • update function from Box to ZIO (reflecting changes in backend + general direction of where we are going)

Other changes that were needed:

  • add a backup/rollback logic if something goes badly when writting the new rudder-users.xml file. At least, let the user know that he is not hopeless.
  • remove useless duplicate call to reload after each changes. The reload is done in back-end (no the responsibility of UI). I changed to call to getUserList to force refresh UI, which seemed to be the wanted logic, but even that should be removed: the API return of POST should send the wanted updated model, and UI just handle that, which will remove more useless roundtrip to backend.

What is not done but need to be done to have a "user management plugin with custom roles":

  • bare minimum: rework the role coverture logic to keep custom role. If the user is defined with some role, the plugin MUST NOT change them, it's only when the role are defined from authz from the UI
  • API need to be changed to use ZIO and our API tooling, which implies also changing JSON serialisation
  • add the possibility to define custom role if the extended authz plugin is there
  • a correct handling of errors from the UI side. We just get a blanck screen with a "error happened" notification, without any way for the user to know what to do. At least say "try to reload", or better handle the error correctly to let the user know things went wrongly, but we did what was needed which is XXX.

file <- getUserFilePath
parsedFile <- IOResult.attempt(ConstructingParser.fromFile(file.toJava, preserveWS = true))
userXML <- IOResult.attempt(parsedFile.document().children)
toUpdate = (userXML \\ "authentication").head
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this is needed

Copy link
Member Author

Choose a reason for hiding this comment

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

👍

@@ -105,23 +105,23 @@ update msg model =
AddUser result ->
case result of
Ok username ->
(model, postReloadConf model )
(model, getUsersConf model )
Copy link
Member Author

Choose a reason for hiding this comment

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

we don't need to ask for a reload, it's the role of the backend to ensure backend logic. In fact, the the API return value should be enough to update the UI as wanted.

@@ -56,15 +58,15 @@ object UserManagementLogger extends Logger {

object Serialisation {

implicit class AuthConfigSer(auth: UserDetailList) {
implicit class AuthConfigSer(auth: ValidatedUserList) {
Copy link
Member Author

Choose a reason for hiding this comment

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

changes in rudder core

def toJson: JValue = {
val encoder: String = PassEncoderToString(auth)
val authBackendsProvider = RudderConfig.authenticationProviders.getConfiguredProviders().map(_.name).toSet

val jUser = auth.users.map {
case (_, u) =>
val (rs, custom) = {
UserManagementService.computeRoleCoverage(Role.values, u.authz.authorizationTypes).getOrElse(Set.empty).partition {
UserManagementService.computeRoleCoverage(RudderRoles.getAllRoles.runNow.values.toSet, u.authz.authorizationTypes).getOrElse(Set.empty).partition {
Copy link
Member Author

Choose a reason for hiding this comment

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

need to ask for all roles including custom roles now

def compareRights(r: Role): Option[Role] = {
if (r.name == "no_rights") {
def compareRights(r: Role, as: Set[AuthorizationType]): Option[Role] = {
if (r == Role.NoRights) {
Copy link
Member Author

Choose a reason for hiding this comment

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

we have type, use them. We should not revert to string comparison appart for very good cases (check at system boudaries: parsing, serialisation, etc)

None
} else if (authzs.contains(AuthorizationType.AnyRights)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

missing that case, which is now necessary given changes in rudder core

Fixes #22349: Update user plugin to manage update custom roles
@fanf
Copy link
Member Author

fanf commented Feb 9, 2023

PR updated with a new commit

val resources: Either[UserConfigFileError, UserFile] = UserFileProcessing.getUserResourceFile()
resources match {
case Left(err) =>
Left(err)
Copy link
Member Author

Choose a reason for hiding this comment

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

when you see that you write case Left(err) => Left(err), you want to just map

case cr if cr == roleAuthzNames => Some(r)
case cr if cr.nonEmpty =>
val test = cr.flatMap(RoleToRights.parseAuthz)
if (test.isEmpty) {
Copy link
Member Author

Choose a reason for hiding this comment

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

test can't be empty, there is a check on that in the pattern match (not exactly, but there is no need to parse either, we just have to avoid to map(_.id) and remains with the types)

}
}
}

if (authzs.isEmpty || roles.isEmpty || authzs.exists(_.id == "no_rights")) {
if (authzs.isEmpty || roles.isEmpty || authzs.contains(AuthorizationType.NoRights)) {
Copy link
Member Author

Choose a reason for hiding this comment

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

keep the types! More info, more efficient, avoid useless parse/serialise roundtrip with errors to manage

…m roles

Fixes #22349: Update user plugin to manage update custom roles
@fanf
Copy link
Member Author

fanf commented Feb 9, 2023

PR updated with a new commit

}
computeRoleCoverage(Set(Role.User), Set(AuthorizationType.Compliance.Read)) must beEqualTo(
Some(Set(Role.forAuthz(AuthorizationType.Compliance.Read)))
)
Copy link
Member Author

Choose a reason for hiding this comment

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

Test need to be kept as small as possible, else the intent is lost. There is a lot of builtin comparators, use them

@VinceMacBuche VinceMacBuche changed the base branch from 7.3-next to branches/rudder/7.3 February 9, 2023 16:16
@VinceMacBuche VinceMacBuche merged commit ba35788 into Normation:branches/rudder/7.3 Feb 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants