diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ActionMatcher.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ActionMatcher.kt index 192fe40c..46a05b5c 100644 --- a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ActionMatcher.kt +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ActionMatcher.kt @@ -22,7 +22,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser interface ActionMatcher : RequestMatcher object AllActionMatcher : ActionMatcher { - const val TYPE = "ALL" + const val TYPE = "all" override val type: String get() = TYPE override val pattern: String @@ -34,7 +34,7 @@ object AllActionMatcher : ActionMatcher { } object NoneActionMatcher : ActionMatcher { - const val TYPE = "NONE" + const val TYPE = "none" override val type: String get() = TYPE override val pattern: String diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ActionMatcherFactory.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ActionMatcherFactory.kt index cfaa7681..defde126 100644 --- a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ActionMatcherFactory.kt +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ActionMatcherFactory.kt @@ -15,7 +15,7 @@ package me.ahoo.cosec.policy object ActionMatcherFactory { fun create(type: String, pattern: String): ActionMatcher { - return when (type.uppercase()) { + return when (type.lowercase()) { AllActionMatcher.TYPE -> AllActionMatcher NoneActionMatcher.TYPE -> NoneActionMatcher PathActionMatcher.TYPE -> if (ActionPatternReplacer.isTemplate(pattern)) { diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ConditionMatcher.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ConditionMatcher.kt index a0107775..04e0e579 100644 --- a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ConditionMatcher.kt +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ConditionMatcher.kt @@ -19,7 +19,7 @@ import me.ahoo.cosec.context.request.Request interface ConditionMatcher : RequestMatcher object AllConditionMatcher : ConditionMatcher { - const val TYPE = "ALL" + const val TYPE = "all" override val type: String get() = TYPE override val pattern: String @@ -31,7 +31,7 @@ object AllConditionMatcher : ConditionMatcher { } object NoneConditionMatcher : ConditionMatcher { - const val TYPE = "NONE" + const val TYPE = "none" override val type: String get() = TYPE override val pattern: String diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ConditionMatcherFactory.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ConditionMatcherFactory.kt index f7b83645..5f7eae2f 100644 --- a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ConditionMatcherFactory.kt +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/ConditionMatcherFactory.kt @@ -15,7 +15,7 @@ package me.ahoo.cosec.policy object ConditionMatcherFactory { fun create(type: String, pattern: String): ConditionMatcher { - return when (type.uppercase()) { + return when (type.lowercase()) { AllConditionMatcher.TYPE -> AllConditionMatcher NoneConditionMatcher.TYPE -> NoneConditionMatcher SpelConditionMatcher.TYPE -> SpelConditionMatcher(pattern) diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/OgnlConditionMatcher.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/OgnlConditionMatcher.kt index 72243545..fcdc5c94 100644 --- a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/OgnlConditionMatcher.kt +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/OgnlConditionMatcher.kt @@ -19,7 +19,7 @@ import ognl.Ognl data class OgnlConditionMatcher(override val pattern: String) : ConditionMatcher { companion object { - const val TYPE = "OGNL" + const val TYPE = "ognl" } override val type: String diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/PathActionMatcher.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/PathActionMatcher.kt index 114373fa..c2b36e60 100644 --- a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/PathActionMatcher.kt +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/PathActionMatcher.kt @@ -20,7 +20,7 @@ import org.springframework.web.util.pattern.PathPatternParser data class PathActionMatcher(override val pattern: String) : ActionMatcher { companion object { - const val TYPE = "PATH" + const val TYPE = "path" } override val type: String diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/RegularActionMatcher.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/RegularActionMatcher.kt index c783160f..01f631f3 100644 --- a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/RegularActionMatcher.kt +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/RegularActionMatcher.kt @@ -18,7 +18,7 @@ import me.ahoo.cosec.context.request.Request data class RegularActionMatcher(override val pattern: String) : ActionMatcher { companion object { - const val TYPE = "REG" + const val TYPE = "reg" } private val matcher: Regex = pattern.toRegex(RegexOption.IGNORE_CASE) diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/SpelConditionMatcher.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/SpelConditionMatcher.kt index 719ad88c..307c8a66 100644 --- a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/SpelConditionMatcher.kt +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/SpelConditionMatcher.kt @@ -19,7 +19,7 @@ import org.springframework.expression.Expression data class SpelConditionMatcher(override val pattern: String) : ConditionMatcher { companion object { - const val TYPE = "SPEL" + const val TYPE = "spel" } override val type: String diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/serialization/JsonPolicySerializer.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/serialization/JsonPolicySerializer.kt index 0cc033f3..4ef1712c 100644 --- a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/serialization/JsonPolicySerializer.kt +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/serialization/JsonPolicySerializer.kt @@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.SerializerProvider import com.fasterxml.jackson.databind.deser.std.StdDeserializer import com.fasterxml.jackson.databind.ser.std.StdSerializer -import me.ahoo.cosec.context.request.RequestTenantIdParser import me.ahoo.cosec.policy.Policy import me.ahoo.cosec.policy.PolicyData import me.ahoo.cosec.policy.PolicyType @@ -31,6 +30,7 @@ const val POLICY_NAME_KEY = "name" const val POLICY_CATEGORY_KEY = "category" const val POLICY_DESCRIPTION_KEY = "description" const val POLICY_TYPE_KEY = "type" +const val TENANT_ID_KEY = "tenantId" const val POLICY_STATEMENTS_KEY = "statements" object JsonPolicySerializer : StdSerializer(Policy::class.java) { @@ -40,8 +40,8 @@ object JsonPolicySerializer : StdSerializer(Policy::class.java) { gen.writeStringField(POLICY_NAME_KEY, value.name) gen.writeStringField(POLICY_CATEGORY_KEY, value.category) gen.writeStringField(POLICY_DESCRIPTION_KEY, value.description) - gen.writeStringField(POLICY_TYPE_KEY, value.type.name) - gen.writeStringField(RequestTenantIdParser.TENANT_ID_KEY, value.tenantId) + gen.writeStringField(POLICY_TYPE_KEY, value.type.name.lowercase()) + gen.writeStringField(TENANT_ID_KEY, value.tenantId) if (value.statements.isNotEmpty()) { gen.writeArrayFieldStart(POLICY_STATEMENTS_KEY) value.statements.forEach { @@ -70,8 +70,8 @@ object JsonPolicyDeserializer : StdDeserializer(Policy::class.java) { name = jsonNode.get(POLICY_NAME_KEY).asText(), category = jsonNode.get(POLICY_CATEGORY_KEY).asText(), description = jsonNode.get(POLICY_DESCRIPTION_KEY).asText(), - type = PolicyType.valueOf(jsonNode.get(POLICY_TYPE_KEY).asText()), - tenantId = jsonNode.get(RequestTenantIdParser.TENANT_ID_KEY).asText(), + type = PolicyType.valueOf(jsonNode.get(POLICY_TYPE_KEY).asText().uppercase()), + tenantId = jsonNode.get(TENANT_ID_KEY).asText(), statements = statements ) } diff --git a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/serialization/JsonStatementSerializer.kt b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/serialization/JsonStatementSerializer.kt index b2cfcf04..fd15d547 100644 --- a/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/serialization/JsonStatementSerializer.kt +++ b/cosec-core/src/main/kotlin/me/ahoo/cosec/policy/serialization/JsonStatementSerializer.kt @@ -33,7 +33,7 @@ const val STATEMENT_CONDITIONS_KEY = "conditions" object JsonStatementSerializer : StdSerializer(Statement::class.java) { override fun serialize(value: Statement, gen: JsonGenerator, provider: SerializerProvider) { gen.writeStartObject() - gen.writeStringField(STATEMENT_EFFECT_KEY, value.effect.name) + gen.writeStringField(STATEMENT_EFFECT_KEY, value.effect.name.lowercase()) if (value.actions.isNotEmpty()) { gen.writeArrayFieldStart(STATEMENT_ACTIONS_KEY) value.actions.forEach { @@ -74,7 +74,7 @@ object JsonStatementDeserializer : StdDeserializer(Statement::class.j } } return StatementData( - effect = Effect.valueOf(jsonNode.get(STATEMENT_EFFECT_KEY).asText()), + effect = Effect.valueOf(jsonNode.get(STATEMENT_EFFECT_KEY).asText().uppercase()), actions = actions, conditions = conditions ) diff --git a/cosec-core/src/test/resources/policy.json b/cosec-core/src/test/resources/policy.json index 31de5104..57b60a75 100644 --- a/cosec-core/src/test/resources/policy.json +++ b/cosec-core/src/test/resources/policy.json @@ -1,26 +1,56 @@ { - "name": "Anonymous", - "effect": "allow", - "description": "Anonymous", - "type": "global", + "id": "2", + "name": "auth", + "category": "auth", + "description": "", + "type": "system", + "tenantId": "1", "statements": [ { + "effect": "allow" + }, + { + "effect": "deny", "actions": [ { - "path": "/", - "verbs": [ - "*" - ] + "type": "all" + }, + { + "type": "none" + }, + { + "type": "path", + "pattern": ".*" + }, + { + "type": "path", + "pattern": "#{principal.id}.*" + }, + { + "type": "reg", + "pattern": ".*" + }, + { + "type": "reg", + "pattern": "#{principal.id}.*" } ], -// "resources": [ -// "my-app:*" -// ], -// "conditions": { -// "string_equals": { -// "aws:username": "my-user" -// } -// } + "conditions": [ + { + "type": "all" + }, + { + "type": "none" + }, + { + "type": "spel", + "pattern": "context.principal.id=='1'" + }, + { + "type": "ognl", + "pattern": "action == \"auth/login:POST\"" + } + ] } ] } diff --git a/cosec-gateway-server/src/main/resources/application.yaml b/cosec-gateway-server/src/main/resources/application.yaml index c1d7fc78..08c8a5ac 100644 --- a/cosec-gateway-server/src/main/resources/application.yaml +++ b/cosec-gateway-server/src/main/resources/application.yaml @@ -19,6 +19,12 @@ spring: - Path=/cosec-auth/** filters: - StripPrefix=1 +# - id: baidu +# uri: https://www.baidu.com +# predicates: +# - Path=/baidu/** +# filters: +# - StripPrefix=1 cosid: namespace: ${spring.application.name} machine: diff --git a/document/cosec-policy.schema.json b/document/cosec-policy.schema.json new file mode 100644 index 00000000..1f563a5e --- /dev/null +++ b/document/cosec-policy.schema.json @@ -0,0 +1,127 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema", + "$id": "https://github.com/Ahoo-Wang/CoSec/blob/main/document/cosec-policy.schema.json", + "title": "CoSec Policy Schema", + "type": "object", + "properties": { + "id": { + "description": "The id of the policy", + "type": "string" + }, + "category": { + "description": "The category of the policy", + "type": "string" + }, + "name": { + "description": "The name of the policy", + "type": "string" + }, + "description": { + "description": "The description of the policy", + "type": "string" + }, + "tenantId": { + "description": "The tenantId of the policy", + "type": "string" + }, + "type": { + "description": "The type of the policy", + "$ref": "#/definitions/policyType" + }, + "statements": { + "type": "array", + "items": { + "$ref": "#/definitions/statement" + } + } + }, + "required": [ + "category", + "name", + "description", + "tenantId", + "type", + "statements" + ], + "definitions": { + "policyType": { + "enum": [ + "global", + "system", + "custom" + ] + }, + "effect": { + "enum": [ + "allow", + "deny" + ] + }, + "actionType": { + "enum": [ + "all", + "none", + "path", + "reg" + ] + }, + "conditionType": { + "enum": [ + "all", + "none", + "spel", + "ognl" + ] + }, + "actionMatcher": { + "type": "object", + "properties": { + "type": { + "$ref": "#/definitions/actionType" + }, + "pattern": { + "type": "string" + } + }, + "required": [ + "type" + ] + }, + "conditionMatcher": { + "type": "object", + "properties": { + "type": { + "$ref": "#/definitions/conditionType" + }, + "pattern": { + "type": "string" + } + }, + "required": [ + "type" + ] + }, + "statement": { + "type": "object", + "properties": { + "effect": { + "$ref": "#/definitions/effect" + }, + "actions": { + "type": "array", + "items": { + "$ref": "#/definitions/actionMatcher" + } + }, + "conditions": { + "type": "array", + "items": { + "$ref": "#/definitions/conditionMatcher" + } + } + } + } + } +} + + diff --git a/gradle.properties b/gradle.properties index 73a4b296..91abe945 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ # limitations under the License. # group=me.ahoo.cosec -version=1.0.3 +version=1.0.5 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