User Guide¶
The objective of security is protection of information from theft or corruption, while allowing the information to remain accessible to its intended users.
Ticket¶
Ticket is a short packet of bytes generated by a network server for a client, which can be delivered to itself as a means of authentication or proof of authorization, and cannot easily be forged.
Ticket
has the following
characteristics:
- It is valid for certain period of time, in particular it has an explicitly set expiration time.
- Its value is signed to prove its authenticity.
- It is encrypted to protect sensitive information.
- It has noise to harden forgery.
Ticket
can be instantiated
by passing the following arguments:
max_age
- period of time (in seconds) this Ticket is considered valid.salt
- a random sequence that hardens against ticket forgery. It is prepended to the validation key and the encryption key.digestmod
- hash algorithm used with HMAC (Hash-based Message Authentication Code) to sign ticket. Defaults to SHA1.cypher
- cryptography algorithm. Defaults to AES128.options
- a dictionary that holds the following configuration values:CRYPTO_VALIDATION_KEY
(used by signature) andCRYPTO_ENCRYPTION_KEY
(used by encryption).
Validation and Encryption Keys¶
Keys used for validation and encryption are ensured to be at least of 320 bits length.
The ensure_strong_key()
function
appends HMAC signature to the key.
If the cryptography library is not available you will see a warning message:
Ticket: cypher not available
Although Ticket continues to function even cryptography library is not installed it strongly recommended to use cryptography in a production environment.
Thread Safety¶
Ticket does not alter it state once initialized. It is guaranteed to be thread safe.
Typical Use Case¶
Here is typical use case when all possible configuration attributes are used:
from wheezy.security.crypto.comp import aes192
from wheezy.security.crypto.comp import sha1
from wheezy.security.crypto import Ticket
options = {
'CRYPTO_VALIDATION_KEY': 'LkLlYR5WbTk54kaIgJOp',
'CRYPTO_ENCRYPTION_KEY': 'rH64daeXBZdgrR7WNawf'
}
ticket = Ticket(
max_age=1200,
salt='CzQnV0KazDKElBYiIC2w',
digestmod=sha1,
cypher=aes192,
options=options)
The ticket
instance can be shared application wide. The encode
/
decode
methods are used in the following way:
protected_value = ticket.encode('hello')
assert 'hello' == ticket.decode(protected_value)
In case the validity of a ticket cannot be confirmed, the decode
method returns
None
.
Extensibility¶
Ticket cypher
can be any callable that satisfies the following contract:
- Initialization is called with encryption key. Returned object must be a factory for the actual algorithm instance.
- Algorithm factory must return new algorithm via simple callable with no arguments.
- Algorithm implementation must support two methods:
encrypt(value)
anddecrypt(value)
.
Principal¶
Principal
is a container of user
specific security information. It includes the following attributes:
id
- user identity, e.g. number 755345, UUID f102a87b-ee36-4a2e-97de-8f803f470867 or whatever else is valid to look up a user quickly in your application.roles
- a list of authorized user roles, e.g. user, manager, etc.alias
- a user friendly name, display name, etc. This can be something like John Smith, etc.extra
- any string you would like to hold in security context.
Here is a sample how to instantiate new Principal:
principal = Principal(
id='125134788',
roles=['user'],
alias='John Smith')
Principal
supports the following
methods:
dump
- converts instance to a string.load
- reverse operation todump
.
You can use Ticket
to securely pass Principal
across network boundaries.
Combining them both you can introduce an authentication/authorization cookie
to your application.
Authorization¶
Authorization specifies access rights to resources and provides access control in particular to your application.
You are able to request authorization by decorating your method with
authorized()
. Here is a typical use
case:
from wheezy.security import authorized
class MyBusinessLogic(object):
principal = None
@authorized
def cancel_transfer(self, id):
return True
@authorized(roles=('operator',))
def approve_transfer(self):
return True
Note that the authorized()
decorator
requires the object to supply a principal
attribute of type
Principal
.
If a caller is not authorized to perform a requested operation,
a SecurityError
exception is raised.
See authorized()
for more details.