Modeling Attribute Patterns
In this section you will:
- Model the authorization for an example credit card app
- Use attributes to control permissions on resources within the app
Application Details
In this tutorial you'll model a credit card app with a rewards program. The application has the following resources described in detail below.
-
Card Account: The card account is the top level resource in this example. A card account can have one or more owners. Only owners have card account permissions. Card accounts also have members. Card account members are users associated with the card account. In the implementation, you'll use this role as another way to establish a user's relationships to a particular card account. However, card account members do not have any permissions at this level.
Role Permissions Owner •Add new credit cards
•View card accounts
•Modify card account options and settingsMember None Relationship Resource Parent of Credit Cards Attribute Description Is Active Features and permissions of card accounts are accessible if and only if the account is active. Rewards Status For accounts enrolled in the rewards program, the status reveals what tier the account member has achieved. -
Credit Card: The credit card is second level resource. A credit card belongs to a single card account. Each credit has one card holder. Card holders can perform all actions associated with their credit card except modifying the credit card limits. Card account owners can modify credit card limits and have all card holder permissions for the credit cards under their accounts.
Role Permissions Card Holder •View the details of the credit card account
•Make credit card transactions
•Dispute any credit card transactionsAccount Owner •View the details of the credit card account
•Make credit card transactions
•Dispute any credit card transactions
•Modify the spending limits of the credit cardRelationship Resource Child of Card Accounts Attribute Description Is Active Certain features and permissions of credit cards are accessible if and only if the account is active. -
Rewards Program: The rewards program is available to members of card accounts. Once card account member becomes a member oef the rewards program they automatically given access to the rewards tier. Subsequent reward tiers are achieved based on the reward program rules and conditions.
Role Permissions Member •View the rewards program
•Rewards
•Bronze (if Bronze status)
•Silver (if Silver status)
•Gold (if Gold status)
•Platinum (if Platinum status)Relationship Resource None Attribute Description None
Creating the Policy
Create the scaffolding for the authorization model in Polar. You can start by defining an actor
User and the three
resources detailed above: CardAccount, CreditCard, and RewardsProgram. For now, only worry about defining roles,
permissions, and relationships — don't add any rules just yet!
actor User {}resource CardAccount { roles = [ "owner", "member" ]; permissions = [ "add_card", "view", "modify_accounts" ];}resource CreditCard { roles = [ "card_holder" ]; permissions = [ "view", "make_transactions", "dispute_transactions", "modify_limits" ]; relations = {parent_account: CardAccount};}resource RewardsProgram { roles = [ "member" ]; permissions = [ "rewards", "view", "bronze_rewards", "silver_rewards", "gold_rewards", "platinum_rewards" ];}
When writing policies in Polar, only simple rules can be defined within resource blocks. Since the goal is to add attributes to enhance the authorization logic, you will need to write the policy rules using the longhand rule syntax. In each case you'll start with the basic roles-based access control pattern and extend it using attribute conditions.
has_permission(user: User, <PERMISSION>, resource: <SOME_RESOURCE>) if has_role(user, <SOME_ROLE>, resource) and ...;
*NOTE: Refer to the attribute description section for each resource to understand how they should be applied in rule definitions.
Writing CardAccount Resource Rules
Create has_permission
rules for each of the three permissions listed for the CardAccount resource. Next, use the
toggle attribute
pattern to define is_active
which takes a CardAccount as its argument. This will ensure that account
permissions are only granted to active accounts.
################################################################################ CardAccount Rules################################################################################ Each permission is only granted if the user has the appropriate role, and the# account is active.has_permission(user: User, "add_card", account: CardAccount) if has_role(user, "owner", account) and is_active(account);has_permission(user: User, "view", account: CardAccount) if has_role(user, "owner", account) and is_active(account);has_permission(user: User, "modify_accounts", account: CardAccount) if has_role(user, "owner", account) and is_active(account);
Writing CreditCard Resource Rules
Use the same toggle pattern and apply it to the rules for CreditCard resources. This resource has a slightly more complex set of rules. You will be adding up to two toggle patterns:
is_active(CardAccount)
is_active(CreditCard)
Remember to also add the has_relation
check which models a credit card's relation to a particular account. A couple of
examples are given below.
################################################################################ CreditCard Rules################################################################################ Only add the attribute condition is_active(account). Users should still# be able to view their account if their card is inactive.has_permission(user: User, "view", card: CreditCard) if (has_role(user, "card_holder", card) or has_role(user, "owner", account)) and account matches CardAccount and has_relation(card, "parent_account", account) and is_active(account);...# Add both attribute conditions: is_active(account) and# is_active(card). Users should not be able to modify credit card# limits if their account OR their card is inactive.has_permission(user: User, "modify_limits", card: CreditCard) if has_role(user, "owner", account) and account matches CardAccount and has_relation(card, "parent_account", account) and is_active(account) and is_active(card);
Action Items
Writing RewardsProgram Resource Rules
The last resource to model is the RewardsProgram. It uses the existing is_active(CardAccount)
fact along
with a multiple attribute state pattern
to model a member's reward status:
has_rewards_status(CardAccount, String);
NOTE: Use the string argument to make the attribute rule unique to the permission that it accompanies.
This section of the policy shows permissions for the basic rewards tier (available to all rewards members) and the platinum tier.
################################################################################ RewardsProgram Rules################################################################################ The rewards tier is the default tier in the rewards program. It only requires# a user to be a member of an active CardAccount and enrolled as a member of# the RewardsProgram. Therefore, no additional rewards_status rule is needed.has_permission(user: User, "rewards", rewards_program: RewardsProgram) if has_role(user, "member", rewards_program) and account matches CardAccount and has_role(user, "member", account) and is_active(account); ...has_permission(user: User, "platinum_rewards", rewards_program: RewardsProgram) if has_role(user, "member", rewards_program) and account matches CardAccount and has_role(user, "member", account) and is_active(account) and has_rewards_status(account, "platinum");
Action Items
Complete Policy Example
actor User {}resource CardAccount { roles = [ "owner", "member" ]; permissions = [ "add_card", "view", "modify_accounts" ];}resource CreditCard { roles = [ "card_holder" ]; permissions = [ "view", "make_transactions", "dispute_transactions", "modify_limits" ]; relations = {parent_account: CardAccount};}resource RewardsProgram { roles = [ "member" ]; permissions = [ "view", "rewards", "bronze_rewards", "silver_rewards", "gold_rewards", "platinum_rewards" ];}################################################################################ CardAccount Rules################################################################################ Each permission is only granted if the user has the appropriate role, and the# account is active.has_permission(user: User, "add_card", account: CardAccount) if has_role(user, "owner", account) and is_active(account);has_permission(user: User, "view", account: CardAccount) if has_role(user, "owner", account) and is_active(account);has_permission(user: User, "modify_accounts", account: CardAccount) if has_role(user, "owner", account) and is_active(account);################################################################################ CreditCard Rules################################################################################ Only add the attribute condition is_active(account). Users should still# be able to view their account if their card is inactive.has_permission(user: User, "view", card: CreditCard) if (has_role(user, "card_holder", card) or has_role(user, "owner", account)) and account matches CardAccount and has_relation(card, "parent_account", account) and is_active(account);# Only add the attribute condition is_active(account). Users should still# be able to dispute transactions on their account if their card is inactive.has_permission(user: User, "dispute_transactions", card: CreditCard) if (has_role(user, "card_holder", card) or has_role(user, "owner", account)) and account matches CardAccount and has_relation(card, "parent_account", account) and is_active(account);# Add both attribute conditions: is_active(account) and# is_active(card). User's should not be able to make transactions if# their account OR their card is inactive.has_permission(user: User, "make_transactions", card: CreditCard) if (has_role(user, "card_holder", card) or has_role(user, "owner", account)) and account matches CardAccount and has_relation(card, "parent_account", account) and is_active(account) and is_active(card);# Add both attribute conditions: is_active(account) and# is_active(card). User's should not be able to modify credit card# limits if their account OR their card is inactive.has_permission(user: User, "modify_limits", card: CreditCard) if has_role(user, "owner", account) and account matches CardAccount and has_relation(card, "parent_account", account) and is_active(account) and is_active(card);################################################################################ RewardsProgram Rules################################################################################ The rewards tier is the default tier in the rewards program. It only requires# a user to be a member of an active CardAccount and enrolled as a member of# the RewardsProgram. Therefore, no additional rewards_status rule is needed.has_permission(user: User, "rewards", rewards_program: RewardsProgram) if has_role(user, "member", rewards_program) and account matches CardAccount and has_role(user, "member", account) and is_active(account);# Users can only view rewards if they meet the same criteria above for rewards.has_permission(user: User, "view", rewards_program: RewardsProgram) if has_role(user, "member", rewards_program) and account matches CardAccount and has_role(user, "member", account) and is_active(account);has_permission(user: User, "bronze_rewards", rewards_program: RewardsProgram) if has_role(user, "member", rewards_program) and account matches CardAccount and has_role(user, "member", account) and is_active(account) and has_rewards_status(account, "bronze");has_permission(user: User, "silver_rewards", rewards_program: RewardsProgram) if has_role(user, "member", rewards_program) and account matches CardAccount and has_role(user, "member", account) and is_active(account) and has_rewards_status(account, "silver");has_permission(user: User, "gold_rewards", rewards_program: RewardsProgram) if has_role(user, "member", rewards_program) and account matches CardAccount and has_role(user, "member", account) and is_active(account) and has_rewards_status(account, "gold");has_permission(user: User, "platinum_rewards", rewards_program: RewardsProgram) if has_role(user, "member", rewards_program) and account matches CardAccount and has_role(user, "member", account) and is_active(account) and has_rewards_status(account, "platinum");
Action Items
Additional Resources
Talk to an Oso Engineer
If you'd like to learn more about using Oso Cloud in your app or have any questions about this guide, connect with us on Slack. We're happy to help.