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

Unexpected behavior when using get_query #69

Closed
cadeParade opened this issue Mar 19, 2024 · 2 comments
Closed

Unexpected behavior when using get_query #69

cadeParade opened this issue Mar 19, 2024 · 2 comments
Assignees

Comments

@cadeParade
Copy link

Hello,
I am having trouble implementing the get_query method for sql_alchemy in our app. Here's what I've got going on. I am fairly new to Cerbos so it may (likely??) be that something is wrong on my end, but I'm a bit stumped so I'm asking for help.

Simplified policies are as follows:

Policies
# org policy
---

apiVersion: api.cerbos.dev/v1
resourcePolicy:
  resource: org
  version: default
  importDerivedRoles:
  - common_roles
  rules:
      effect: EFFECT_ALLOW
    - actions: ['org.read']
      derived_roles: [
        'OrgViewer',
      ]

# derived role
    - name: OrgViewer
      parentRoles: ['user']
      condition:
        match:
          any:
            of:
              - expr: P.attr.orgs[R.id].role == "owner"
              - expr: P.attr.orgs[R.attr.org_id].role == "owner"
              - expr: P.attr.orgs[R.id].role == "viewer"
              - expr: P.attr.orgs[R.attr.org_id].role == "viewer"

When I run is_allowed with the following principal and resource, things work as expected and shows that Cerbos is running and knows about the policies.

# principal
{
  "id": "user_764c63",
  "roles": ["user"],
  "attr": {"orgs": {"org_dd60a6": {"role": "owner"}}}
}

# resource
{
  "kind": "org",
  "id": "org_dd60a6",
  "attr": {
    "org_id": "org_dd60a6"
  }
}

c.is_allowed('org.read', principal, resource) # ---> True

When I try to run get_query with the above principal and the following code, it errors on the get_query line.

plan_resource = PlanResourcesInput.Resource(kind="org")
plan = c.plan_resources("org.read", p, plan_resource)
query = get_query(plan, models.Org, {"request.resource.id": models.Org._id})

The plan looks like this:

Printout of query plan
request_id: "84523808-6920-4e54-bbc7-0ee54d99de6b"
action: "org.read"
resource_kind: "org"
filter {
  kind: KIND_CONDITIONAL
  condition {
    expression {
      operator: "or"
      operands {
        expression {
          operator: "eq"
          operands {
            expression {
              operator: "get-field"
              operands {
                expression {
                  operator: "index"
                  operands {
                    expression {
                      operator: "struct"
                      operands {
                        expression {
                          operator: "set-field"
                          operands {
                            value {
                              string_value: "org_018e5806b4211f0fd2196c1644dd60a6"
                            }
                          }
                          operands {
                            expression {
                              operator: "struct"
                              operands {
                                expression {
                                  operator: "set-field"
                                  operands {
                                    value {
                                      string_value: "role"
                                    }
                                  }
                                  operands {
                                    value {
                                      string_value: "owner"
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                  operands {
                    variable: "request.resource.id"
                  }
                }
              }
              operands {
                variable: "role"
              }
            }
          }
          operands {
            value {
              string_value: "owner"
            }
          }
        }
      }
      operands {
        expression {
          operator: "eq"
          operands {
            expression {
              operator: "get-field"
              operands {
                expression {
                  operator: "index"
                  operands {
                    expression {
                      operator: "struct"
                      operands {
                        expression {
                          operator: "set-field"
                          operands {
                            value {
                              string_value: "org_018e5806b4211f0fd2196c1644dd60a6"
                            }
                          }
                          operands {
                            expression {
                              operator: "struct"
                              operands {
                                expression {
                                  operator: "set-field"
                                  operands {
                                    value {
                                      string_value: "role"
                                    }
                                  }
                                  operands {
                                    value {
                                      string_value: "owner"
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                  operands {
                    variable: "request.resource.attr.org_id"
                  }
                }
              }
              operands {
                variable: "role"
              }
            }
          }
          operands {
            value {
              string_value: "owner"
            }
          }
        }
      }
      operands {
        expression {
          operator: "eq"
          operands {
            expression {
              operator: "get-field"
              operands {
                expression {
                  operator: "index"
                  operands {
                    expression {
                      operator: "struct"
                      operands {
                        expression {
                          operator: "set-field"
                          operands {
                            value {
                              string_value: "org_018e5806b4211f0fd2196c1644dd60a6"
                            }
                          }
                          operands {
                            expression {
                              operator: "struct"
                              operands {
                                expression {
                                  operator: "set-field"
                                  operands {
                                    value {
                                      string_value: "role"
                                    }
                                  }
                                  operands {
                                    value {
                                      string_value: "owner"
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                  operands {
                    variable: "request.resource.id"
                  }
                }
              }
              operands {
                variable: "role"
              }
            }
          }
          operands {
            value {
              string_value: "viewer"
            }
          }
        }
      }
      operands {
        expression {
          operator: "eq"
          operands {
            expression {
              operator: "get-field"
              operands {
                expression {
                  operator: "index"
                  operands {
                    expression {
                      operator: "struct"
                      operands {
                        expression {
                          operator: "set-field"
                          operands {
                            value {
                              string_value: "org_018e5806b4211f0fd2196c1644dd60a6"
                            }
                          }
                          operands {
                            expression {
                              operator: "struct"
                              operands {
                                expression {
                                  operator: "set-field"
                                  operands {
                                    value {
                                      string_value: "role"
                                    }
                                  }
                                  operands {
                                    value {
                                      string_value: "owner"
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                  operands {
                    variable: "request.resource.attr.org_id"
                  }
                }
              }
              operands {
                variable: "role"
              }
            }
          }
          operands {
            value {
              string_value: "viewer"
            }
          }
        }
      }
    }
  }
}
cerbos_call_id: "01HSC29G47ZD606S6K6MHCVBG6"

The error is

File "/Users/foo/projects/my_project/api/.venv/lib/python3.11/site-packages/cerbos_sqlalchemy/query.py", line 127, in traverse_and_map_operands
    variable = d["variable"]
               ~^^^^^^^^^^^^
KeyError: 'variable'

When I put a print in the file where the error originates, I get this for the value of d:

{'expression': {'operator': 'get-field', 'operands': [{'expression': {'operator': 'index', 'operands': [{'expression': {'operator': 'struct', 'operands': [{'expression': {'operator': 'set-field', 'operands': [{'value': 'org_018e5806b4211f0fd2196c1644dd60a6'}, {'expression': {'operator': 'struct', 'operands': [{'expression': {'operator': 'set-field', 'operands': [{'value': 'role'}, {'value': 'owner'}]}}]}}]}}]}}, {'variable': 'request.resource.id'}]}}, {'variable': 'role'}]}, 'value': 'owner'}

There is no top level variable key in this data structure, which is why it throws an error. I don't really understand why the data structure d is wrong at this point though. Could someone help me out? Thanks!

@dbuduev dbuduev self-assigned this Mar 19, 2024
@dbuduev
Copy link

dbuduev commented Mar 19, 2024

Depends on cerbos/cerbos#2058

@Sambigeara
Copy link
Collaborator

This was "fixed" in Dennis' PR above. However, it did highlight a failure case in the adapter when unsupported operators make their way through to the resolution logic. I've created another issue to track this and will close this as complete!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants