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 #24872: Rework api authorization models #5669

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,8 @@ trait EndpointSchema {
// data container name: the expected object key in answer
def dataContainer: Option[String]

// any authorization that allows to access that API - by default, admin.write
def authz: List[AuthorizationType] = List(AuthorizationType.Administration.Write)
// any authorization that allows to access that API
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps add "Nil mean special any_righs, ie admin role, is needed"

def authz: List[AuthorizationType]
}

trait EndpointSchema0 extends EndpointSchema {
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ package com.normation.rudder.rest
import com.normation.rudder.AuthorizationType
import com.normation.rudder.Rights
import com.normation.rudder.Role
import com.normation.rudder.api.AclPathSegment
import com.normation.rudder.api.ApiAclElement
import com.normation.rudder.api.ApiAuthorization as ApiAuthz

Expand All @@ -61,6 +60,7 @@ class AuthorizationMappingListEndpoint(endpoints: List[EndpointSchema]) extends

override def mapAuthorization(authz: AuthorizationType): List[ApiAclElement] = {
acls.get(authz).getOrElse(Nil)

}
}

Expand All @@ -73,14 +73,17 @@ class ExtensibleAuthorizationApiMapping(base: List[AuthorizationApiMapping]) ext
private var mappers: List[AuthorizationApiMapping] = base

def addMapper(mapper: AuthorizationApiMapping): Unit = {
// no need to add again and again the default mapper - it's ok, we have it.
if (mapper != AuthorizationApiMapping.OnlyAdmin) {
mappers = mappers :+ mapper
}
mappers = mappers :+ mapper
}

override def mapAuthorization(authz: AuthorizationType): List[ApiAclElement] = {
mappers.flatMap(_.mapAuthorization(authz))
import AuthorizationType.*
authz match {
case NoRights => Nil
case AnyRights => ApiAuthz.allAuthz.acl
case _ =>
mappers.flatMap(_.mapAuthorization(authz))
}
}
}

Expand All @@ -89,148 +92,6 @@ object AuthorizationApiMapping {
def x: ApiAclElement = AuthzForApi(api)
}

/*
* A default mapping for "only 'all rights' (ie admin) can access it
*/
case object OnlyAdmin extends AuthorizationApiMapping {
override def mapAuthorization(authz: AuthorizationType): List[ApiAclElement] = Nil
}

/*
* The core authorization/api mapping, ie the authorization for Rudder
* default API.
*/
object Core extends AuthorizationApiMapping {

override def mapAuthorization(authz: AuthorizationType): List[ApiAclElement] = {
import AuthorizationType.*
// shorthand to get authz for a given api
authz match {
case NoRights => Nil
case AnyRights => ApiAuthz.allAuthz.acl
// Administration is Rudder setting

case Administration.Read =>
SettingsApi.GetAllSettings.x :: SettingsApi.GetSetting.x :: SystemApi.ArchivesDirectivesList.x ::
SystemApi.ArchivesFullList.x :: SystemApi.ArchivesGroupsList.x :: SystemApi.ArchivesRulesList.x ::
SystemApi.GetAllZipArchive.x :: SystemApi.GetDirectivesZipArchive.x :: SystemApi.GetGroupsZipArchive.x ::
SystemApi.GetRulesZipArchive.x :: SystemApi.Info.x :: SystemApi.Status.x :: SystemApi.ArchivesParametersList.x ::
SystemApi.GetParametersZipArchive.x :: SystemApi.GetHealthcheckResult.x :: PluginApi.GetPluginsSettings.x ::
SettingsApi.GetAllowedNetworks.x :: SettingsApi.GetAllAllowedNetworks.x :: HookApi.GetHooks.x :: InfoApi.endpoints.map(
_.x
)
case Administration.Write =>
PluginApi.UpdatePluginsSettings.x :: SettingsApi.ModifySettings.x :: SettingsApi.ModifySetting.x ::
InventoryApi.FileWatcherRestart.x :: InventoryApi.FileWatcherStart.x :: InventoryApi.FileWatcherStop.x ::
NodeApi.CreateNodes.x :: SystemApi.endpoints.map(_.x)
case Administration.Edit =>
PluginApi.UpdatePluginsSettings.x :: SettingsApi.ModifySettings.x :: SettingsApi.ModifySetting.x ::
SettingsApi.ModifyAllowedNetworks.x :: SettingsApi.ModifyDiffAllowedNetworks.x ::
Nil

case Compliance.Read =>
ComplianceApi.GetGlobalCompliance.x :: ComplianceApi.GetRulesCompliance.x :: ComplianceApi.GetRulesComplianceId.x ::
ComplianceApi.GetNodesCompliance.x :: ComplianceApi.GetNodeComplianceId.x :: ChangesApi.GetRuleRepairedReports.x ::
ChangesApi.GetRecentChanges.x :: ComplianceApi.GetDirectiveComplianceId.x :: ComplianceApi.GetNodeSystemCompliance.x ::
ComplianceApi.GetDirectivesCompliance.x :: ComplianceApi.GetNodeGroupComplianceId.x :: ComplianceApi.GetNodeGroupComplianceTargetId.x ::
ComplianceApi.GetNodeGroupComplianceSummary.x :: Nil
case Compliance.Write => Nil
case Compliance.Edit => Nil

case Configuration.Read =>
(Parameter.Read :: Technique.Read :: Directive.Read :: Rule.Read :: Nil).flatMap(c => mapAuthorization(c))
case Configuration.Write =>
(Parameter.Write :: Technique.Write :: Directive.Write :: Rule.Write :: Nil).flatMap(c => mapAuthorization(c))
case Configuration.Edit =>
(Parameter.Edit :: Technique.Edit :: Directive.Edit :: Rule.Edit :: Nil).flatMap(c => mapAuthorization(c))

case Deployment.Read => Nil
case Deployment.Write => Nil
case Deployment.Edit => Nil

case Deployer.Read => Nil // ChangeRequestApi.ListChangeRequests.x :: ChangeRequestApi.ChangeRequestsDetails.x :: Nil
case Deployer.Write => Nil // ChangeRequestApi.DeclineRequestsDetails.x :: ChangeRequestApi.AcceptRequestsDetails.x :: Nil
case Deployer.Edit => Nil // ChangeRequestApi.UpdateRequestsDetails.x :: Nil

case Parameter.Read => ParameterApi.ListParameters.x :: ParameterApi.ParameterDetails.x :: Nil
case Parameter.Write => ParameterApi.CreateParameter.x :: ParameterApi.DeleteParameter.x :: Nil
case Parameter.Edit => ParameterApi.UpdateParameter.x :: Nil

case Directive.Read =>
DirectiveApi.ListDirectives.x :: DirectiveApi.DirectiveDetails.x ::
DirectiveApi.DirectiveTree.x :: DirectiveApi.DirectiveRevisions.x ::
Nil
case Directive.Write =>
DirectiveApi.CreateDirective.x :: DirectiveApi.DeleteDirective.x ::
DirectiveApi.CheckDirective.x :: Nil
case Directive.Edit => DirectiveApi.UpdateDirective.x :: Nil

case Group.Read =>
GroupApi.ListGroups.x :: GroupApi.GroupDetails.x :: GroupApi.GetGroupTree.x ::
GroupApi.GetGroupCategoryDetails.x :: GroupApi.GroupInheritedProperties.x ::
NodeApi.NodeDetailsTable.x :: GroupApi.GroupDisplayInheritedProperties.x ::
GroupInternalApi.GetGroupCategoryTree.x :: Nil
case Group.Write =>
GroupApi.CreateGroup.x :: GroupApi.DeleteGroup.x :: GroupApi.ReloadGroup.x ::
GroupApi.DeleteGroupCategory.x :: GroupApi.CreateGroupCategory.x :: Nil
case Group.Edit => GroupApi.UpdateGroup.x :: GroupApi.UpdateGroupCategory.x :: Nil

case Node.Read =>
NodeApi.ListAcceptedNodes.x :: NodeApi.ListPendingNodes.x :: NodeApi.NodeDetails.x ::
NodeApi.NodeInheritedProperties.x :: NodeApi.NodeDisplayInheritedProperties.x :: NodeApi.NodeDetailsTable.x ::
NodeApi.PendingNodeDetails.x :: NodeApi.NodeDetailsSoftware.x :: NodeApi.NodeDetailsProperty.x ::
NodeApi.GetNodesStatus.x :: InventoryApi.QueueInformation.x ::
NodeApi.NodeGlobalScore.x :: NodeApi.NodeScoreDetail.x :: NodeApi.NodeScoreDetails.x ::
NodeApi.GetNodesStatus.x ::
// score about node
NodeApi.NodeGlobalScore.x :: NodeApi.NodeScoreDetails.x :: NodeApi.NodeScoreDetail.x ::
InventoryApi.QueueInformation.x ::
// node read also allows to read some settings
AuthzForApi.withValues(SettingsApi.GetSetting, AclPathSegment.Segment("global_policy_mode") :: Nil) ::
AuthzForApi.withValues(SettingsApi.GetSetting, AclPathSegment.Segment("global_policy_mode_overridable") :: Nil) ::
ScoreApi.GetScoreList.x ::
Nil
case Node.Write =>
NodeApi.DeleteNode.x :: NodeApi.ChangePendingNodeStatus.x :: NodeApi.ChangePendingNodeStatus2.x ::
NodeApi.ApplyPolicyAllNodes.x :: NodeApi.ApplyPolicy.x :: Nil
case Node.Edit => NodeApi.UpdateNode.x :: InventoryApi.UploadInventory.x :: Nil

case Rule.Read =>
RuleApi.ListRules.x :: RuleApi.RuleDetails.x :: RuleApi.GetRuleTree.x ::
RuleApi.GetRuleCategoryDetails.x :: RuleInternalApi.GetRuleNodesAndDirectives.x ::
RuleInternalApi.GetGroupRelatedRules.x ::
Nil
case Rule.Write =>
RuleApi.CreateRule.x :: RuleApi.DeleteRule.x :: RuleApi.CreateRuleCategory.x ::
RuleApi.DeleteRuleCategory.x :: RuleApi.LoadRuleRevisionForGeneration.x :: RuleApi.UnloadRuleRevisionForGeneration.x ::
Nil
case Rule.Edit => RuleApi.UpdateRule.x :: RuleApi.UpdateRuleCategory.x :: Nil

case Technique.Read =>
TechniqueApi.ListTechniques.x :: TechniqueApi.ListTechniquesDirectives.x ::
TechniqueApi.ListTechniqueDirectives.x :: TechniqueApi.TechniqueRevisions.x ::
TechniqueApi.GetMethods.x :: TechniqueApi.GetTechniques.x ::
TechniqueApi.GetAllTechniqueCategories.x :: TechniqueApi.GetResources.x :: TechniqueApi.GetNewResources.x ::
TechniqueApi.GetTechniqueAllVersion.x :: TechniqueApi.GetTechnique.x :: Nil
case Technique.Write =>
TechniqueApi.CreateTechnique.x :: SystemApi.PoliciesUpdate.x :: SystemApi.PoliciesRegenerate.x ::
TechniqueApi.DeleteTechnique.x :: Nil
case Technique.Edit =>
TechniqueApi.UpdateTechnique.x :: SystemApi.PoliciesUpdate.x :: SystemApi.PoliciesRegenerate.x ::
TechniqueApi.UpdateTechniques.x :: TechniqueApi.UpdateMethods.x :: Nil

case UserAccount.Read => UserApi.GetApiToken.x :: Nil
case UserAccount.Write => UserApi.CreateApiToken.x :: UserApi.DeleteApiToken.x :: Nil
case UserAccount.Edit => UserApi.UpdateApiToken.x :: Nil

case Validator.Read => Nil // ChangeRequestApi.ListChangeRequests.x :: ChangeRequestApi.ChangeRequestsDetails.x :: Nil
case Validator.Write =>
Nil // ChangeRequestApi.DeclineRequestsDetails.x :: ChangeRequestApi.AcceptRequestsDetails.x :: Nil
case Validator.Edit => Nil // ChangeRequestApi.UpdateRequestsDetails.x :: Nil
case _ => Nil // Done within plugin
}
}
}
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ object UserManagementApi extends Enum[UserManagementApi] with ApiModuleProvider[
val z = implicitly[Line].value
val description = "Reload (read again rudder-users.xml and process result) information about registered users in Rudder"
val (action, path) = POST / "usermanagement" / "users" / "reload"

override def dataContainer: Option[String] = None
override def dataContainer: Option[String] = None
val authz: List[AuthorizationType] = AuthorizationType.UserAccount.Write :: Nil
}

final case object DeleteUser extends UserManagementApi with OneParam with StartsAtVersion10 {
Expand All @@ -138,6 +138,8 @@ object UserManagementApi extends Enum[UserManagementApi] with ApiModuleProvider[
val (action, path) = DELETE / "usermanagement" / "{username}"

override def dataContainer: Option[String] = None

val authz: List[AuthorizationType] = AuthorizationType.UserAccount.Write :: Nil
}

final case object AddUser extends UserManagementApi with ZeroParam with StartsAtVersion10 {
Expand All @@ -146,6 +148,8 @@ object UserManagementApi extends Enum[UserManagementApi] with ApiModuleProvider[
val (action, path) = POST / "usermanagement"

override def dataContainer: Option[String] = None

val authz: List[AuthorizationType] = AuthorizationType.UserAccount.Write :: Nil
}

final case object UpdateUser extends UserManagementApi with OneParam with StartsAtVersion10 {
Expand All @@ -154,6 +158,8 @@ object UserManagementApi extends Enum[UserManagementApi] with ApiModuleProvider[
val (action, path) = POST / "usermanagement" / "update" / "{username}"

override def dataContainer: Option[String] = None

val authz: List[AuthorizationType] = AuthorizationType.UserAccount.Write :: Nil
}

final case object UpdateUserInfo extends UserManagementApi with OneParam with StartsAtVersion10 {
Expand All @@ -162,6 +168,8 @@ object UserManagementApi extends Enum[UserManagementApi] with ApiModuleProvider[
val (action, path) = POST / "usermanagement" / "update" / "info" / "{username}"

override def dataContainer: Option[String] = None

val authz: List[AuthorizationType] = AuthorizationType.UserAccount.Write :: Nil
}

final case object ActivateUser extends UserManagementApi with OneParam with StartsAtVersion10 {
Expand All @@ -170,6 +178,8 @@ object UserManagementApi extends Enum[UserManagementApi] with ApiModuleProvider[
val (action, path) = PUT / "usermanagement" / "status" / "activate" / "{username}"

override def dataContainer: Option[String] = None

val authz: List[AuthorizationType] = AuthorizationType.UserAccount.Write :: Nil
}

final case object DisableUser extends UserManagementApi with OneParam with StartsAtVersion10 {
Expand All @@ -178,6 +188,8 @@ object UserManagementApi extends Enum[UserManagementApi] with ApiModuleProvider[
val (action, path) = PUT / "usermanagement" / "status" / "disable" / "{username}"

override def dataContainer: Option[String] = None

val authz: List[AuthorizationType] = AuthorizationType.UserAccount.Write :: Nil
}

final case object RoleCoverage extends UserManagementApi with OneParam with StartsAtVersion10 {
Expand All @@ -186,6 +198,8 @@ object UserManagementApi extends Enum[UserManagementApi] with ApiModuleProvider[
val (action, path) = POST / "usermanagement" / "coverage" / "{username}"

override def dataContainer: Option[String] = None

val authz: List[AuthorizationType] = AuthorizationType.UserAccount.Read :: Nil
}

def endpoints = values.toList.sortBy(_.z)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ import com.normation.rudder.repository.FullNodeGroupCategory
import com.normation.rudder.repository.RoNodeGroupRepository
import com.normation.rudder.repository.RoRuleRepository
import com.normation.rudder.repository.WoRuleRepository
import com.normation.rudder.rest.AuthorizationApiMapping
import com.normation.rudder.rest.ExtensibleAuthorizationApiMapping
import com.normation.rudder.rest.ProviderRoleExtension
import com.normation.rudder.rest.RoleApiMapping
import com.normation.rudder.rest.lift.ComplianceAPIService
Expand Down Expand Up @@ -858,7 +858,7 @@ class MockUserManagement(userInfos: List[UserInfo], userSessions: List[UserSessi
val userService: FileUserDetailListProvider = {
val usersFile = UserFile("test-users.xml", usersInputStream)

val roleApiMapping = new RoleApiMapping(AuthorizationApiMapping.Core)
val roleApiMapping = new RoleApiMapping(new ExtensibleAuthorizationApiMapping(Nil))

val res = new FileUserDetailListProvider(roleApiMapping, usersFile)
res.reload()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -955,7 +955,7 @@ class RestTestSetUp {
mockUserManagement.userRepo,
mockUserManagement.userService,
mockUserManagement.userManagementService,
new RoleApiMapping(new ExtensibleAuthorizationApiMapping(AuthorizationApiMapping.Core :: Nil)),
new RoleApiMapping(new ExtensibleAuthorizationApiMapping(Nil)),
() => mockUserManagement.providerRoleExtension,
() => mockUserManagement.authBackendProviders
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import com.normation.rudder.domain.logger.ApplicationLogger
import com.normation.rudder.domain.logger.ApplicationLoggerPure
import com.normation.rudder.domain.logger.PluginLogger
import com.normation.rudder.rest.ApiModuleProvider
import com.normation.rudder.rest.AuthorizationMappingListEndpoint
import com.normation.rudder.rest.EndpointSchema
import com.normation.rudder.rest.InfoApi as InfoApiDef
import com.normation.rudder.rest.lift.InfoApi
Expand Down Expand Up @@ -534,13 +535,15 @@ class Boot extends Loggable {
LiftRules.statelessDispatch.append(RudderConfig.eventLogApi)
// REST API (all public/internal API)
// we need to add "info" API here to have all used API (even plugins)
val infoApi = {
val infoApi = {
// all used api - add info as it is not yet declared
val schemas = RudderConfig.rudderApi.apis().map(_.schema) ++ InfoApiDef.endpoints
val endpoints = schemas.flatMap(RudderConfig.apiDispatcher.withVersion(_, RudderConfig.ApiVersions))
new InfoApi(RudderConfig.restExtractorService, RudderConfig.ApiVersions, endpoints)
}
RudderConfig.rudderApi.addModules(infoApi.getLiftEndpoints())
val apiRoleMapper = new AuthorizationMappingListEndpoint(RudderConfig.rudderApi.apis().map(_.schema))
RudderConfig.authorizationApiMapping.addMapper(apiRoleMapper)
LiftRules.statelessDispatch.append(RudderConfig.rudderApi.getLiftRestApi())

// URL rewrites
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1515,7 +1515,7 @@ object RudderConfigInit {
lazy val authenticationProviders = new AuthBackendProvidersManager()

// Plugin input interface for Authorization for API
lazy val authorizationApiMapping = new ExtensibleAuthorizationApiMapping(AuthorizationApiMapping.Core :: Nil)
lazy val authorizationApiMapping = new ExtensibleAuthorizationApiMapping(Nil)

////////// end pluggable service providers //////////

Expand Down