Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -13,10 +13,12 @@

package me.ahoo.cosec.api.context.request

typealias AppId = String

interface AppIdCapable {
companion object {
const val APP_ID_KEY = "CoSec-App-Id"
}

val appId: String
val appId: AppId
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@

package me.ahoo.cosec.api.context.request

typealias DeviceId = String

interface DeviceIdCapable {
companion object {
const val DEVICE_ID_KEY = "CoSec-Device-Id"
}
val deviceId: String
val deviceId: DeviceId
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,29 @@ import me.ahoo.cosec.api.context.Attributes
import me.ahoo.cosec.api.context.request.AppIdCapable.Companion.APP_ID_KEY
import me.ahoo.cosec.api.context.request.DeviceIdCapable.Companion.DEVICE_ID_KEY
import me.ahoo.cosec.api.context.request.RequestIdCapable.Companion.REQUEST_ID_KEY
import me.ahoo.cosec.api.context.request.SpaceIdCapable.Companion.SPACE_ID_KEY
import java.net.URI

interface Request : Attributes<Request, String, String>, AppIdCapable, DeviceIdCapable, RequestIdCapable {
interface Request :
Attributes<Request, String, String>,
AppIdCapable,
SpaceIdCapable,
DeviceIdCapable,
RequestIdCapable {

override val appId: String
override val appId: AppId
get() {
return getHeader(APP_ID_KEY).ifBlank { getQuery(APP_ID_KEY) }
}
override val deviceId: String
override val spaceId: SpaceId
get() {
return getHeader(SPACE_ID_KEY).ifBlank { getQuery(SPACE_ID_KEY) }
}
override val deviceId: DeviceId
get() {
return getHeader(DEVICE_ID_KEY).ifBlank { getQuery(DEVICE_ID_KEY) }
}
override val requestId: String
override val requestId: RequestId
get() {
return getHeader(REQUEST_ID_KEY)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@

package me.ahoo.cosec.api.context.request

typealias RequestId = String

interface RequestIdCapable {
companion object {
const val REQUEST_ID_KEY = "CoSec-Request-Id"
}

val requestId: String
val requestId: RequestId
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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.api.context.request

typealias SpaceId = String

interface SpaceIdCapable {
companion object {
const val SPACE_ID_KEY = "CoSec-Space-Id"
const val DEFAULT = ""
}

val spaceId: SpaceId
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package me.ahoo.cosec.api.permission

import me.ahoo.cosec.api.context.request.AppId
import me.ahoo.cosec.api.policy.ConditionMatcher

/**
* App permissions metadata.
*/
interface AppPermission {
val id: String
val id: AppId
val condition: ConditionMatcher
val groups: List<PermissionGroup>

/**
* PermissionId -> Permission
*/
val permissionIndexer: Map<String, Permission>
val permissionIndexer: Map<PermissionId, Permission>
get() = groups.flatMap { it.permissions }.associateBy { it.id }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package me.ahoo.cosec.api.permission

import me.ahoo.cosec.api.principal.RoleId

/**
* App Role Permission.
*/
Expand All @@ -10,7 +12,7 @@ interface AppRolePermission {
/**
* RoleId -> Permissions
*/
val rolePermissionIndexer: Map<String, List<Permission>>
val rolePermissionIndexer: Map<RoleId, List<Permission>>
get() {
rolePermissions.forEach {
if (it.permissions.contains(ALL_PERMISSION_ID)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ package me.ahoo.cosec.api.permission

import me.ahoo.cosec.api.policy.Statement

typealias PermissionId = String

/**
* Permission metadata.
*/
interface Permission : Statement {
/**
* format : appId.group.permission
*/
val id: String
val id: PermissionId
val description: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@

package me.ahoo.cosec.api.permission

import me.ahoo.cosec.api.principal.RoleId

/**
* Role Permissions.
*/
interface RolePermission {
/**
* role id
*/
val id: String
val id: RoleId

/**
* @see me.ahoo.cosec.api.permission.Permission
*/
val permissions: Set<String>
val permissions: Set<PermissionId>
}
4 changes: 3 additions & 1 deletion cosec-api/src/main/kotlin/me/ahoo/cosec/api/policy/Policy.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ import me.ahoo.cosec.api.context.SecurityContext
import me.ahoo.cosec.api.context.request.Request
import me.ahoo.cosec.api.tenant.Tenant

typealias PolicyId = String

/**
* Permission Policy
*/
interface Policy : Named, Tenant, PermissionVerifier {
val id: String
val id: PolicyId
val category: String
val description: String
val type: PolicyType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,44 @@
*/
package me.ahoo.cosec.api.principal

import me.ahoo.cosec.api.context.request.SpaceId
import me.ahoo.cosec.api.context.request.SpaceIdCapable

typealias RoleId = String

interface RoleIdCapable {
val roleId: RoleId
}

data class SpacedRoleId(
override val roleId: RoleId,
override val spaceId: SpaceId = SpaceIdCapable.DEFAULT
) : RoleIdCapable, SpaceIdCapable {
companion object {
const val SPACE_ID_SEPARATOR = "@"

val String.spaced: Boolean
get() = contains(SPACE_ID_SEPARATOR)

fun String.toSpacedRoleId(): SpacedRoleId {
val split = this.split(SPACE_ID_SEPARATOR)
val spaceId = if (split.size == 1) {
SpaceIdCapable.DEFAULT
} else {
split[1]
}
return SpacedRoleId(split[0], spaceId)
}
}

override fun toString(): String {
if (spaceId == SpaceIdCapable.DEFAULT) {
return roleId
}
return "$roleId$SPACE_ID_SEPARATOR$spaceId"
}
}

/**
* RoleCapable .
*
Expand All @@ -21,15 +59,14 @@ interface RoleCapable {
/**
* get role ids.
* relation:
* <pre>
*
* [CoSecPrincipal] 1:N [me.ahoo.cosec.api.tenant.Tenant]
* [me.ahoo.cosec.api.tenant.Tenant] 1:N Role
* [CoSecPrincipal] 1:N Role
</pre> *
*
* @return role ids..
*/
val roles: Set<String>
val roles: Set<RoleId>

companion object {
const val ROLE_KEY = "roles"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package me.ahoo.cosec.cache

import me.ahoo.cache.api.Cache
import me.ahoo.cosec.api.context.request.AppId
import me.ahoo.cosec.api.permission.AppPermission

interface AppPermissionCache : Cache<String, AppPermission>
interface AppPermissionCache : Cache<AppId, AppPermission>
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@

package me.ahoo.cosec.cache

import me.ahoo.cosec.api.context.request.AppId
import me.ahoo.cosec.api.context.request.SpaceId
import me.ahoo.cosec.api.permission.AppRolePermission
import me.ahoo.cosec.api.principal.RoleId
import me.ahoo.cosec.api.principal.SpacedRoleId
import me.ahoo.cosec.authorization.AppRolePermissionRepository
import me.ahoo.cosec.permission.AppRolePermissionData
import me.ahoo.cosec.permission.RolePermissionData
Expand All @@ -24,13 +28,14 @@ class RedisAppRolePermissionRepository(
private val appPermissionCache: AppPermissionCache,
private val rolePermissionCache: RolePermissionCache
) : AppRolePermissionRepository {
override fun getAppRolePermission(appId: String, roleIds: Set<String>): Mono<AppRolePermission> {
override fun getAppRolePermission(appId: AppId, spaceId: SpaceId, roleIds: Set<RoleId>): Mono<AppRolePermission> {
val appPermission = appPermissionCache[appId] ?: return Mono.empty()
val rolePermissions = roleIds.mapNotNull {
val permissions = rolePermissionCache[it] ?: return@mapNotNull null
val spacedRoleId = SpacedRoleId(roleId = it, spaceId = spaceId)
val permissions = rolePermissionCache[spacedRoleId] ?: return@mapNotNull null
RolePermissionData(
it,
permissions,
id = it,
permissions = permissions,
)
}
return AppRolePermissionData(appPermission, rolePermissions).toMono()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package me.ahoo.cosec.cache

import io.github.oshai.kotlinlogging.KotlinLogging
import me.ahoo.cosec.api.policy.Policy
import me.ahoo.cosec.api.policy.PolicyId
import me.ahoo.cosec.api.policy.PolicyType
import me.ahoo.cosec.authorization.PolicyRepository
import me.ahoo.cosec.cache.GlobalPolicyIndexCache.Companion.CACHE_KEY
Expand All @@ -38,7 +39,7 @@ class RedisPolicyRepository(
}
}

override fun getPolicies(policyIds: Set<String>): Mono<List<Policy>> {
override fun getPolicies(policyIds: Set<PolicyId>): Mono<List<Policy>> {
return policyIds.mapNotNull {
policyCache[it]
}.toMono()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@
package me.ahoo.cosec.cache

import me.ahoo.cache.api.Cache
import me.ahoo.cosec.api.permission.PermissionId
import me.ahoo.cosec.api.principal.SpacedRoleId

interface RolePermissionCache : Cache<String, Set<String>>
interface RolePermissionCache : Cache<SpacedRoleId, Set<PermissionId>>
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package me.ahoo.cosec.cache
import io.mockk.every
import io.mockk.mockk
import me.ahoo.cosec.api.policy.Effect
import me.ahoo.cosec.api.principal.SpacedRoleId.Companion.toSpacedRoleId
import me.ahoo.cosec.permission.AppPermissionData
import me.ahoo.cosec.permission.PermissionData
import me.ahoo.cosec.permission.PermissionGroupData
Expand All @@ -20,7 +21,7 @@ class RedisAppRolePermissionRepositoryTest {
val appPermissionCache = mockk<AppPermissionCache>()
every { appPermissionCache.get("appId") } returns null
val permissionRepository = RedisAppRolePermissionRepository(appPermissionCache, mockk())
permissionRepository.getAppRolePermission("appId", setOf("roleId"))
permissionRepository.getAppRolePermission("appId", "", setOf("roleId"))
.test()
.verifyComplete()
}
Expand All @@ -41,10 +42,10 @@ class RedisAppRolePermissionRepositoryTest {
every { appPermissionCache.get("appId") } returns appPermission

val rolePermissionCache = mockk<RolePermissionCache>()
every { rolePermissionCache.get("roleId") } returns setOf(permission.id)
every { rolePermissionCache.get("roleId".toSpacedRoleId()) } returns setOf(permission.id)

val permissionRepository = RedisAppRolePermissionRepository(appPermissionCache, rolePermissionCache)
permissionRepository.getAppRolePermission("appId", setOf("roleId"))
permissionRepository.getAppRolePermission("appId", "", setOf("roleId"))
.test()
.consumeNextWith {
assertThat(it.appPermission, equalTo(appPermission))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@

package me.ahoo.cosec.authorization

import me.ahoo.cosec.api.context.request.AppId
import me.ahoo.cosec.api.context.request.SpaceId
import me.ahoo.cosec.api.permission.AppRolePermission
import me.ahoo.cosec.api.principal.RoleId
import reactor.core.publisher.Mono

interface AppRolePermissionRepository {

fun getAppRolePermission(appId: String, roleIds: Set<String>): Mono<AppRolePermission>
fun getAppRolePermission(appId: AppId, spaceId: SpaceId, roleIds: Set<RoleId>): Mono<AppRolePermission>
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class SimpleAuthorization(
if (context.principal.roles.isEmpty()) {
return Mono.empty()
}
return appRolePermissionRepository.getAppRolePermission(request.appId, context.principal.roles)
return appRolePermissionRepository.getAppRolePermission(request.appId, request.spaceId, context.principal.roles)
.mapNotNull {
verifyAppRolePermission(it, request, context)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@

package me.ahoo.cosec.permission

import me.ahoo.cosec.api.permission.PermissionId
import me.ahoo.cosec.api.permission.RolePermission
import me.ahoo.cosec.api.principal.RoleId

data class RolePermissionData(
override val id: String,
override val permissions: Set<String>
override val id: RoleId,
override val permissions: Set<PermissionId>
) : RolePermission
Loading
Loading