Skip to content

Latest commit

 

History

History
335 lines (288 loc) · 9.28 KB

migrating-relations.mdx

File metadata and controls

335 lines (288 loc) · 9.28 KB
sidebar_position slug description
1
/modeling/migrating/migrating-relations
Migrating relations

import { AuthzModelSnippetViewer, CardBox, CheckRequestViewer, DocumentationNotice, ProductConcept, ProductName, ProductNameFormat, ReadRequestViewer, RelatedSection, RelationshipTuplesViewer, WriteRequestViewer, } from '@components/Docs';

Migrating Relations

In the lifecycle of software development, you will need to make updates or changes to the . In this guide, you will learn best practices for changing your existing authorization model. With these recommendations, you will minimize downtime and ensure your relationship models stay up to date.

Before You Start

This guide assumes you are familiar with the following OpenFGA concepts:

  • A : a class of objects that have similar characteristics
  • A : an entity in the system that can be related to an object
  • A : is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • An : represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
  • A : a grouping consisting of a user, a relation and an object stored in
  • Intersection Operator: the intersection operator can be used to indicate a relationship exists if the user is in all the sets of users

Step By Step

The document below is an example of a relational authorization model. In this model, you can assign users to the editor relation. The editor relation has write privileges that regular users do not.

In this scenario, you will migrate the following model:

<AuthzModelSnippetViewer configuration={{ schema_version: '1.1', type_definitions: [ { type: 'document', relations: { editor: { this: {}, }, can_edit: { computedUserset: { object: '', relation: 'editor', }, }, }, metadata: { relations: { editor: { directly_related_user_types: [{ type: 'user' }] }, }, }, }, { type: 'user', }, ], }} />

There are existing associated with editor relation.

<RelationshipTuplesViewer relationshipTuples={[ { user: 'user:anne', relation: 'editor', object: 'document:roadmap', }, { user: 'user:charles', relation: 'editor', object: 'document:roadmap', }, ]} />

This is the authorization model that you will want to migrate to:

<AuthzModelSnippetViewer configuration={{ schema_version: '1.1', type_definitions: [ { type: 'document', relations: { writer: { this: {}, }, can_write: { computedUserset: { object: '', relation: 'writer', }, }, }, metadata: { relations: { writer: { directly_related_user_types: [{ type: 'user' }] }, }, }, }, { type: 'user', }, ], }} />


01. Create A Backwards Compatible Model

To avoid service disruption, you will create a backwards compatible model. The backwards compatible model ensures the existing relationship tuple will still work.

In the example below, user:Anne still has write privileges to the document:roadmap resource.

<AuthzModelSnippetViewer configuration={{ schema_version: '1.1', type_definitions: [ { type: 'document', relations: { editor: { this: {}, }, writer: { union: { child: [ { this: {}, }, { computedUserset: { relation: 'editor', }, }, ], }, }, can_write: { computedUserset: { object: '', relation: 'writer', }, }, can_edit: { computedUserset: { object: '', relation: 'writer', }, }, }, metadata: { relations: { editor: { directly_related_user_types: [{ type: 'user' }] }, writer: { directly_related_user_types: [{ type: 'user' }] }, }, }, }, { type: 'user', }, ], }} />

Test the can_edit definition. It should produce a value of true.

<CheckRequestViewer user={'user:anne'} relation={'can_write'} object={'document:roadmap'} allowed={true} /> <CheckRequestViewer user={'user:anne'} relation={'can_edit'} object={'document:roadmap'} allowed={true} />

02. Create a New Relationship Tuple

Now that you have a backwards compatible model, you can create new relationship tuples with a new relation.

In this example, you will add Bethany to the writer relationship.

<WriteRequestViewer relationshipTuples={[ { _description: 'Bethany assigned writer instead of editor', user: 'user:bethany', relation: 'writer', object: 'document:roadmap', }, ]} />

Run a check in the API for Bethany to ensure correct access.

<CheckRequestViewer user={'user:bethany'} relation={'can_write'} object={'document:roadmap'} allowed={true} />

03. Migrate The Existing Relationship Tuples

Next, migrate the existing relationship tuples. The new relation makes this definition obsolete.

Use the read API to lookup all relationship tuples.

<ReadRequestViewer tuples={[ { user: 'user:anne', relation: 'editor', object: 'document:planning', }, { user: 'user:charles', relation: 'editor', object: 'document:planning', }, ]} />

Then filter out the tuples that do not match the object type or relation (in this case, document and editor respectively), and update the new tuples with the write relationship.

<WriteRequestViewer relationshipTuples={[ { user: 'user:anne', relation: 'writer', object: 'document:roadmap', }, { user: 'user:charles', relation: 'writer', object: 'document:roadmap', }, ]} />

Finally, remove the old relationship tuples.

<WriteRequestViewer deleteRelationshipTuples={[ { user: 'user:anne', relation: 'editor', object: 'document:roadmap', }, { user: 'user:charles', relation: 'editor', object: 'document:roadmap', }, ]} />

:::info Perform a write operation before a delete operation to ensure Anne still has access. :::

Confirm the tuples are correct by running a check on the user.

<CheckRequestViewer user={'user:anne'} relation={'can_write'} object={'document:roadmap'} allowed={true} />

The old relationship tuple no longer exists.

<CheckRequestViewer user={'user:anne'} relation={'editor'} object={'document:roadmap'} allowed={false} />

04. Remove Obsolete Relationship From The Model

After you remove the previous relationship tuples, update your authorization model to remove the obsolete relation.

<AuthzModelSnippetViewer configuration={{ schema_version: '1.1', type_definitions: [ { type: 'document', relations: { writer: { this: {}, }, can_write: { computedUserset: { object: '', relation: 'writer', }, }, }, metadata: { relations: { writer: { directly_related_user_types: [{ type: 'user' }] }, }, }, }, { type: 'user', }, ], }} />

Now, the write API will only accept the new relation name.

Related Sections

<RelatedSection description="Review the following sections for more information on managing relationship tuples." relatedLinks={[ { title: 'Transactional Writes', description: 'Learn how to perform transactional write', link: '../../interacting/transactional-writes', id: '../../interacting/transactional-writes.mdx', }, { title: 'Relationship Queries', description: 'Understand the differences between check, read, expand and list objects.', link: '../../interacting/relationship-queries', id: '../../interacting/relationship-queries.mdx', }, { title: 'Production Best Practices', description: 'Learn the best practices of running OpenFGA in a production environment', link: '../../getting-started/running-in-production', id: '../../getting-started/running-in-production', }, ]} />