This section of the documentation is an Role Based Access Control tutorial.
To read and learn about the syntax and language for declaring RBAC within Semantic Object schemas, see the
Role Based Access Control (RBAC) section within the Semantic Object Modeling language
documentation.
Let’s say we have defined the following role in the schema:
CharacterRead:
description: "Role which can read all Character properties"
actions: [
"Character/*/read"
]
The user CharacterRead
has permissions only over the abstract class Character
.
When querying, abstract classes permissions are resolved from the lowest concrete class up. The abstract
class is constrained to query other classes that are inherited from the abstract class.
Since the properties degree
and cybernetics
are defined in the concrete
classes for Droid
and Human
, the following request will pass but will contain errors for each
field that cannot be read by CharacterRead
role.
Loading...
https://swapi-platform.ontotext.com/graphql
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlVWWHMyZ2hidFhBSUtyc2V5QnduTVYzR0dBSEZaRzMwIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE2NjAyMjk3MzMsImlhdCI6MTU5NzE1NzczMywiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiMGRkMGI5OGEtMTM5Yy00ZDE2LWFkZjAtYzY0ZDUxMDU5YzFjIiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6ImNoYXJhY3RlcnJlYWR1c2VyQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByZWZlcnJlZF91c2VybmFtZSI6ImNoYXJhY3RlcnJlYWR1c2VyIiwiYXBwbGljYXRpb25JZCI6IjY3MmNhN2IzLWMzNzItNGRmMy04MmQ4LTlhMWEwZDdkNjhjMSIsInJvbGVzIjpbIkNoYXJhY3RlclJlYWQiXX0.0a8bJEKCcoigR2HnMEr9dltyGaa5hfbfyUufJQPXLb4
true
query allCharacters {
character {
name
__typename
... on Droid {
degree
}
... on Human {
cybernetics
}
}
}
What if the role has permissions to view only Human
class and we try to execute a query for Character
class?
HumanRead:
description: "Role which can read all Human properties"
actions: [
"Human/*/read"
]
Loading...
https://swapi-platform.ontotext.com/graphql
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlVWWHMyZ2hidFhBSUtyc2V5QnduTVYzR0dBSEZaRzMwIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE2NjAyMjk3NzksImlhdCI6MTU5NzE1Nzc3OSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiNGVjOGJjMTctNmM2ZS00ZTEyLWEzNTktOWU4YzUzNWE1M2FmIiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6Imh1bWFucmVhZHVzZXJAZXhhbXBsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiaHVtYW5yZWFkIiwiYXBwbGljYXRpb25JZCI6IjY3MmNhN2IzLWMzNzItNGRmMy04MmQ4LTlhMWEwZDdkNjhjMSIsInJvbGVzIjpbIkh1bWFuUmVhZCJdfQ.vjnOA_5YgmZ93TDKBDmlAYcPzmeKgHMOgeHka4rSI18
true
query allCharacters {
character {
name
__typename
... on Droid {
degree
}
... on Human {
cybernetics
}
}
}
You will notice that only humans are returned and all other characters have been omitted.
If we try to query Droid
with the same role, then we will get an error message stating that we do not have access to this object:
Loading...
https://swapi-platform.ontotext.com/graphql
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlVWWHMyZ2hidFhBSUtyc2V5QnduTVYzR0dBSEZaRzMwIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE2NjAyMjk3NzksImlhdCI6MTU5NzE1Nzc3OSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiNGVjOGJjMTctNmM2ZS00ZTEyLWEzNTktOWU4YzUzNWE1M2FmIiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6Imh1bWFucmVhZHVzZXJAZXhhbXBsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiaHVtYW5yZWFkIiwiYXBwbGljYXRpb25JZCI6IjY3MmNhN2IzLWMzNzItNGRmMy04MmQ4LTlhMWEwZDdkNjhjMSIsInJvbGVzIjpbIkh1bWFuUmVhZCJdfQ.vjnOA_5YgmZ93TDKBDmlAYcPzmeKgHMOgeHka4rSI18
true
query getDroid {
droid {
id
name
degree
}
}
We can be even more specific with the permissions and use filters. Let’s take a look at this role:
HumanFromTatooineRead:
description: "Role which can read properties of Human with homeworld Tatooine"
actions: [
'Human/*/read/(where: {homeworld: {name: {EQ: "Tatooine"}}})',
'Planet/*/read'
]
It will give access only to the Human
-s from Tatooine. The permission over Planet
are needed
in order to retrieve the planet of the Humans
-s and make sure the results are correct:
Loading...
https://swapi-platform.ontotext.com/graphql
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlVWWHMyZ2hidFhBSUtyc2V5QnduTVYzR0dBSEZaRzMwIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE2NjA0NzcwNDgsImlhdCI6MTU5NzQwNTA0OCwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZGQ0ZjEwZjItZjJmNi00ODhiLWJjMGUtNTdkNjE4NTIwZGFmIiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6Imh1bWFuZnJvbXRhdG9vaW5lcmVhZHVzZXJAZXhhbXBsZS54b20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiSHVtYW5Gcm9tVGF0b29pbmVSZWFkVXNlciIsImFwcGxpY2F0aW9uSWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJyb2xlcyI6WyJIdW1hbkZyb21UYXRvb2luZVJlYWQiXX0.SlV9CHH59KhAwF3_-DlDo6TSqQRPyd_3jiix4e4FBTU
true
query allHuman {
human {
id
name
homeworld {
id
name
}
}
}
Create, update, and delete mutations allow you to perform selections as part of the response.
However, if the role has no read access, the response will ignore the selections.
For example if we have the following role:
PersonWriter:
description: "Can write People and read their id."
actions: [
"Person/*/write",
"Person/id/read"
]
This request will pass but will contain errors for each field that cannot be read by PersonWriter
.
Loading...
https://swapi-platform.ontotext.com/graphql
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlVWWHMyZ2hidFhBSUtyc2V5QnduTVYzR0dBSEZaRzMwIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE2NjAzMDg1ODUsImlhdCI6MTU5NzIzNjU4NSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZWZkYTAwNDYtN2ZlOC00ZDQ5LWI2MGQtMGZjM2U1NGQwYmY1IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InBlcnNvbndyaXRlcnVzZXJAZXhhbXBsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiUGVyc29uV3JpdGVyVXNlciIsImFwcGxpY2F0aW9uSWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJyb2xlcyI6WyJQZXJzb25Xcml0ZXIiXX0.VIa85WONlWS2fhfvmJl_GgIdq9jr2VMcwPE2J9oFRv0
true
mutation createJemRayfield {
create_Person(objects: [{rdfs_label: {value: "Jem Rayfield"}, birthDate: "2020-01-01"}]) {
person {
id
name
birthDate
}
affected_objects {
kind
ids
}
}
}
Note the id
of the newly created Person. We will be using this id
in the examples below.
It is important to note that a role with a property write action cannot delete or set a property to null
| []
. For example, run the following mutation replacing person_id
with the ID of the person we just created in the previous example:
Loading...
https://swapi-platform.ontotext.com/graphql
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlVWWHMyZ2hidFhBSUtyc2V5QnduTVYzR0dBSEZaRzMwIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE2NjAzMDg1ODUsImlhdCI6MTU5NzIzNjU4NSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZWZkYTAwNDYtN2ZlOC00ZDQ5LWI2MGQtMGZjM2U1NGQwYmY1IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InBlcnNvbndyaXRlcnVzZXJAZXhhbXBsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiUGVyc29uV3JpdGVyVXNlciIsImFwcGxpY2F0aW9uSWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJyb2xlcyI6WyJQZXJzb25Xcml0ZXIiXX0.VIa85WONlWS2fhfvmJl_GgIdq9jr2VMcwPE2J9oFRv0
true
mutation {
update_Person(
objects: {
birthDate: null
},
where: {ID: "person_id"})
{
person {
id
}
affected_objects {
kind
ids
}
}
}
The request will be rejected with Unauthorized errors, since setting birthDate
to null
is effectively deleting the birthDate
property.
The PersonWriter
role actions
explicitly states that this role can only write/update this property.
The GraphQL schema may set a property as optional, so you will need RBAC rules to manage controlled removal of such a property by roles with delete access.
If you do not have write permissions assigned and try to perform a mutation, then the mutation will fail and no data will be inserted, updated, or deleted.
ReadOnly:
description: "Users which can read all Objects and properties"
actions: [
"*/*/read"
]
Loading...
https://swapi-platform.ontotext.com/graphql
true
mutation createJemRayfield {
create_Person(objects: [{rdfs_label: {value: "Jem Rayfield"}, birthDate: "2020-01-01"}]) {
person {
id
name
birthDate
}
affected_objects {
kind
ids
}
}
}
It is important to remember that notActions
take precedence over actions
.
If we have a role such as:
PersonNoDelete:
description: "Can read and update People."
actions: [
"Person/*/*"
]
notActions: [
"Person/*/delete"
]
Then you will not be able to delete objects.
Loading...
https://swapi-platform.ontotext.com/graphql
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlVWWHMyZ2hidFhBSUtyc2V5QnduTVYzR0dBSEZaRzMwIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE2NjAzMDg2MjQsImlhdCI6MTU5NzIzNjYyNCwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiMzFiMWI0MGYtOWRkOC00YTdlLWFlYzgtMjQ1NTU2ZTY3Nzk1IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InBlcnNvbm5vZGVsZXRldXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJQZXJzb25Ob0RlbGV0ZVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUGVyc29uTm9EZWxldGUiXX0.KX4fBY676963eYkVVTGJaSncRPvAJYT_hVp0l00jAZw
true
mutation {
delete_Person (where: {ID: "person_id"}) {
person {
id
}
}
}
Or remove property values.
Loading...
https://swapi-platform.ontotext.com/graphql
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlVWWHMyZ2hidFhBSUtyc2V5QnduTVYzR0dBSEZaRzMwIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE2NjAzMDg2MjQsImlhdCI6MTU5NzIzNjYyNCwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiMzFiMWI0MGYtOWRkOC00YTdlLWFlYzgtMjQ1NTU2ZTY3Nzk1IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InBlcnNvbm5vZGVsZXRldXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJQZXJzb25Ob0RlbGV0ZVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUGVyc29uTm9EZWxldGUiXX0.KX4fBY676963eYkVVTGJaSncRPvAJYT_hVp0l00jAZw
true
mutation {
update_Person(
objects: {
birthDate: null
},
where: {ID: "person_id"})
{
person {
id
}
affected_objects {
kind
ids
}
}
}
Filters can be used for mutations as well. To illustrate this, let’s create a second Person
:
Loading...
https://swapi-platform.ontotext.com/graphql
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Imc5Vm1fbGlyaHptdlk1dklsS1dGMXZCV0pSSWtGZ3NtIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE2NTEzMTEyNDMsImlhdCI6MTU4ODIzOTI0MywiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiYTQwYjczMTAtMDQzYy00NzI0LWFmNWYtMTQ1YmU4MDFlMmM3IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InBlb3BsZWxvY2F0aW9uQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByZWZlcnJlZF91c2VybmFtZSI6InBlb3BsZWxvY2F0aW9uIiwiYXBwbGljYXRpb25JZCI6IjY3MmNhN2IzLWMzNzItNGRmMy04MmQ4LTlhMWEwZDdkNjhjMSIsInJvbGVzIjpbIlBlcnNvbkNvdW50cnlMb2NhdGlvbiJdfQ.1MUJDbnQeYdIkgrS2OYeQ34ZPnyKNBYOUNq84LpYVGk
true
mutation createGeorgeLucas {
create_Person(objects: [{rdfs_label: {value: "George Lucas"}, birthDate: "1944-05-14"}]) {
person {
id
name
birthDate
}
affected_objects {
kind
ids
}
}
}
Note the id
of the second person as well.
Now try to delete first “Jem Rayfield” using the following role:
PersonJemAdmin:
description: "Full permission over Jem Rayfield."
actions: [
'Person/*/*/(where: {name: {EQ: "Jem Rayfield"}})'
]
In order to do so, replace person_id
with the id
of Jem:
Loading...
https://swapi-platform.ontotext.com/graphql
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlVWWHMyZ2hidFhBSUtyc2V5QnduTVYzR0dBSEZaRzMwIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE2NjAzMDg2NTIsImlhdCI6MTU5NzIzNjY1MiwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiNDdmOWQyOGItMzQzNS00MGNlLWFmOWYtZTQxNjk2OTViOTQyIiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InBlcnNvbmplbWFkbWludXNlckBleGFtbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByZWZlcnJlZF91c2VybmFtZSI6IlBlcnNvbkplbUFkbWluVXNlciIsImFwcGxpY2F0aW9uSWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJyb2xlcyI6WyJQZXJzb25KZW1BZG1pbiJdfQ.nf0JzmVV4BU2ZqOD1PSI8Atc9bFEtEvm90EYGSfCGhM
true
mutation {
delete_Person (where: {ID: "person_id"}) {
person {
id
}
affected_objects {
kind
ids
}
}
}
The mutation will pass. Now run the same mutation but using the id
of “George Lucas”. You will
not be able to delete him, as the filter in the action will prevent it.
With the same role, you can try to create a Person
with a name different from Jem Rayfield
:
Loading...
https://swapi-platform.ontotext.com/graphql
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlVWWHMyZ2hidFhBSUtyc2V5QnduTVYzR0dBSEZaRzMwIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE2NjAzMDg2NTIsImlhdCI6MTU5NzIzNjY1MiwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiNDdmOWQyOGItMzQzNS00MGNlLWFmOWYtZTQxNjk2OTViOTQyIiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InBlcnNvbmplbWFkbWludXNlckBleGFtbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByZWZlcnJlZF91c2VybmFtZSI6IlBlcnNvbkplbUFkbWluVXNlciIsImFwcGxpY2F0aW9uSWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJyb2xlcyI6WyJQZXJzb25KZW1BZG1pbiJdfQ.nf0JzmVV4BU2ZqOD1PSI8Atc9bFEtEvm90EYGSfCGhM
true
mutation createPerson {
create_Person(objects: [{rdfs_label: {value: "Random Person"}, birthDate: "2020-01-01"}]) {
person {
id
}
}
}
You will see that the mutation gets blocked.