From faaf08b0d1e13d83488578c24eeb6fb144a7e652 Mon Sep 17 00:00:00 2001 From: Ahoo Wang Date: Tue, 10 Jan 2023 17:21:26 +0800 Subject: [PATCH] Feature: add `EndsWithConditionMatcher` (#65) * Feature: add `EndsWithConditionMatcher` --- README.md | 2 +- README.zh-CN.md | 3 +- .../part/ContainsConditionMatcher.kt | 5 +- .../part/EndsWithConditionMatcher.kt | 43 ++++++++++++++++ ...c.policy.condition.ConditionMatcherFactory | 1 + .../part/ContainsConditionMatcherTest.kt | 10 +--- .../part/EndsWithConditionMatcherTest.kt | 50 +++++++++++++++++++ .../part/RegularConditionMatcherTest.kt | 10 +--- .../part/StartsWithConditionMatcherTest.kt | 16 ++---- .../src/test/resources/test-policy.json | 14 ++++++ .../src/main/resources/application.yaml | 12 ++--- document/cosec-policy.schema.json | 1 + gradle.properties | 2 +- 13 files changed, 129 insertions(+), 40 deletions(-) create mode 100644 cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition/part/EndsWithConditionMatcher.kt create mode 100644 cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/EndsWithConditionMatcherTest.kt diff --git a/README.md b/README.md index 9f633d5e..11215f34 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ class CustomConditionMatcher(configuration: Configuration) : ## Policy Schema -[Policy Schema](document/cosec-policy.schema.json) +Configure [Policy Schema](document/cosec-policy.schema.json) to support IDE ([IntelliJ IDEA](https://www.jetbrains.com/help/idea/json.html#ws_json_using_schemas)) input autocompletion. > Policy Demo diff --git a/README.zh-CN.md b/README.zh-CN.md index fc905e40..0a1f3d09 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -113,7 +113,8 @@ class CustomConditionMatcher(configuration: Configuration) : ## 策略 Schema -[Policy Schema](document/cosec-policy.schema.json) +配置 [Policy Schema](document/cosec-policy.schema.json) 以支持 IDE ([IntelliJ IDEA](https://www.jetbrains.com/help/idea/json.html#ws_json_using_schemas)) 输入自动完成。 + > 策略 Demo diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition/part/ContainsConditionMatcher.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition/part/ContainsConditionMatcher.kt index ae47b5de..27023534 100644 --- a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition/part/ContainsConditionMatcher.kt +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition/part/ContainsConditionMatcher.kt @@ -21,8 +21,11 @@ import me.ahoo.cosec.policy.getMatcherPattern class ContainsConditionMatcher(configuration: Configuration) : PartConditionMatcher(ContainsConditionMatcherFactory.TYPE, configuration) { private val pattern: String = configuration.getMatcherPattern() + private val ignoreCase: Boolean = + configuration.get(STARTS_WITH_CONDITION_MATCHER_IGNORE_CASE_KEY)?.asBoolean() ?: false + override fun matchPart(partValue: String): Boolean { - return partValue.contains(pattern) + return partValue.contains(pattern, ignoreCase) } } diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition/part/EndsWithConditionMatcher.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition/part/EndsWithConditionMatcher.kt new file mode 100644 index 00000000..f6739bbd --- /dev/null +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition/part/EndsWithConditionMatcher.kt @@ -0,0 +1,43 @@ +/* + * Copyright [2021-present] [ahoo wang (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.part + +import me.ahoo.cosec.api.configuration.Configuration +import me.ahoo.cosec.api.policy.ConditionMatcher +import me.ahoo.cosec.policy.condition.ConditionMatcherFactory +import me.ahoo.cosec.policy.getMatcherPattern + +class EndsWithConditionMatcher(configuration: Configuration) : + PartConditionMatcher(EndsWithConditionMatcherFactory.TYPE, configuration) { + private val pattern: String = configuration.getMatcherPattern() + private val ignoreCase: Boolean = + configuration.get(STARTS_WITH_CONDITION_MATCHER_IGNORE_CASE_KEY)?.asBoolean() ?: false + + override fun matchPart(partValue: String): Boolean { + return partValue.endsWith(pattern, ignoreCase) + } +} + +class EndsWithConditionMatcherFactory : ConditionMatcherFactory { + companion object { + const val TYPE = "ends_with" + } + + override val type: String + get() = TYPE + + override fun create(configuration: Configuration): ConditionMatcher { + return EndsWithConditionMatcher(configuration) + } +} diff --git a/cosec-core/src/main/resources/META-INF/services/me.ahoo.cosec.policy.condition.ConditionMatcherFactory b/cosec-core/src/main/resources/META-INF/services/me.ahoo.cosec.policy.condition.ConditionMatcherFactory index 3597bd36..d3941c71 100644 --- a/cosec-core/src/main/resources/META-INF/services/me.ahoo.cosec.policy.condition.ConditionMatcherFactory +++ b/cosec-core/src/main/resources/META-INF/services/me.ahoo.cosec.policy.condition.ConditionMatcherFactory @@ -23,6 +23,7 @@ me.ahoo.cosec.policy.condition.part.EqConditionMatcherFactory me.ahoo.cosec.policy.condition.part.RegularConditionMatcherFactory me.ahoo.cosec.policy.condition.part.PathConditionMatcherFactory me.ahoo.cosec.policy.condition.part.StartsWithConditionMatcherFactory +me.ahoo.cosec.policy.condition.part.EndsWithConditionMatcherFactory me.ahoo.cosec.policy.condition.SpelConditionMatcherFactory me.ahoo.cosec.policy.condition.OgnlConditionMatcherFactory me.ahoo.cosec.policy.condition.BoolConditionMatcherFactory diff --git a/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/ContainsConditionMatcherTest.kt b/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/ContainsConditionMatcherTest.kt index 2593733d..56e7c128 100644 --- a/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/ContainsConditionMatcherTest.kt +++ b/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/ContainsConditionMatcherTest.kt @@ -31,20 +31,12 @@ class ContainsConditionMatcherTest { ).asConfiguration(), ) - @Test - fun matchWhenRemoteIpIsNull() { - val request = mockk { - every { remoteIp } returns "remoteIp" - } - assertThat(conditionMatcher.type, `is`(ContainsConditionMatcherFactory.TYPE)) - assertThat(conditionMatcher.match(request, mockk()), `is`(false)) - } - @Test fun match() { val request = mockk { every { remoteIp } returns "192.168.0.1" } + assertThat(conditionMatcher.type, `is`(ContainsConditionMatcherFactory.TYPE)) assertThat(conditionMatcher.match(request, mockk()), `is`(true)) } diff --git a/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/EndsWithConditionMatcherTest.kt b/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/EndsWithConditionMatcherTest.kt new file mode 100644 index 00000000..5c85f48d --- /dev/null +++ b/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/EndsWithConditionMatcherTest.kt @@ -0,0 +1,50 @@ +/* + * Copyright [2021-present] [ahoo wang (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.part + +import io.mockk.every +import io.mockk.mockk +import me.ahoo.cosec.api.context.request.Request +import me.ahoo.cosec.configuration.JsonConfiguration.Companion.asConfiguration +import me.ahoo.cosec.policy.MATCHER_PATTERN_KEY +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.`is` +import org.junit.jupiter.api.Test + +class EndsWithConditionMatcherTest { + private val conditionMatcher = + EndsWithConditionMatcherFactory().create( + mapOf( + CONDITION_MATCHER_PART_KEY to RequestParts.REMOTE_IP, + MATCHER_PATTERN_KEY to ".168.0.1", + ).asConfiguration(), + ) + + @Test + fun match() { + val request = mockk { + every { remoteIp } returns "192.168.0.1" + } + assertThat(conditionMatcher.type, `is`(EndsWithConditionMatcherFactory.TYPE)) + assertThat(conditionMatcher.match(request, mockk()), `is`(true)) + } + + @Test + fun notMatch() { + val requestNotMatch = mockk { + every { remoteIp } returns "10.168.1.1" + } + assertThat(conditionMatcher.match(requestNotMatch, mockk()), `is`(false)) + } +} diff --git a/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/RegularConditionMatcherTest.kt b/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/RegularConditionMatcherTest.kt index ba951737..0a49fad1 100644 --- a/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/RegularConditionMatcherTest.kt +++ b/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/RegularConditionMatcherTest.kt @@ -31,20 +31,12 @@ class RegularConditionMatcherTest { ).asConfiguration(), ) - @Test - fun matchWhenRemoteIpIsNull() { - val request = mockk { - every { remoteIp } returns "remoteIp" - } - assertThat(conditionMatcher.type, `is`(RegularConditionMatcherFactory.TYPE)) - assertThat(conditionMatcher.match(request, mockk()), `is`(false)) - } - @Test fun match() { val request = mockk { every { remoteIp } returns "192.168.0.1" } + assertThat(conditionMatcher.type, `is`(RegularConditionMatcherFactory.TYPE)) assertThat(conditionMatcher.match(request, mockk()), `is`(true)) } diff --git a/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/StartsWithConditionMatcherTest.kt b/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/StartsWithConditionMatcherTest.kt index 941e3db6..d528ead2 100644 --- a/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/StartsWithConditionMatcherTest.kt +++ b/cosec-core/src/test/kotlin/me/ahoo/cosec/policy/condition/part/StartsWithConditionMatcherTest.kt @@ -22,29 +22,21 @@ import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` import org.junit.jupiter.api.Test -class StartsWithConditionMatcherTest{ +class StartsWithConditionMatcherTest { private val conditionMatcher = StartsWithConditionMatcherFactory().create( mapOf( CONDITION_MATCHER_PART_KEY to RequestParts.REMOTE_IP, - MATCHER_PATTERN_KEY to "192", + MATCHER_PATTERN_KEY to "192.", ).asConfiguration(), ) - @Test - fun matchWhenRemoteIpIsNull() { - val request = mockk { - every { remoteIp } returns "remoteIp" - } - assertThat(conditionMatcher.type, `is`(StartsWithConditionMatcherFactory.TYPE)) - assertThat(conditionMatcher.match(request, mockk()), `is`(false)) - } - @Test fun match() { val request = mockk { every { remoteIp } returns "192.168.0.1" } + assertThat(conditionMatcher.type, `is`(StartsWithConditionMatcherFactory.TYPE)) assertThat(conditionMatcher.match(request, mockk()), `is`(true)) } @@ -55,4 +47,4 @@ class StartsWithConditionMatcherTest{ } assertThat(conditionMatcher.match(requestNotMatch, mockk()), `is`(false)) } -} \ No newline at end of file +} diff --git a/cosec-core/src/test/resources/test-policy.json b/cosec-core/src/test/resources/test-policy.json index 52322aa2..a65af5b6 100644 --- a/cosec-core/src/test/resources/test-policy.json +++ b/cosec-core/src/test/resources/test-policy.json @@ -163,6 +163,20 @@ "part": "request.attributes.ipRegion", "pattern": "中国" } + }, + { + "name": "TestEndsWith", + "effect": "allow", + "actions": [ + { + "type": "all" + } + ], + "condition": { + "type": "ends_with", + "part": "request.attributes.remoteIp", + "pattern": ".168.0.1" + } } ] } diff --git a/cosec-gateway-server/src/main/resources/application.yaml b/cosec-gateway-server/src/main/resources/application.yaml index 812df6e3..95206da8 100644 --- a/cosec-gateway-server/src/main/resources/application.yaml +++ b/cosec-gateway-server/src/main/resources/application.yaml @@ -22,12 +22,12 @@ spring: - Path=/cosec-auth/** filters: - StripPrefix=1 -# - id: baidu -# uri: https://www.baidu.com -# predicates: -# - Path=/baidu/** -# filters: -# - StripPrefix=1 + - id: google + uri: https://www.google.com + predicates: + - Path=/google/** + filters: + - StripPrefix=1 cosid: namespace: ${spring.application.name} machine: diff --git a/document/cosec-policy.schema.json b/document/cosec-policy.schema.json index e6e32f69..7a26bf14 100644 --- a/document/cosec-policy.schema.json +++ b/document/cosec-policy.schema.json @@ -103,6 +103,7 @@ "in_user_tenant", "contains", "starts_with", + "ends_with", "eq", "in", "reg", diff --git a/gradle.properties b/gradle.properties index 3ea1d098..0f1374d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ # limitations under the License. # group=me.ahoo.cosec -version=1.10.2 +version=1.10.3 description=RBAC-based And Policy-based Multi-Tenant Reactive Security Framework website=https://github.com/Ahoo-Wang/CoSec issues=https://github.com/Ahoo-Wang/CoSec/issues