Skip to content

Commit

Permalink
Feature: add EndsWithConditionMatcher (#65)
Browse files Browse the repository at this point in the history
* Feature: add `EndsWithConditionMatcher`
  • Loading branch information
Ahoo-Wang authored Jan 10, 2023
1 parent 09cb0a2 commit faaf08b
Show file tree
Hide file tree
Showing 13 changed files with 129 additions and 40 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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.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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,12 @@ class ContainsConditionMatcherTest {
).asConfiguration(),
)

@Test
fun matchWhenRemoteIpIsNull() {
val request = mockk<Request> {
every { remoteIp } returns "remoteIp"
}
assertThat(conditionMatcher.type, `is`(ContainsConditionMatcherFactory.TYPE))
assertThat(conditionMatcher.match(request, mockk()), `is`(false))
}

@Test
fun match() {
val request = mockk<Request> {
every { remoteIp } returns "192.168.0.1"
}
assertThat(conditionMatcher.type, `is`(ContainsConditionMatcherFactory.TYPE))
assertThat(conditionMatcher.match(request, mockk()), `is`(true))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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.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<Request> {
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<Request> {
every { remoteIp } returns "10.168.1.1"
}
assertThat(conditionMatcher.match(requestNotMatch, mockk()), `is`(false))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,12 @@ class RegularConditionMatcherTest {
).asConfiguration(),
)

@Test
fun matchWhenRemoteIpIsNull() {
val request = mockk<Request> {
every { remoteIp } returns "remoteIp"
}
assertThat(conditionMatcher.type, `is`(RegularConditionMatcherFactory.TYPE))
assertThat(conditionMatcher.match(request, mockk()), `is`(false))
}

@Test
fun match() {
val request = mockk<Request> {
every { remoteIp } returns "192.168.0.1"
}
assertThat(conditionMatcher.type, `is`(RegularConditionMatcherFactory.TYPE))
assertThat(conditionMatcher.match(request, mockk()), `is`(true))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Request> {
every { remoteIp } returns "remoteIp"
}
assertThat(conditionMatcher.type, `is`(StartsWithConditionMatcherFactory.TYPE))
assertThat(conditionMatcher.match(request, mockk()), `is`(false))
}

@Test
fun match() {
val request = mockk<Request> {
every { remoteIp } returns "192.168.0.1"
}
assertThat(conditionMatcher.type, `is`(StartsWithConditionMatcherFactory.TYPE))
assertThat(conditionMatcher.match(request, mockk()), `is`(true))
}

Expand All @@ -55,4 +47,4 @@ class StartsWithConditionMatcherTest{
}
assertThat(conditionMatcher.match(requestNotMatch, mockk()), `is`(false))
}
}
}
14 changes: 14 additions & 0 deletions cosec-core/src/test/resources/test-policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
]
}
12 changes: 6 additions & 6 deletions cosec-gateway-server/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions document/cosec-policy.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"in_user_tenant",
"contains",
"starts_with",
"ends_with",
"eq",
"in",
"reg",
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit faaf08b

Please sign in to comment.