realm.io Retaining Child objects - copy

So I'm using realm to cache and keep all data from our web-platform. which is loaded through an API.
When you fetch yourself as user we're also returning a user role, depending if you're a simple member, admin or whatever.
so it'd basically be
user: {
"username" : "user",
"role" : {"id":1,"name":"admin"}
}
which is cool, since realm stores this just fine in our objects which have the role as a child realmobject.
However when we load content, f/e comments. The object does not contain a role but it can contain the user which is current logged in. The data is being persisted and thus the role will be missing since it's not provided.
Are there any smart ways we could resolve this? or would the only option be to send role information with the user when comments are loaded.

If the username on User is defined as a primary key, you can use createOrUpdate / create(…, update: true) when retrieving the comments from the API to retain the user's role and merge it with the existing cached instance.
let realm = Realm()
let jsonDict = [
"message": "Hello world",
"user": [ "username" : "user" ]
]
realm.create(type: Comment.self, value: jsonDict, update: true)
Note that this works only as long as the role is missing from the retrieved JSON. If it's there as "role": null, the dictionary will contain a NSNull, which will cause that Realm nullifies the link from the user.

Related

Keycloak - Manage realm with user from different realm

Is possible to have user in one realm to manage another realm in keycloak?
My goal is to have 2 realms - adminRealm & userRalm. In adminRealm should be users, which will be able to log in to our admin app and there they could create via Keycloak rest api "ordinary user" which will be placed into userRealm.
Currently my solution working over one realm, where I have admin user which is able to log into my admin app and there he can create users in the same realm. But if I want create users to another realm, I get 403 error. So is there any way how to allow admin user to manage another realm (eg create users etc.)?
You should use master realm for storing admin accounts. Non master realms are isolated from each other. If you look to the clients list in master realm you should see that every realm represented by client with OIDC id like "foo-realm". This clients represents administration REST API for corresponding realms, and users with granted roles from this clients could perform admin requests to corresponding apis.
For example you have foo realm which will contain ordinary application users. To achieve your goal to introduce admin accounts that will be able to manage users from foo you have to create foo-admin user in master realm and grant him foo-realm.realm-admin role. Now this user has total control over foo realm and no control over master realm. You also can map foo-realm.realm-admin role to some group in master realm and add users to it (so if any changes appears in future you will have to change only group role settings)
In case you use terraform your solution would look like this:
data "keycloak_realm" "master" {
realm = "master"
}
data "keycloak_openid_client" "realm_management" {
realm_id = data.keycloak_realm.master.id
client_id = "foo-realm"
}
data "keycloak_role" "query_users" {
realm_id = data.keycloak_realm.master.id
client_id = data.keycloak_openid_client.realm_management.id
name = "query-users"
}
data "keycloak_role" "manage_users" {
realm_id = data.keycloak_realm.master.id
client_id = data.keycloak_openid_client.realm_management.id
name = "manage-users"
}
resource "keycloak_user_roles" "user_admin_roles" {
realm_id = data.keycloak_realm.master.id
user_id = keycloak_user.users_admin.id
role_ids = [
data.keycloak_role.query_users.id,
data.keycloak_role.manage_users.id,
]
}

Is there a way to setup a field-level authorisation on FaunaDB + GraphQL?

I'm having troubles finding a way to hide user emails from everyone, except the owner (user has access to only his email). Is there a way to hide a certain document field, for a certain roles?
Here is an example I found that creates a role with dynamic access to the whole User collection:
CreateRole({
name: "tier1_role",
membership: {
resource: Collection("User"),
predicate: Query(
Lambda("userRef",
// User attribute based rule:
// It grants access only if the User has TIER1 role.
// If so, further rules specified in the privileges
// section are applied next.
Equals(Select(["data", "role"], Get(Var("userRef"))), "TIER1")
)
)
},
privileges: [
{
// Note: 'allUsers' Index is used to retrieve the
// documents from the File collection. Therefore,
// read access to the Index is required here as well.
resource: Index("allUsers"),
actions: { read: true }
}
]
})
I tried to change it a bit, but I wasn't able to set up field-level access.
Let's say I'd set up FaunaDB with GraphQL schema below.
enum UserRole {
TIER1
}
type User {
email: String! #unique
username: String! #unique
role: UserRole!
}
type Query {
allUsers: [User!]
}
type Mutation {
addUsers(new_users: [UserInput]): [User]
#resolver(name: "add_users", paginated: false)
}
How do create a FaunaDB role in such a way that all of the users (except the current one) in resulting array from allUsers query, will not have email field?
I could break User collection into two: one is public, the other is accessible to a document owner, but this sounds wrong.
I'm new to the noSQL concept, so maybe I'm looking at this problem from the wrong perspective?
it's a request that came up a few times. You probably want to do this straight in FaunaDB's ABAC role system but although it provides row-level security, hiding a specific field is currently not provided yet. The feedback has been logged though, we will look into it.
The current way to do this is to split out Users from Accounts and fetch Users instead of Accounts. It would be useful to have something like hidden fields though in the future.
If you think of it, in this case, it does make sense to split authentication information from User information. You never know that you might offer another way to authentication in the future. I still recall from the Phoenix Framework book that they do it there was well and considered it a good practice.
You could also make a thin wrapper using Apollo in a serverless function and filter out these fields when you pass through the results. There is a guide that explains how to build such a thin Apollo middleware that just delegates to FaunaDB https://www.gatlin.io/blog/post/social-login-with-faunadb-and-auth0

Retrieving arbitrary data into nested object with ORM

I am attempting to develop an api in go, to allow the user to specify an arbitrary data structure, and easily set up endpoints that perform CRUD operations on an auto generated postgres database, based on the structure that they define.
For now, I have been using gorm, and am able to have a database automatically generated based on a user-defined set of structs, that support all types of relations (has one, one to many, etc.). I am also able to insert into the generated database, when JSON is sent in through the endpoints.
The issue I have discovered, is when I try to receive the data. It seems where many of the go ORMs fall short on, is mapping data from all tables back into the nested structs of the parent struct.
For example, if the user defines:
type Member struct {
ID string
FirstName string
Hometown Hometown `gorm:"ForeignKey:MemberRefer"`
}
type Hometown struct {
ID string
City string
Province string
MemberRefer string
}
The database creates the tables:
Members
id
first_name
Hometowns
id
city
province
member_refer
However, when retrieving the data, all that is mapped back is:
{
"id": "dc2bb591-506f-40a5-a141-bdc0c8410ba1",
"name": "Kevin Krishna",
"hometown": {
"id": "",
"city": "",
"province": ""
}
}
Does anyone know of a go orm that supports this kind of behaviour?
Thanks
5 sec google search showed me the answer:
Preloading associations
Now that you actually have them properly related, you can .Preload() get the nested object you want:
db.Preload("GoogleAccount").First(&user)
Get nested object in structure in gorm
https://www.google.com/search?q=gorm+nested+struct+golang

Loopback Update User Field

I am trying to update a field in a model that extends the user model. In the API explorer, I set the where field to {"id": 59}, and have the access token one that corresponds with id 59. In the data field I have {"age": 55} where I am just trying to update the age to 55.
The request URL ends up being: http://IP:3000/api/MODEL/update?where=%7B%22id%22%3A%2059%7D&access_token=LONG ACCESS TOKEN VALUE
Which gives an error:
{
"error": {
"statusCode": 401,
"name": "Error",
"message": "Authorization Required",
"code": "AUTHORIZATION_REQUIRED",
}
}
I don't understand why authorization is required when I have a correct access token and the email has been verified. What am I doing wrong?
Loopback by default provides ACL to user model. So by default the update operation can only be changed by the $OWNER, ie. the person himself.
So first login with the username and password, you get the accesstoken. Copy and set the accesstoken in Api Explorer.
Now use the PUT method, which will say Users/{$id}
Open it and you will see 2 fields, data and id. Provide your model's id and provide the data object (the data that needs to be changed)
Hope this helps.

GCS delete bucket ACL always returns 404

I can't seem to delete a GCS bucket ACL that I inserted.
I did a POST to insert an ACL for my service account:
https://www.googleapis.com/storage/v1/b/arqclient-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s/acl
with this request JSON:
{
"entity" : "user-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s#developer.gserviceaccount.com",
"role" : "WRITER"
}
When I list the ACLs, the ACL I inserted looks like this:
{
bucket = "arqclient-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s";
entity = "user-00b4903a970addfce72044c71917166bd27bc8b9ab94a391dc841b526cd9466f";
entityId = 00b4903a970addfce72044c71917166bd27bc8b9ab94a391dc841b526cd9466f;
etag = "CA0=";
id = "arqclient-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s/user-00b4903a970addfce72044c71917166bd27bc8b9ab94a391dc841b526cd9466f";
kind = "storage#bucketAccessControl";
role = WRITER;
selfLink = "https://www.googleapis.com/storage/v1/b/arqclient-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s/acl/user-00b4903a970addfce72044c71917166bd27bc8b9ab94a391dc841b526cd9466f";
}
So apparently my "user-<emailaddress>" gets converted some other kind of ID.
When I try to delete the ACL:
DELETE https://www.googleapis.com/storage/v1/b/arqclient-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0sfkjhfkjhf/acl/user-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s%40developer.gserviceaccount.com
I always get a 404 error.
What's wrong with my DELETE command? The doc says I can use user-emailAddress, but that doesn't work.
If I use the entity ID from the listing, "user-00b4903a970addfce72044c71917166bd27bc8b9ab94a391dc841b526cd9466f", that works through the Google APIs Explorer.
If I'm supposed to use the entity ID, how do I get the entity ID given a service-account email address?
The access control page of the Google API docs says "You can find a user's Google Storage ID by retrieving the ACL of an object that the user uploaded." https://cloud.google.com/storage/docs/access-control?hl=en#google-storage-ids
So I guess the best answer is to create an object with my service account, retrieve its ACL, and find the entity ID in the ACL.