Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Init acls provisioning #5222

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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 @@ -31,8 +31,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.model.ResourceF._
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchResults
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchResults.searchResultsJsonLdEncoder
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.Permissions.{acls => aclsPermissions}
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.model.Permission
import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Identity, Label, ProjectRef}
import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Label, ProjectRef}
import io.circe._
import io.circe.generic.extras.Configuration
import io.circe.generic.extras.semiauto.deriveConfiguredDecoder
Expand Down Expand Up @@ -196,23 +195,6 @@ class AclsRoutes(identities: Identities, acls: Acls, aclCheck: AclCheck)(implici

object AclsRoutes {

final private case class IdentityPermissions(identity: Identity, permissions: Set[Permission])

final private[routes] case class AclValues(value: Seq[(Identity, Set[Permission])])

private[routes] object AclValues {

implicit private val identityPermsDecoder: Decoder[IdentityPermissions] = {
implicit val config: Configuration = Configuration.default.withStrictDecoding
deriveConfiguredDecoder[IdentityPermissions]
}

implicit val aclValuesDecoder: Decoder[AclValues] =
Decoder
.decodeSeq[IdentityPermissions]
.map(seq => AclValues(seq.map(value => value.identity -> value.permissions)))
}

final private[routes] case class ReplaceAcl(acl: AclValues)
private[routes] object ReplaceAcl {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package ch.epfl.bluebrain.nexus.delta.routes

import ch.epfl.bluebrain.nexus.delta.routes.AclsRoutes.PatchAcl.{Append, Subtract}
import ch.epfl.bluebrain.nexus.delta.routes.AclsRoutes.{AclValues, PatchAcl, ReplaceAcl}
import ch.epfl.bluebrain.nexus.delta.routes.AclsRoutes.{PatchAcl, ReplaceAcl}
import ch.epfl.bluebrain.nexus.delta.sdk.acls.model.AclValues
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.Permissions.resources
import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity
import ch.epfl.bluebrain.nexus.testkit.scalatest.BaseSpec
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import ch.epfl.bluebrain.nexus.delta.kernel.error.FormatError
import ch.epfl.bluebrain.nexus.delta.sdk.error.FormatErrors.IllegalAclAddressFormatError
import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Label, ProjectRef}
import doobie.{Get, Put}
import io.circe.{Decoder, Encoder}
import io.circe.{Decoder, Encoder, KeyDecoder}

/**
* Enumeration of possible ACL addresses. An ACL address is the address where a certain ACL is anchored.
Expand Down Expand Up @@ -100,6 +100,8 @@ object AclAddress {

implicit val aclAddressOrdering: Ordering[AclAddress] = Ordering.by(_.string)

implicit val aclAddressKeyDecoder: KeyDecoder[AclAddress] = KeyDecoder.instance(AclAddress.fromString(_).toOption)

implicit val aclAddressEncoder: Encoder[AclAddress] = Encoder.encodeString.contramap(_.string)
implicit val aclAddressDecoder: Decoder[AclAddress] = Decoder.decodeString.emap { str =>
AclAddress.fromString(str).leftMap(_.getMessage)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ch.epfl.bluebrain.nexus.delta.sdk.acls.model

import io.circe.Decoder

final case class AclBatchReplace(acls: Vector[Acl])

object AclBatchReplace {

implicit val aclBatchReplaceDecoder: Decoder[AclBatchReplace] = Decoder[Map[AclAddress, AclValues]].map { valuesMap =>
val acls = valuesMap.foldLeft(Vector.empty[Acl]) { case (acc, (address, values)) =>
acc :+ Acl(address, values.value: _*)
}
AclBatchReplace(acls)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ch.epfl.bluebrain.nexus.delta.sdk.acls.model

import ch.epfl.bluebrain.nexus.delta.sdk.permissions.model.Permission
import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity
import io.circe.Decoder
import io.circe.generic.extras.Configuration
import io.circe.generic.extras.semiauto.deriveConfiguredDecoder

final case class AclValues(value: Seq[(Identity, Set[Permission])])

object AclValues {

final private case class IdentityPermissions(identity: Identity, permissions: Set[Permission])

implicit private val identityPermsDecoder: Decoder[IdentityPermissions] = {
implicit val config: Configuration = Configuration.default.withStrictDecoding
deriveConfiguredDecoder[IdentityPermissions]
}

implicit val aclValuesDecoder: Decoder[AclValues] =
Decoder
.decodeSeq[IdentityPermissions]
.map(seq => AclValues(seq.map(value => value.identity -> value.permissions)))

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package ch.epfl.bluebrain.nexus.delta.sdk.acls.model

import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.{Group, User}
import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label
import ch.epfl.bluebrain.nexus.testkit.mu.NexusSuite
import ch.epfl.bluebrain.nexus.delta.sdk.permissions.Permissions.{acls, projects, resources}

class AclBatchReplaceSuite extends NexusSuite {

test("Deserialize properly the json payload") {
val payload = json"""
{
"/" : [
{
"permissions": [
"acls/read",
"acls/write"
],
"identity": {
"realm": "realm",
"subject": "superuser"
}
},
{
"permissions": [
"projects/read",
"projects/write"
],
"identity": {
"realm": "realm",
"group": "admins"
}
}
],
"/bbp": [
{
"permissions": [
"resources/read",
"resources/write"
],
"identity": {
"realm": "realm",
"group": "bbp-users"
}
}
],
"/bbp/atlas": [
{
"permissions": [
"resources/read",
"resources/write"
],
"identity": {
"realm": "realm",
"group": "atlas-users"
}
}
]
}"""

val realm = Label.unsafe("realm")
val bbp = Label.unsafe("bbp")
val atlas = Label.unsafe("atlas")
val expected = AclBatchReplace(
Vector(
Acl(
AclAddress.Root,
User("superuser", realm) -> Set(acls.read, acls.write),
Group("admins", realm) -> Set(projects.read, projects.write)
),
Acl(AclAddress.Organization(bbp), Group("bbp-users", realm) -> Set(resources.read, resources.write)),
Acl(AclAddress.Project(bbp, atlas), Group("atlas-users", realm) -> Set(resources.read, resources.write))
)
)

assertEquals(
payload.as[AclBatchReplace],
Right(expected)
)
}

}