UDFs encapsulation

I have to specify access to collections and UDFs that are called by a UDF, that is intended to be public. I do not want my clients to be able to call the underlying UDFs directly, as they accept variable parameters, so there’s a security concern.

For instance, if I may have a method that allows me to log out an account, whom ref is passed as a parameter. If I grant access to this private UDF, my clients will be able to log each other out, which is definitely not what I want. I wish I could grant access to only the top-level UDF so that all the underlying UDFs could get called with no problem, being treated system-level and private.

And if I want a user to be able to like a post, I definitely don’t want him to be able to update posts collection directly and writing a million likes update there.

This won’t be a breaking change, as everything is currently exposed, and nothing will change to the currently configured databases.

Hi @Orimay. Can you elaborate a little more. I don’t quite understand to gap here.

You can grant access to top-level UDF’s by giving keys/tokens the privileges to call them.

UDF’s are always executed with the token’s/key’s credentials unless they are specified a Role. If you want the UDF to fall back on the permissions granted to the public/user Key or Token, then don’t specify a Role in the UDF definition.

If I understand correctly, this is already possible. Can you be more specific about what you want to do that is not possible?

The ABAC role predicates for the call action accept the arguments for the UDF as well. It is possible, for example, to restrict a user from calling a UDF only if a certain parameter is that user, or so that the function will only update Documents that you know are “owned” by that user.

The details for the predicate signature is here in the docs: How to use database security roles | Fauna Documentation

Here is an example Role

{
  name: "RoleToCallWithUser",
  privileges: [
    {
      resource: Function("logout"),
      actions: {
        call: Query(
          Lambda("userRef", Equals(Var("userRef"), CurrentIdentity()))
        )
      }
    }
  ],
  membership: [
    {
      resource: Collection("User")
    }
  ]
}

Thank you for your response!

Calling a UDF is not really an issue here. The issue is — FaunaDB enforces to also expose to the end user everything UDF touches. Every underlying UDF, that was easier to just not expose, rather than fine-tune, as well as every document.

Even if I can restrict user access to specific documents, I can’t control the data they put there.

The way I’d love to have it for great DX:

  • I create a UDF, that does all nessesary calculations and updates to specific documents
  • I never expose these documents and the UDFs my UDF is composed of — all this data is considered private, unless I explicitly mark it as available to the end user
  • User can not access my sub-UDFs and documents without any additional checks — not marking them available explicitly should be just enough

I don’t understand. You can give the user the privilege only to call the UDF and then give the UDF the role/permissions it needs to do something without giving the user additional privileges.

Consider having UDF A, that is exposed to end user, UDF B, that is called by UDF A, and collection C, that is read and modified by UDF B:

A -> B -> C

I don’t want to expose B nor C to the user at all. No exceptions. User should only have access to A, and all the checks/logic/data behind this UDF must be blackboxed away.

This is what I exactly mean by encapsulation.

If you give UDF A a custom role, that Role must explicitly provide the privilege to call UDF B. If you give UDF B a custom role, you must explicitly give UDF B the privilege to access resource C. That way, the user does not have to be concerned with or have access to resource C.

Wait, UDFs may have priveledges themselves? I think I missed that. Could you, please, provide a sample?

If you set a UDF’s role property (see the CreateRole function details in the docs), then it is executed with that Role.

Sorry if that was the mix up the whole time. Any time I said something like “grant a UDF the privilege to do X” previously, that is what I meant – to set the UDF’s role property. This is my fault for forgetting to start at beginning :grimacing:

1 Like

No worries! Awesome, thank you, this is exactly what I wanted! A bit trickier than I’d love it to be, but definitely works!

I still hope, that, at some point, UDFs will be private by default and auto-granted required access to all the underlying resources.

Edit: All I need to do – is set Admin role per UDF and grant access to only those UDFs that users need. This way, all UDFs get auto-granted required access to all the underlying resources.

And it suddenly becomes clear what the role dropdown does. I was somehow thinking that this is the default role required to call the function

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.