Skip to content

Commit

Permalink
Feature: support negate for ConditionMatcher (#50)
Browse files Browse the repository at this point in the history
* Feature: support `negate` for `ConditionMatcher`
  • Loading branch information
Ahoo-Wang authored Jan 4, 2023
1 parent c11ef90 commit 8f7302e
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ class SecurityContextTest {
fun getRequiredAttribute() {
val securityContext: SecurityContext = object : SecurityContext {
override val principal: CoSecPrincipal
get() = TODO("Not yet implemented")
get() = throw UnsupportedOperationException()

override fun setAttribute(key: String, value: Any): SecurityContext {
TODO("Not yet implemented")
throw UnsupportedOperationException()
}

override fun <T> getAttribute(key: String): T? {
Expand All @@ -39,7 +39,7 @@ class SecurityContextTest {
}

override val tenant: Tenant
get() = TODO("Not yet implemented")
get() = throw UnsupportedOperationException()
}
assertThat(securityContext.getAttribute("key"), equalTo("key"))
assertThat(securityContext.getRequiredAttribute("key"), equalTo("key"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ class CoSecPrincipalTest {
get() = ANONYMOUS_ID

override fun getName(): String {
TODO("Not yet implemented")
throw UnsupportedOperationException()
}

override val attrs: Map<String, Any>
get() = TODO("Not yet implemented")
get() = throw UnsupportedOperationException()
override val policies: Set<String>
get() = TODO("Not yet implemented")
get() = throw UnsupportedOperationException()
override val roles: Set<String>
get() = TODO("Not yet implemented")
get() = throw UnsupportedOperationException()
}
assertThat(anonymous.anonymous(), equalTo(true))
}
Expand All @@ -47,15 +47,15 @@ class CoSecPrincipalTest {
get() = "id"

override fun getName(): String {
TODO("Not yet implemented")
throw UnsupportedOperationException()
}

override val attrs: Map<String, Any>
get() = TODO("Not yet implemented")
get() = throw UnsupportedOperationException()
override val policies: Set<String>
get() = TODO("Not yet implemented")
get() = throw UnsupportedOperationException()
override val roles: Set<String>
get() = TODO("Not yet implemented")
get() = throw UnsupportedOperationException()
}
assertThat(authenticated.authenticated(), equalTo(true))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright [2021-present] [ahoo wang <[email protected]> (https://github.com/Ahoo-Wang)].
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package me.ahoo.cosec.policy.condition

import me.ahoo.cosec.api.configuration.Configuration
import me.ahoo.cosec.api.context.SecurityContext
import me.ahoo.cosec.api.context.request.Request
import me.ahoo.cosec.api.policy.ConditionMatcher

const val CONDITION_MATCHER_NEGATE_KEY = "negate"

abstract class AbstractConditionMatcher(final override val configuration: Configuration) : ConditionMatcher {
protected val negate: Boolean = configuration.get(CONDITION_MATCHER_NEGATE_KEY)?.asBoolean() ?: false

override fun match(request: Request, securityContext: SecurityContext): Boolean {
val match = internalMatch(request, securityContext)
return if (negate) !match else match
}

protected abstract fun internalMatch(request: Request, securityContext: SecurityContext): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import me.ahoo.cosec.api.context.SecurityContext
import me.ahoo.cosec.api.context.request.Request
import me.ahoo.cosec.api.policy.ConditionMatcher

class AllConditionMatcher(override val configuration: Configuration) : ConditionMatcher {
class AllConditionMatcher(configuration: Configuration) : AbstractConditionMatcher(configuration) {

override val type: String
get() = AllConditionMatcherFactory.TYPE

override fun match(request: Request, securityContext: SecurityContext): Boolean {
override fun internalMatch(request: Request, securityContext: SecurityContext): Boolean {
return true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ import me.ahoo.cosec.api.context.SecurityContext
import me.ahoo.cosec.api.context.request.Request
import me.ahoo.cosec.api.policy.ConditionMatcher

class NoneConditionMatcher(override val configuration: Configuration) : ConditionMatcher {
class NoneConditionMatcher(configuration: Configuration) : AbstractConditionMatcher(configuration) {
override val type: String
get() = NoneConditionMatcherFactory.TYPE

override fun match(request: Request, securityContext: SecurityContext): Boolean {
override fun internalMatch(request: Request, securityContext: SecurityContext): Boolean {
return false
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import me.ahoo.cosec.api.policy.ConditionMatcher
import me.ahoo.cosec.policy.getMatcherPattern
import ognl.Ognl

class OgnlConditionMatcher(override val configuration: Configuration) : ConditionMatcher {
class OgnlConditionMatcher(configuration: Configuration) : AbstractConditionMatcher(configuration) {
override val type: String
get() = OgnlConditionMatcherFactory.TYPE
private val ognlExpression = Ognl.parseExpression(configuration.getMatcherPattern())
override fun match(request: Request, securityContext: SecurityContext): Boolean {
override fun internalMatch(request: Request, securityContext: SecurityContext): Boolean {
val ognlContext = mapOf(
"request" to request,
"context" to securityContext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ import me.ahoo.cosec.policy.action.SPEL_PARSER
import me.ahoo.cosec.policy.getMatcherPattern
import org.springframework.expression.Expression

class SpelConditionMatcher(override val configuration: Configuration) : ConditionMatcher {
class SpelConditionMatcher(configuration: Configuration) : AbstractConditionMatcher(configuration) {

override val type: String
get() = SpelConditionMatcherFactory.TYPE

private val expression: Expression = SPEL_PARSER.parseExpression(configuration.getMatcherPattern())

override fun match(request: Request, securityContext: SecurityContext): Boolean {
override fun internalMatch(request: Request, securityContext: SecurityContext): Boolean {
val root = Root(request = request, context = securityContext)
return expression.getValue(root, Boolean::class.java) ?: false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ package me.ahoo.cosec.policy.condition.part
import me.ahoo.cosec.api.configuration.Configuration
import me.ahoo.cosec.api.context.SecurityContext
import me.ahoo.cosec.api.context.request.Request
import me.ahoo.cosec.api.policy.ConditionMatcher
import me.ahoo.cosec.policy.condition.AbstractConditionMatcher

abstract class PartConditionMatcher(
override val type: String,
final override val configuration: Configuration
) : ConditionMatcher {
configuration: Configuration
) : AbstractConditionMatcher(configuration) {
private val partExtractor: PartExtractor = configuration
.getRequired(CONDITION_MATCHER_PART_KEY).asString()
.let {
DefaultPartExtractor(it)
}

override fun match(request: Request, securityContext: SecurityContext): Boolean {
override fun internalMatch(request: Request, securityContext: SecurityContext): Boolean {
val partValue = partExtractor.extract(request, securityContext)
return matchPart(partValue)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright [2021-present] [ahoo wang <[email protected]> (https://github.com/Ahoo-Wang)].
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package me.ahoo.cosec.policy.condition

import io.mockk.mockk
import me.ahoo.cosec.api.context.SecurityContext
import me.ahoo.cosec.api.context.request.Request
import me.ahoo.cosec.configuration.JsonConfiguration
import me.ahoo.cosec.configuration.JsonConfiguration.Companion.asConfiguration
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.*
import org.junit.jupiter.api.Test

class AbstractConditionMatcherTest {

@Test
fun match() {
val conditionMatcher =
object : AbstractConditionMatcher(mapOf(CONDITION_MATCHER_NEGATE_KEY to true).asConfiguration()) {
override fun internalMatch(request: Request, securityContext: SecurityContext): Boolean {
return true
}

override val type: String
get() = throw UnsupportedOperationException()
}
assertThat(conditionMatcher.match(mockk(), mockk()), equalTo(false))
}

@Test
fun matchWhenNegateIsNull() {
val conditionMatcher = object : AbstractConditionMatcher(JsonConfiguration.EMPTY) {
override fun internalMatch(request: Request, securityContext: SecurityContext): Boolean {
return true
}

override val type: String
get() = throw UnsupportedOperationException()
}
assertThat(conditionMatcher.match(mockk(), mockk()), equalTo(true))
}
}
3 changes: 3 additions & 0 deletions document/cosec-policy.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@
}
]
},
"negate": {
"type": "boolean"
},
"pattern": {
"type": "string"
},
Expand Down

0 comments on commit 8f7302e

Please sign in to comment.