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

[RORDEV-1388] New sytax of groups rules, refactor and common decoder #1080

Open
wants to merge 42 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
488e78e
draft
mgoworko Jan 19, 2025
b741ec3
draft
mgoworko Jan 19, 2025
986f057
draft
mgoworko Jan 22, 2025
849dc76
tests and mapping logic for negative rules
mgoworko Jan 23, 2025
993c759
tests and mapping logic for negative rules
mgoworko Jan 23, 2025
4a58069
refactor and logic fix
mgoworko Jan 25, 2025
64c335a
qs
mgoworko Jan 25, 2025
532ea44
Merge remote-tracking branch 'origin/develop' into feature/RORDEV-1268
mgoworko Jan 25, 2025
6fa55de
review changes
mgoworko Jan 27, 2025
c8d0b65
AI review changes
mgoworko Jan 27, 2025
30e6c36
review changes
mgoworko Jan 27, 2025
c38482c
review changes
mgoworko Jan 28, 2025
9df4752
review
coutoPL Jan 28, 2025
a6420bd
g3 group is not eligible, but the test passes
coutoPL Jan 28, 2025
097c000
draft of possible fix ?
mgoworko Jan 29, 2025
5171338
Added and refactored tests + fix applied to both groups mapping modes
mgoworko Jan 29, 2025
de93e02
msg
mgoworko Jan 29, 2025
5e36ab0
review changes
mgoworko Jan 30, 2025
508c78d
review changes
mgoworko Jan 30, 2025
f2d63d1
chnages propsition
coutoPL Jan 31, 2025
f4b916c
review changes
mgoworko Jan 31, 2025
7d97b39
Merge remote-tracking branch 'origin/develop' into feature/RORDEV-1268
mgoworko Feb 1, 2025
697957f
review changes
mgoworko Feb 1, 2025
c012e97
review changes
mgoworko Feb 2, 2025
98c94f9
review changes
mgoworko Feb 2, 2025
b75cba3
review changes
mgoworko Feb 3, 2025
2f1c32a
use new logic decoder for all types of rules and add tests
mgoworko Feb 5, 2025
d3130b4
extracted GroupsLogicDecoder, added tests
mgoworko Feb 6, 2025
fc4b965
refactor and added user_belongs_to_groups config section
mgoworko Feb 8, 2025
6ed3391
refactor and added user_belongs_to_groups config section
mgoworko Feb 8, 2025
ec6dcdb
generic decoder
mgoworko Feb 11, 2025
1c9fd79
generic decoder
mgoworko Feb 16, 2025
8659a43
Merge remote-tracking branch 'origin/develop' into feature/RORDEV-1388
mgoworko Feb 16, 2025
38bc390
merge fixes
mgoworko Feb 16, 2025
c6b4e5c
merge fixes
mgoworko Feb 16, 2025
8567266
merge fixes
mgoworko Feb 16, 2025
b4ee24d
tests of new config
mgoworko Feb 18, 2025
23e845b
tests
mgoworko Feb 20, 2025
3488f69
Merge remote-tracking branch 'origin/develop' into feature/RORDEV-1388
mgoworko Feb 20, 2025
1f8b29e
qs
mgoworko Feb 21, 2025
343f872
review changes
mgoworko Feb 23, 2025
a1bcf3f
fix
mgoworko Feb 23, 2025
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 @@ -23,7 +23,7 @@ import tech.beshu.ror.accesscontrol.blocks.BlockContextUpdater.*
import tech.beshu.ror.accesscontrol.blocks.metadata.UserMetadata
import tech.beshu.ror.accesscontrol.domain.*
import tech.beshu.ror.accesscontrol.domain.FieldLevelSecurity.RequestFieldsUsage
import tech.beshu.ror.accesscontrol.domain.GroupsLogic.{CombinedGroupsLogic, NegativeGroupsLogic, PositiveGroupsLogic}
import tech.beshu.ror.accesscontrol.domain.GroupsLogic.{Combined, NegativeGroupsLogic, PositiveGroupsLogic}
import tech.beshu.ror.accesscontrol.request.RequestContext
import tech.beshu.ror.syntax.*

Expand Down Expand Up @@ -54,7 +54,7 @@ sealed trait BlockContext {
true
case logic: PositiveGroupsLogic =>
isCurrentGroupEligible(logic.permittedGroupIds)
case logic: CombinedGroupsLogic =>
case logic: Combined =>
isCurrentGroupEligible(logic.positiveGroupsLogic.permittedGroupIds)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ import tech.beshu.ror.accesscontrol.blocks.rules.elasticsearch.indices.IndicesRu
import tech.beshu.ror.accesscontrol.blocks.rules.http.*
import tech.beshu.ror.accesscontrol.blocks.rules.kibana.*
import tech.beshu.ror.accesscontrol.blocks.rules.tranport.{HostsRule, LocalHostsRule}
import tech.beshu.ror.accesscontrol.domain.RequestId
import tech.beshu.ror.accesscontrol.domain.GroupsLogic.*
import tech.beshu.ror.accesscontrol.domain.{GroupsLogic, RequestId}
import tech.beshu.ror.implicits.*
import tech.beshu.ror.utils.RefinedUtils.*

Expand Down Expand Up @@ -130,10 +131,7 @@ object ImpersonationWarning {
}
} yield warning
)
implicit val groupsOrRule: ImpersonationWarningExtractor[GroupsOrRule] = noWarnings[GroupsOrRule]
implicit val groupsAndRule: ImpersonationWarningExtractor[GroupsAndRule] = noWarnings[GroupsAndRule]
implicit val groupsNotAllOfRule: ImpersonationWarningExtractor[GroupsNotAllOfRule] = noWarnings[GroupsNotAllOfRule]
implicit val groupsNotAnyOfRule: ImpersonationWarningExtractor[GroupsNotAnyOfRule] = noWarnings[GroupsNotAnyOfRule]
implicit def groupsRule[GL <: GroupsLogic]: ImpersonationWarningExtractor[GroupsRule[GL]] = noWarnings[GroupsRule[GL]]
implicit val jwtAuthRule: ImpersonationWarningExtractor[JwtAuthRule] = ImpersonationWarningExtractor[JwtAuthRule] { (rule, blockName, _) =>
Some(impersonationNotSupportedWarning(rule, blockName))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import tech.beshu.ror.accesscontrol.blocks.rules.elasticsearch.indices.*
import tech.beshu.ror.accesscontrol.blocks.rules.http.*
import tech.beshu.ror.accesscontrol.blocks.rules.kibana.*
import tech.beshu.ror.accesscontrol.blocks.rules.tranport.*
import tech.beshu.ror.accesscontrol.domain.GroupsLogic.*
import tech.beshu.ror.accesscontrol.orders.*

class RuleOrdering extends Ordering[Rule] with Logging {
Expand Down Expand Up @@ -65,8 +66,11 @@ object RuleOrdering {
classOf[LdapAuthRule],
classOf[LdapAuthenticationRule],
classOf[ExternalAuthenticationRule],
classOf[GroupsOrRule],
classOf[GroupsAndRule],
classOf[AnyOfGroupsRule],
classOf[AllOfGroupsRule],
classOf[NotAnyOfGroupsRule],
classOf[NotAllOfGroupsRule],
classOf[CombinedGroupsRule],
// all authorization rules should be placed after any authentication rule
classOf[LdapAuthorizationRule],
classOf[ExternalAuthorizationRule],
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import tech.beshu.ror.accesscontrol.blocks.definitions.UserDef
import tech.beshu.ror.accesscontrol.blocks.definitions.UserDef.Mode.WithGroupsMapping.Auth
import tech.beshu.ror.accesscontrol.blocks.definitions.UserDef.{GroupMappings, Mode}
import tech.beshu.ror.accesscontrol.blocks.rules.Rule
import tech.beshu.ror.accesscontrol.blocks.rules.Rule.*
import tech.beshu.ror.accesscontrol.blocks.rules.Rule.AuthenticationRule.EligibleUsersSupport
import tech.beshu.ror.accesscontrol.blocks.rules.Rule.RuleResult.{Fulfilled, Rejected}
import tech.beshu.ror.accesscontrol.blocks.rules.Rule.{AuthRule, AuthenticationRule, AuthorizationRule, RuleResult}
import tech.beshu.ror.accesscontrol.blocks.rules.auth.BaseGroupsRule.Settings
import tech.beshu.ror.accesscontrol.blocks.rules.auth.GroupsRule.Settings
import tech.beshu.ror.accesscontrol.blocks.rules.auth.base.impersonation.{AuthenticationImpersonationCustomSupport, AuthorizationImpersonationCustomSupport}
import tech.beshu.ror.accesscontrol.blocks.variables.runtime.RuntimeResolvableGroupsLogic
import tech.beshu.ror.accesscontrol.blocks.{BlockContext, BlockContextUpdater}
Expand All @@ -35,7 +35,29 @@ import tech.beshu.ror.accesscontrol.matchers.GenericPatternMatcher
import tech.beshu.ror.implicits.*
import tech.beshu.ror.utils.uniquelist.{UniqueList, UniqueNonEmptyList}

abstract class BaseGroupsRule[GL <: GroupsLogic](val settings: Settings[GL])
class AnyOfGroupsRule(override val name: Rule.Name, override val settings: Settings[GroupsLogic.AnyOf])
(override implicit val userIdCaseSensitivity: CaseSensitivity)
extends GroupsRule[GroupsLogic.AnyOf](name, settings)

class AllOfGroupsRule(override val name: Rule.Name, override val settings: Settings[GroupsLogic.AllOf])
(override implicit val userIdCaseSensitivity: CaseSensitivity)
extends GroupsRule[GroupsLogic.AllOf](name, settings)

class NotAnyOfGroupsRule(override val name: Rule.Name, override val settings: Settings[GroupsLogic.NotAnyOf])
(override implicit val userIdCaseSensitivity: CaseSensitivity)
extends GroupsRule[GroupsLogic.NotAnyOf](name, settings)

class NotAllOfGroupsRule(override val name: Rule.Name, override val settings: Settings[GroupsLogic.NotAllOf])
(override implicit val userIdCaseSensitivity: CaseSensitivity)
extends GroupsRule[GroupsLogic.NotAllOf](name, settings)

class CombinedGroupsRule(override val name: Rule.Name, override val settings: Settings[GroupsLogic.Combined])
(override implicit val userIdCaseSensitivity: CaseSensitivity)
extends GroupsRule[GroupsLogic.Combined](name, settings)

abstract class GroupsRule[+GL <: GroupsLogic](override val name: Rule.Name,
val settings: Settings[GL])
(override implicit val userIdCaseSensitivity: CaseSensitivity)
extends AuthRule
with AuthenticationImpersonationCustomSupport
with AuthorizationImpersonationCustomSupport
Expand Down Expand Up @@ -287,7 +309,29 @@ abstract class BaseGroupsRule[GL <: GroupsLogic](val settings: Settings[GL])
}
}

object BaseGroupsRule {
final case class Settings[GL <: GroupsLogic](permittedGroupsLogic: RuntimeResolvableGroupsLogic[GL],
usersDefinitions: NonEmptyList[UserDef])
object GroupsRule {

def name(ruleName: String): RuleName[GroupsRule[GroupsLogic]] = new RuleName[GroupsRule[GroupsLogic]] {
override val name: Rule.Name = Rule.Name(ruleName)
}

final case class Settings[+GL <: GroupsLogic](permittedGroupsLogic: RuntimeResolvableGroupsLogic[GL],
usersDefinitions: NonEmptyList[UserDef])

trait Creator[GL <: GroupsLogic] {
def create(name: Rule.Name,
settings: Settings[GL],
userIdCaseSensitivity: CaseSensitivity): GroupsRule[GL]
}

object Creator {
implicit val allOfTypeInfo: Creator[GroupsLogic.AllOf] = new AllOfGroupsRule(_, _)(_)
implicit val anyOfTypeInfo: Creator[GroupsLogic.AnyOf] = new AnyOfGroupsRule(_, _)(_)
implicit val notAllOfTypeInfo: Creator[GroupsLogic.NotAllOf] = new NotAllOfGroupsRule(_, _)(_)
implicit val notAnyOfTypeInfo: Creator[GroupsLogic.NotAnyOf] = new NotAnyOfGroupsRule(_, _)(_)
implicit val combinedTypeInfo: Creator[GroupsLogic.Combined] = new CombinedGroupsRule(_, _)(_)

def apply[GL <: GroupsLogic](implicit creator: Creator[GL]): Creator[GL] = creator
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,6 @@ object LdapAuthorizationRule {
groupsLogic: GroupsLogic.PositiveGroupsLogic) extends Settings

final case class CombinedGroupsLogicSettings(ldap: LdapAuthorizationService,
groupsLogic: GroupsLogic.CombinedGroupsLogic) extends Settings
groupsLogic: GroupsLogic.Combined) extends Settings
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import tech.beshu.ror.accesscontrol.blocks.rules.http.*
import tech.beshu.ror.accesscontrol.blocks.rules.kibana.*
import tech.beshu.ror.accesscontrol.blocks.rules.tranport.*
import tech.beshu.ror.accesscontrol.blocks.variables.runtime.RuntimeMultiResolvableVariable
import tech.beshu.ror.accesscontrol.domain.LocalUsers
import tech.beshu.ror.accesscontrol.domain.GroupsLogic.*
import tech.beshu.ror.accesscontrol.domain.{GroupsLogic, LocalUsers}
import tech.beshu.ror.syntax.*

object LocalUsersContext {
Expand All @@ -53,10 +54,7 @@ object LocalUsersContext {
implicit val externalAuthorizationRule: LocalUsersSupport[ExternalAuthorizationRule] = NotAvailableLocalUsers()
implicit val fieldsRule: LocalUsersSupport[FieldsRule] = NotAvailableLocalUsers()
implicit val filterRule: LocalUsersSupport[FilterRule] = NotAvailableLocalUsers()
implicit val groupsOrRule: LocalUsersSupport[GroupsOrRule] = NotAvailableLocalUsers()
implicit val groupsAndRule: LocalUsersSupport[GroupsAndRule] = NotAvailableLocalUsers()
implicit val groupsNotAnyOfRule: LocalUsersSupport[GroupsNotAnyOfRule] = NotAvailableLocalUsers()
implicit val groupsNotAllOfRule: LocalUsersSupport[GroupsNotAllOfRule] = NotAvailableLocalUsers()
implicit def groupsRule[GL <: GroupsLogic]: LocalUsersSupport[GroupsRule[GL]] = NotAvailableLocalUsers()
implicit val headersAndRule: LocalUsersSupport[HeadersAndRule] = NotAvailableLocalUsers()
implicit val headersOrRule: LocalUsersSupport[HeadersOrRule] = NotAvailableLocalUsers()
implicit val hostsRule: LocalUsersSupport[HostsRule] = NotAvailableLocalUsers()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,42 @@ package tech.beshu.ror.accesscontrol.blocks.variables.runtime

import cats.data.NonEmptyList
import tech.beshu.ror.accesscontrol.blocks.BlockContext
import tech.beshu.ror.accesscontrol.domain.GroupsLogic.{NegativeGroupsLogic, PositiveGroupsLogic}
import tech.beshu.ror.accesscontrol.domain.{GroupIdLike, GroupIds, GroupsLogic}
import tech.beshu.ror.accesscontrol.utils.RuntimeMultiResolvableVariableOps.resolveAll
import tech.beshu.ror.utils.uniquelist.UniqueNonEmptyList

class RuntimeResolvableGroupsLogic[GL <: GroupsLogic](val groupIds: UniqueNonEmptyList[RuntimeMultiResolvableVariable[GroupIdLike]],
creator: GroupIds => GL) {
def resolve[B <: BlockContext](blockContext: B): Option[GL] = {
UniqueNonEmptyList
.from(resolveAll(groupIds.toNonEmptyList, blockContext))
.map(GroupIds.apply)
.map(creator)
trait RuntimeResolvableGroupsLogic[+GL <: GroupsLogic] {
def resolve[B <: BlockContext](blockContext: B): Option[GL]

def usedVariables: NonEmptyList[RuntimeMultiResolvableVariable[GroupIdLike]]
}

object RuntimeResolvableGroupsLogic {

type RESOLVABLE_GROUP_IDS = UniqueNonEmptyList[RuntimeMultiResolvableVariable[GroupIdLike]]

final class Simple[+GL <: GroupsLogic : GroupsLogic.Creator](val groupIds: RESOLVABLE_GROUP_IDS) extends RuntimeResolvableGroupsLogic[GL] {
override def resolve[B <: BlockContext](blockContext: B): Option[GL] = {
UniqueNonEmptyList
.from(resolveAll(groupIds.toNonEmptyList, blockContext))
.map(GroupIds.apply)
.map(GroupsLogic.Creator[GL].create)
}

override def usedVariables: NonEmptyList[RuntimeMultiResolvableVariable[GroupIdLike]] = groupIds.toNonEmptyList
}

def usedVariables: NonEmptyList[RuntimeMultiResolvableVariable[GroupIdLike]] = groupIds.toNonEmptyList
}
final class Combined(val positive: RuntimeResolvableGroupsLogic[PositiveGroupsLogic],
val negative: RuntimeResolvableGroupsLogic[NegativeGroupsLogic]) extends RuntimeResolvableGroupsLogic[GroupsLogic.Combined] {
override def resolve[B <: BlockContext](blockContext: B): Option[GroupsLogic.Combined] = {
for {
permitted <- positive.resolve(blockContext)
forbidden <- negative.resolve(blockContext)
} yield GroupsLogic.Combined(permitted, forbidden)
}

override def usedVariables: NonEmptyList[RuntimeMultiResolvableVariable[GroupIdLike]] =
positive.usedVariables ::: negative.usedVariables
}
}
Loading