oso
oso copied to clipboard
Oso does not support Kotlin data classes
Hey 👋 Finally getting around to trialing Oso as an auth solution for a Kotlin application that I'm building.
However, it seems that Oso does not support Kotlin data classes :( Or, as is always possible... I'm just doing something dumb
I am trying to emulate the Java quickstart example, with a User trying to read from a repository.
I have the following models
data class Repo(
val id: UUID,
val name: String,
val isPublic: Boolean
)
data class User (
val id: UUID,
val email: String,
val repoRoles: List<RepoRole>
)
I have set up OSO with the following
private val oso: Oso = Oso()
init {
// On a tangent... it doesn't seem to even load
// unless I explicitly repeat the class name as the second param
oso.registerClass(Repo::class.java, "Repo")
oso.registerClass(User::class.java, "User")
oso.loadStr(
"""
allow(actor, action, resource) if
has_permission(actor, action, resource);
actor User {}
resource Repo {
permissions = ["read", "push", "delete"];
roles = ["contributor", "maintainer", "admin"];
"read" if "contributor";
"push" if "maintainer";
"delete" if "admin";
"maintainer" if "admin";
"contributor" if "maintainer";
}
# This rule tells Oso how to fetch roles for a Repo
has_role(actor: User, role_name: String, Repo: Repo) if
role in actor.repoRoles and
role_name = role.name and
Repo = role.Repo;
has_permission(_actor: User, "read", Repo: Repo) if
Repo.isPublic;
allow(actor, action, resource) if
has_permission(actor, action, resource);
""".trimIndent()
)
}
Just as a test, I have created a repo with isPublic=true
with name test
. However, when I run the following
fun readByName(name: String): RepoModels.Response {
val result = Repo(
id = UUID.randomUUID(),
name = name,
isPublic = true
)
val user = User(
id = UUID.randomUUID(),
email = "[email protected]",
repoRoles = listOf(RepoRole(role = "admin", repo = result))
)
oso.authorize(user, "read", result)
return RepoModels.Response.fromRepo(result)
}
I get an authorization error from oso
com.osohq.oso.Exceptions$NotFoundException: Oso NotFoundException -- The current user does not have permission to read the given resource. You should handle this error by returning a 404 error to the client.
at com.osohq.oso.Oso.authorize(Oso.java:110)
at com.osohq.oso.Oso.authorize(Oso.java:118)
at io.bkbn.sourdough.api.service.RepoService.readByName(RepoService.kt:81)
// ...
If it helps, I have pushed all of this code to a repo https://github.com/bkbnio/oso-poc Instructions in the README for how to run the app. If you have any issues with getting it set up just let me know :)
You can emulate this error by running GET localhost:8080/repo?name=test
Out of curiosity I tried making this work in https://github.com/osohq/oso/pull/1662.
Seems to work with some to the repo
Index: api/src/main/kotlin/io/bkbn/sourdough/api/service/RepoService.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/api/src/main/kotlin/io/bkbn/sourdough/api/service/RepoService.kt b/api/src/main/kotlin/io/bkbn/sourdough/api/service/RepoService.kt
--- a/api/src/main/kotlin/io/bkbn/sourdough/api/service/RepoService.kt (revision e4e856f304b1c09de9f2cdcdb658dce59deffab5)
+++ b/api/src/main/kotlin/io/bkbn/sourdough/api/service/RepoService.kt (date 1673734442646)
@@ -35,10 +35,10 @@
}
# This rule tells Oso how to fetch roles for a Repo
-has_role(actor: User, role_name: String, Repo: Repo) if
+has_role(actor: User, role_name: String, repo: Repo) if
role in actor.repoRoles and
- role_name = role.name and
- Repo = role.Repo;
+ role_name = role.role and
+ repo = role.repo;
has_permission(_actor: User, "read", Repo: Repo) if
Repo.isPublic;
Index: api/build.gradle.kts
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/api/build.gradle.kts b/api/build.gradle.kts
--- a/api/build.gradle.kts (revision e4e856f304b1c09de9f2cdcdb658dce59deffab5)
+++ b/api/build.gradle.kts (date 1673734519566)
@@ -41,7 +41,7 @@
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
// Auth
- implementation("com.osohq:oso:0.26.4")
+ implementation("com.osohq:oso:0.26.5-SNAPSHOT")
}
testing {

I used this test for faster feedback:
package io.bkbn.sourdough.api.service
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
internal class RepoServiceTest {
@Test
internal fun `can read by name`() {
val response = RepoService.readByName("foo")
assertEquals("foo", response.name)
}
}