Skip to main content

Contracts, Policies

Pidentity is an authorization and access control library built to provide simple yet robust ABAC paradigms. (NOTE: Pidentity is not a strict ABAC system) - it is simpler but without sacrificing the power of ABAC.

Components

pidentity works on a © Micro C5 Paradigm which translates to Control Content from Contact via Contracts Contextually. Sounds intimidating but it is really simple once broken down.

Every information system has:

  • Content: this is the data you might want to protect i.e. data stored in the system or system(s)

  • Contacts: Entities that want to come in contact with the data (owner of the data, someone granted access by owner, hacker, application) etc.

  • Context: Information within the information system or that the information system has access to but exists outside of the Content or protected data i.e. dates or times when no one is allowed to update content, ip address of a contact etc.

  • Contracts: What is a legal or illegal operation when Content, Contact, Context is combined together

  • Controls: The system, processes, tools etc. that deny or allows operations to and on content

So how does this all relate to C5 - From the definition it means: You (your application, company) wants to control (allow, deny access to or limit actions on) content (data, information) from contact (application, hacker, human) via contracts (combinatory rules) contextually (which might include the use of data not stored within the content being controlled).

Contracts

The first thing to understand is Contracts. Contracts are how you specify the relationships betweem Contacts and Content. How do we create Contracts? Let's look at some code

Code Snippet: 1a
from pidentity import Contract

contract = Contract()

Simple enough, but then, how do you tell a contract what actions are possible, and how to identify Content to be Controlled?

Code Snippet: 1b
...  # code from above

contract.on('delete').to('/customers/:id')

To specify actions use the .on(*actions) method of the contracts object. Actions can be called whatever you want i.e. .on('foo') - for web applications HTTP verbs can be an intuitive option or popular candidate.

It is also important to note that all contract object method calls are order agnostic, this means you called have also called the .to('/customers/:id') method before the .on('deletes') method and still get the same output.

This means the code snippet in snippet 1b above is equivalent to code in snippet 1c below.

Code Snippet: 1c
contract.to('/customers/:id').on('delete') 

Contract Rules & Conditions

Great, now we know how to build a contract and tell it what actions and Content .to('a-unique-id-for-content') it identifies. But a contract is useless if we have no way of specifying the actual content, contact, and context data for which the contract is valid.

Controlling Access Based On Content

If you want to control access to content based on the data in the content itself - you tell your contract this by using the .content(conditions: dict) method of the contract object. It is important to note that by default pidentity denies all access unless a contract is found.

from pidentity import Contract


# pidentity by default denies all access where there is no contract
# so to delete unlocked orders - this contract is needed
c = Contract()
c.on('delete').to('orders').content({
    'unlocked': True
})


# this will allow any content at the address `/orders/:id` with category
# `Perishables` to be deleted
d = Contract()
d.on('delete').to('/orders/:id').contact({
    'category': 'Perishables'
})

We are going to cover Contact, and Context blocks in later sections, but before we do it is important to explain how their configurations dictionary works. Dictionaries, hashmaps, associative arrays (different names for the same thing) have a common format - a key maps to a value. pidentity conditions i.e. .contact(**conditions), .content(**conditions), .context(**conditions) are dictionaries that are passed into the content, contact, and context pidentity.Contract methods.

By default condition keys i.e. dict keys are used for specifying what fields in the block(s) - (content, contact, context) to target, and the values provide indication of what the value of those fields should be i.e. constant values expected to be seen for given contract conditions.

For all condition dicts across all blocks i.e. content, context, contact - the default combination logic is AND i.e.

{"key": 0, "key2": 1}

means where key = 0 AND key2 = 1

and is the same as

{"&key": 0, "&key2": 1}

this is because & as the default symbol for condition keys, in addition, AND is the default operation for condition dictionaries when no symbol is explicitly provided.

To use OR logic instead of AND, use the OR symbol ? as the first character of your conditions dict i.e.

from pidentity import Contract
from pidentity.conditions import GT  # other options -> GTE, LT, BETWEEN, IN, NIN etc


# this contract will allow
#   any contact
# to retrieve
#   any content
# where
#   name = 'Jon' OR age > 18
Contract().on('gets').to('/customers').content({
    '?name': 'Jon',
    '?age': GT(18)
})


# OR, AND and others are non greedy and top to bottom
# that means &age, &name, ?role, &department
c = Contract()

# this contract means give everyone access when orders content is public AND unlocked
c.on('gets').to('/orders').content({
    'public': True,
    'unlocked': True
})

# this is the same as above but using explicit symbol notation
c.on('gets').to('/orders').content({
    '&public': True,
    '&unlocked': True
})


# this contract means give everyone access when orders content is public OR unlocked
c.on('gets').to('/orders').content({
    '?public': True,
    '?unlocked': True
})

To specify OR combinations the keys must use the explicit symbol notation with the symbol for OR which is a ?.

c = Contract()

# this contract means allow Contact to the content
# at address `/products/:id` when it is public OR unlocked
c.on('updates').to('/products/:id').content({
    '?public': True,
    '?unlocked': True
})
from pidentity import Controls

... # code from previous block here

controls = Controls()
controls.add(c, d)

These contracts are loaded in memory and for test use cases that is fine, but to make the most of pidentity you might want to connect a storage engine like a database for contracts to be saved and retrieved easily.

Currently only redis, postgres, sql server, oracle db, and mysql is supported as a storage engine.

from pidentity import Contract, Controls

controls = Controls(engine='postgres', dsn=...)
contract = Contract()

contract.on('patches').to('/customers/:id').context({
    'cidr': '10.0.0.0/24'
})
# contracts above are added in-memory but not saved, to persist contracts?
await controls.save()

# for synchronous use cases use save sync
controls.saves()

# now we can provide some context, content, and contact rules/conditions we
# want to combine with the possible actions specified above

c.context({})  # let's use an empty dict for now - this will allow everyone but it's good enough for now
c.content({})  # empty dict for now
c.contact({})  # empty dict for now


# finally let's add this contract to our controls for saving so it can be used later
# await protocol.add_contract(c) also possible
protocol.add_contract_sync(c)
# this will allow any contact with first_name of Tersoo to delete an order
d = Contract()
d.on('delete').to('orders/:id').contact({
    'first_name': 'Tersoo'
})

Contact

This is recorded personal identifying information that can be used to identify a persona (app, human etc).

Crash Course

pidentity is all about identifying contacts, protecting content, they can have access to, as well as the context for that access to be valid. There are a few things to note about pidentity namely:

  • Context:

Metadata

Release files for pidentity 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pidentity 0.1.3
File Size Uploaded Provenance
pidentity-0.1.3.tar.gz 14.2 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pidentity 0.1.3
File Interpreter ABI Platform
pidentity-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 28.1 kB

Release files / pidentity-0.1.3.tar.gz

Download URL pidentity-0.1.3.tar.gz
Size 14.2 kB
Tags Source
SHA-256 checksum
How to use checksums
9f1d6870ec4602826faf900ee7972c21b239a705eaa9c3158b0f5e7fd0bb4fa2
BLAKE2b-256 checksum
How to use checksums
52d7189ece5d900d0b6769244a6370204bf0a66d34c65b079e79a2668892630f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.4.2 CPython/3.11.3 Darwin/24.2.0

Release files / pidentity-0.1.3-py3-none-any.whl

Download URL pidentity-0.1.3-py3-none-any.whl
Size 13.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5834536e49c4f54a479b1dc062a318a277274a07804bd3df68c773e110257ed5
BLAKE2b-256 checksum
How to use checksums
a43955f7eafd370dbb345459b068b7340ba52eb2e27cc799a04d1d6fb2f9d290
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.4.2 CPython/3.11.3 Darwin/24.2.0

Security for pidentity 0.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page