Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """
- Keyring backend that uses the Fernet symmetric key cryptography from the
- `cryptography` library.
- This stores a private key for a user at `~/.trigger_key`.
- The idea is that this could be used for updating .tacacsrc internals to
- store/retrieve credentials using the Keyring API and therefore take advantage
- of any backend that Keyring supports.
- This backend could be the default Trigger keyring backend so that Trigger can
- operate in a self-contained way (only adding keyring and keyrings.alt libs as
- requirements).
- Requirements:
- - cryptography
- - keyring
- - keyrings.alt
- Run this before testing::
- pip install cryptography keyring keyrings.alt
- How to use it:
- >>> import fernet_keyring
- >>> import keyring
- >>> keyring.set_keyring(fernet_keyring.FernetKeyring())
- >>> keyring.set_password('example', 'admin', 'password')
- Reading key from existing keyfile /Users/jathan/.trigger_key
- >>> keyring.get_password('example', 'admin')
- u'password'
- """
- import getpass
- import os
- import sys
- from keyring.py27compat import configparser
- from keyring.util import properties
- from keyring.util.escape import escape as escape_for_ini
- from keyrings.alt import file_base
- __author__ = 'jathan@gmail.com'
- # Where the user's private key is stored.
- KEYFILE = os.path.expanduser('~/.trigger_key')
- class FernetKeyring(file_base.Keyring):
- """
- A Fernet keyring.
- """
- keyfile = KEYFILE
- filename = 'fernet_pass.cfg'
- pw_prefix = 'pw:'.encode()
- @properties.ClassProperty
- @classmethod
- def priority(self):
- try:
- __import__('cryptography.fernet')
- except ImportError:
- raise RuntimeError('cryptography required')
- return .25
- @properties.NonDataProperty
- def keyring_key(self):
- if self._check_file():
- self._unlock()
- else:
- self._init_file()
- return self.keyring_key
- def _create_cipher(self, key):
- from cryptography.fernet import Fernet
- return Fernet(key)
- def _get_new_password(self):
- if not os.path.exists(self.keyfile):
- print 'Creating new keyfile', self.keyfile
- from cryptography.fernet import Fernet
- password = Fernet.generate_key()
- with open(self.keyfile, 'w') as f:
- f.write(password)
- os.chmod(self.keyfile, 0600)
- else:
- print 'Reading key from existing keyfile', self.keyfile
- with open(self.keyfile, 'r') as f:
- password = f.read()
- return password
- def _init_file(self):
- """Initialize a new password file and set the reference password."""
- self.keyring_key = self._get_new_password()
- # Set a reference password, used to check that the password provided
- # matches for subsequent checks.
- self.set_password(
- 'keyring-setting', 'password reference', 'password reference value'
- )
- def _check_file(self):
- """
- Check if the file exists and has the expected password reference.
- """
- if not os.path.exists(self.file_path):
- return False
- self._migrate()
- config = configparser.RawConfigParser()
- config.read(self.file_path)
- try:
- config.get(
- escape_for_ini('keyring-setting'),
- escape_for_ini('password reference'),
- )
- except (configparser.NoSectionError, configparser.NoOptionError):
- return False
- return True
- def _unlock(self):
- """
- Unlock this keyring by getting the password for the keyring from the
- user.
- """
- print 'Reading key from existing keyfile', self.keyfile
- with open(self.keyfile, 'r') as f:
- password = f.read()
- self.keyring_key = password
- try:
- ref_pw = self.get_password('keyring-setting', 'password reference')
- assert ref_pw == 'password reference value'
- except AssertionError:
- self._lock()
- raise ValueError('Incorrect password')
- def _lock(self):
- """
- Remove the keyring key from this instance.
- """
- del self.keyring_key
- def encrypt(self, password):
- cipher = self._create_cipher(self.keyring_key)
- password_encrypted = cipher.encrypt(bytes(self.pw_prefix + password))
- return password_encrypted
- def decrypt(self, password_encrypted):
- cipher = self._create_cipher(self.keyring_key)
- password = cipher.decrypt(password_encrypted)
- assert password.startswith(self.pw_prefix)
- return password[3:]
- def _migrate(self, keyring_password=None):
- """
- Convert older keyrings to the current format.
- """
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement