Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a339274
feat(services): Do not delete permissions in `RepositoryService`
oheger-bosch Oct 29, 2025
22b639e
feat(services): Do not sync permissions in `ProductService`
oheger-bosch Oct 29, 2025
e39e41b
feat(services): Do not sync permissions in `OrganizationService`
oheger-bosch Oct 29, 2025
6a2ebb2
feat(authorization): Add useful functionality to roles
oheger-bosch Oct 30, 2025
7cdfc80
fix(authorization): Tweak the permissions in role classes
oheger-bosch Oct 31, 2025
d0059cd
feat(authorization): Rework the `listUsers` function
oheger-bosch Oct 30, 2025
00124b3
feat(authorization): Compute user roles in parallel
oheger-bosch Oct 31, 2025
7864523
feat(authorization): Add mappings for roles
oheger-bosch Oct 31, 2025
b3f66a7
feat(services): Add a function to check whether a user exists
oheger-bosch Oct 31, 2025
0386cb8
fix(authorization): Ignore unknown users when resolving multiple IDs
oheger-bosch Nov 3, 2025
a1b1e83
feat(authorization): Introduce `InvalidHierarchyIdException`
oheger-bosch Nov 3, 2025
3f70822
feat(authorization): Handle exceptions during authentication
oheger-bosch Nov 4, 2025
61d3543
feat(authorization): Support checking for a principal
oheger-bosch Nov 4, 2025
866b48f
feat(authorization): Add authorized routes with paths
oheger-bosch Nov 5, 2025
ecfc0d0
feat(authorization): Integrate new authorization with routes
oheger-bosch Nov 3, 2025
ea455af
feat(authorization): Integrate new authorization with components
oheger-bosch Nov 5, 2025
a351de8
test(infrastructure-services): Add missing authorization tests
oheger-bosch Nov 6, 2025
b7f58df
test(authorization): Optimize authorization tests
oheger-bosch Nov 6, 2025
f455838
fix(authorization): Fix hierarchy filters for superusers
oheger-bosch Nov 7, 2025
95eb6b2
feat(authorization): Correctly filter products
oheger-bosch Nov 7, 2025
b99f6d2
feat(authorization): Correctly filter repositories
oheger-bosch Nov 7, 2025
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
2 changes: 1 addition & 1 deletion components/admin-config/backend/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ dependencies {
implementation(libs.exposedCore)
implementation(libs.exposedKotlinDatetime)

routesImplementation(projects.components.authorizationKeycloak.backend)
routesImplementation(projects.components.authorization.backend)
routesImplementation(projects.shared.apiModel)
routesImplementation(projects.shared.ktorUtils)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import io.ktor.server.routing.Route
import org.eclipse.apoapsis.ortserver.components.adminconfig.Config
import org.eclipse.apoapsis.ortserver.components.adminconfig.ConfigKey
import org.eclipse.apoapsis.ortserver.components.adminconfig.ConfigTable
import org.eclipse.apoapsis.ortserver.components.authorization.keycloak.requireAuthenticated
import org.eclipse.apoapsis.ortserver.components.authorization.routes.OrtServerPrincipal.Companion.requirePrincipal
import org.eclipse.apoapsis.ortserver.shared.ktorutils.jsonBody
import org.eclipse.apoapsis.ortserver.shared.ktorutils.requireParameter
import org.eclipse.apoapsis.ortserver.shared.ktorutils.respondError
Expand Down Expand Up @@ -68,7 +68,7 @@ internal fun Route.getConfigByKey(db: Database) = get("admin/config/{key}", {
}
}
}) {
requireAuthenticated()
requirePrincipal()

val keyParameter = call.requireParameter("key")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

package org.eclipse.apoapsis.ortserver.components.adminconfig.routes

import io.github.smiley4.ktoropenapi.post

import io.ktor.http.HttpStatusCode
import io.ktor.server.request.receive
import io.ktor.server.response.respond
Expand All @@ -29,7 +27,8 @@ import io.ktor.server.routing.Route
import org.eclipse.apoapsis.ortserver.components.adminconfig.Config
import org.eclipse.apoapsis.ortserver.components.adminconfig.ConfigKey
import org.eclipse.apoapsis.ortserver.components.adminconfig.ConfigTable
import org.eclipse.apoapsis.ortserver.components.authorization.keycloak.requireSuperuser
import org.eclipse.apoapsis.ortserver.components.authorization.routes.post
import org.eclipse.apoapsis.ortserver.components.authorization.routes.requireSuperuser
import org.eclipse.apoapsis.ortserver.shared.ktorutils.jsonBody
import org.eclipse.apoapsis.ortserver.shared.ktorutils.requireParameter
import org.eclipse.apoapsis.ortserver.shared.ktorutils.respondError
Expand Down Expand Up @@ -69,9 +68,7 @@ internal fun Route.setConfigByKey(db: Database) = post("admin/config/{key}", {
description = "The config key is invalid."
}
}
}) {
requireSuperuser()

}, requireSuperuser()) {
val keyParameter = call.requireParameter("key")

val key = runCatching {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,12 @@ enum class OrganizationPermission {
/** Permission to delete the [Organization]. */
DELETE
}

/**
* The set of permissions required by the role to read an organization. (This is defined here to avoid circular
* dependencies, as it is referenced by multiple role classes.)
*/
internal val organizationReadPermissions = setOf(
OrganizationPermission.READ,
OrganizationPermission.READ_PRODUCTS
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package org.eclipse.apoapsis.ortserver.components.authorization.rights

import org.eclipse.apoapsis.ortserver.model.CompoundHierarchyId

/**
* This enum contains the available roles for [organizations][org.eclipse.apoapsis.ortserver.model.Organization]. It
* maps the permissions available for an organization to the default roles [READER], [WRITER], and [ADMIN].
Expand All @@ -35,10 +37,7 @@ enum class OrganizationRole(
) : Role {
/** A role that grants read permissions for an [org.eclipse.apoapsis.ortserver.model.Organization]. */
READER(
organizationPermissions = setOf(
OrganizationPermission.READ,
OrganizationPermission.READ_PRODUCTS
),
organizationPermissions = organizationReadPermissions,
productPermissions = ProductRole.READER.productPermissions,
repositoryPermissions = RepositoryRole.READER.repositoryPermissions
),
Expand All @@ -63,5 +62,7 @@ enum class OrganizationRole(
organizationPermissions = OrganizationPermission.entries.toSet(),
productPermissions = ProductPermission.entries.toSet(),
repositoryPermissions = RepositoryPermission.entries.toSet()
)
);

override val level = CompoundHierarchyId.ORGANIZATION_LEVEL
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,12 @@ enum class ProductPermission {
/** Permission to delete the [Product]. */
DELETE
}

/**
* The set of permissions required by the role to read a product. (This is defined here to avoid circular dependencies,
* as it is referenced by multiple role classes.)
*/
internal val productReadPermissions = setOf(
ProductPermission.READ,
ProductPermission.READ_REPOSITORIES
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package org.eclipse.apoapsis.ortserver.components.authorization.rights

import org.eclipse.apoapsis.ortserver.model.CompoundHierarchyId

/**
* This enum contains the available roles for [products][org.eclipse.apoapsis.ortserver.model.Product]. It
* maps the permissions available for a product to the default roles [READER], [WRITER], and [ADMIN].
Expand All @@ -29,16 +31,13 @@ package org.eclipse.apoapsis.ortserver.components.authorization.rights
* - The constants are expected to be listed in increasing order of permissions.
*/
enum class ProductRole(
override val organizationPermissions: Set<OrganizationPermission> = setOf(OrganizationPermission.READ),
override val organizationPermissions: Set<OrganizationPermission> = organizationReadPermissions,
override val productPermissions: Set<ProductPermission>,
override val repositoryPermissions: Set<RepositoryPermission>
) : Role {
/** A role that grants read permissions for a [org.eclipse.apoapsis.ortserver.model.Product]. */
READER(
productPermissions = setOf(
ProductPermission.READ,
ProductPermission.READ_REPOSITORIES
),
productPermissions = productReadPermissions,
repositoryPermissions = RepositoryRole.READER.repositoryPermissions
),

Expand All @@ -61,5 +60,7 @@ enum class ProductRole(
ADMIN(
productPermissions = ProductPermission.entries.toSet(),
repositoryPermissions = RepositoryPermission.entries.toSet()
)
);

override val level = CompoundHierarchyId.PRODUCT_LEVEL
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@

package org.eclipse.apoapsis.ortserver.components.authorization.rights

import org.eclipse.apoapsis.ortserver.model.CompoundHierarchyId

/**
* This enum contains the available roles for [repositories][org.eclipse.apoapsis.ortserver.model.Repository]. It
* maps the permissions available for a product to the default roles [READER], [WRITER], and [ADMIN].
*/
enum class RepositoryRole(
override val organizationPermissions: Set<OrganizationPermission> = setOf(OrganizationPermission.READ),
override val productPermissions: Set<ProductPermission> = setOf(ProductPermission.READ),
override val organizationPermissions: Set<OrganizationPermission> = organizationReadPermissions,
override val productPermissions: Set<ProductPermission> = productReadPermissions,
override val repositoryPermissions: Set<RepositoryPermission>
) : Role {
/** A role that grants read permissions for a [org.eclipse.apoapsis.ortserver.model.Repository]. */
Expand All @@ -49,5 +51,7 @@ enum class RepositoryRole(
/** A role that grants all permissions for a [org.eclipse.apoapsis.ortserver.model.Repository]. */
ADMIN(
repositoryPermissions = RepositoryPermission.entries.toSet()
)
);

override val level: Int = CompoundHierarchyId.REPOSITORY_LEVEL
}
32 changes: 32 additions & 0 deletions components/authorization/backend/src/main/kotlin/rights/Role.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package org.eclipse.apoapsis.ortserver.components.authorization.rights

import org.eclipse.apoapsis.ortserver.model.CompoundHierarchyId

/**
* An interface to define common properties of all roles in the authorization system.
*
Expand All @@ -27,6 +29,36 @@ package org.eclipse.apoapsis.ortserver.components.authorization.rights
* specific repository should also be entitled to view the product and the organization the repository belongs to.
*/
sealed interface Role {
companion object {
/**
* Return a [List] of all roles defined for the given hierarchy [level]. For an invalid level, return an empty
* list.
*/
fun rolesForLevel(level: Int): List<Role> =
when (level) {
CompoundHierarchyId.ORGANIZATION_LEVEL -> OrganizationRole.entries
CompoundHierarchyId.PRODUCT_LEVEL -> ProductRole.entries
CompoundHierarchyId.REPOSITORY_LEVEL -> RepositoryRole.entries
else -> emptyList()
}

/**
* Return the role with the given [name] defined for the given hierarchy [level], or null if no such role
* exists.
*/
fun getRoleByNameAndLevel(level: Int, name: String): Role? =
rolesForLevel(level).find { it.name == name }
}

/** The name of this role. */
val name: String

/**
* The level in the hierarchy this role is defined for. The value corresponds to the constants defined by the
* [org.eclipse.apoapsis.ortserver.model.CompoundHierarchyId] companion object.
*/
val level: Int

/** A set with permissions that are granted by this role on the organization level. */
val organizationPermissions: Set<OrganizationPermission>

Expand Down
Loading