From 0043ce9937485ce975271365b2094f783db2e9bf Mon Sep 17 00:00:00 2001 From: František Zatloukal Date: Nov 28 2018 09:27:38 +0000 Subject: [PATCH 1/3] Merge branch 'master' into feature/python3 --- diff --git a/vault/serializers/api_v1.py b/vault/serializers/api_v1.py index a01dbaf..554f646 100644 --- a/vault/serializers/api_v1.py +++ b/vault/serializers/api_v1.py @@ -31,8 +31,6 @@ class Serializer(BaseSerializer): active=o.active, value=o.value, ) - rv = {} - rv[o.name] = o.value return {key: self.serialize(value) for key, value in rv.iteritems()} @@ -43,7 +41,7 @@ class Serializer(BaseSerializer): active=o.active, description=o.description, # roles=o.roles, - secrets=[s for s in o.secrets if s.active], + secrets=dict([(s.name, s.value) for s in o.secrets if s.active]), ) return {key: self.serialize(value) for key, value in rv.iteritems()} From 6abd7551ce396a6b7096d4593f447374c84df9a9 Mon Sep 17 00:00:00 2001 From: František Zatloukal Date: Nov 28 2018 12:02:58 +0000 Subject: [PATCH 2/3] Fix Python 3 issues in the code Use Python 3 on Fedora --- diff --git a/init_db.sh b/init_db.sh old mode 100644 new mode 100755 index 516be00..be8e645 --- a/init_db.sh +++ b/init_db.sh @@ -2,7 +2,7 @@ # this is a simple script to aid in the setup of a new db for F18 # init db -python run_cli.py -d init_db +python3 run_cli.py -d init_db # insert mock data -python run_cli.py -d mock_data +python3 run_cli.py -d mock_data diff --git a/run_cli.py b/run_cli.py index 3b49441..185c714 100644 --- a/run_cli.py +++ b/run_cli.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 # # Copyright 2014, Red Hat, Inc # diff --git a/runapp.py b/runapp.py index 6510268..b26b66c 100644 --- a/runapp.py +++ b/runapp.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 # # runapp.py - script to facilitate running the vault app from the CLI # diff --git a/setup.py b/setup.py index 9ed77a8..aaaa0e5 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 from setuptools import setup import codecs diff --git a/vault.spec b/vault.spec index 946381d..1d3908e 100644 --- a/vault.spec +++ b/vault.spec @@ -9,27 +9,22 @@ Source0: https://releases.pagure.org/%{name}/%{name}-%{version}.tar.gz BuildArch: noarch -Requires: python2-alembic -Requires: python2-flask -Requires: python2-flask-httpauth -%if 0%{?fedora} <= 27 -Requires: python-flask-login -Requires: python-flask-wtf -%else -Requires: python2-flask-login -Requires: python2-flask-wtf -%endif -Requires: python2-flask-oidc -Requires: python2-flask-restful -Requires: python2-flask-sqlalchemy -Requires: python2-crypto - -BuildRequires: python2-devel -BuildRequires: python2-setuptools +Requires: python3-alembic +Requires: python3-flask +Requires: python3-flask-httpauth +Requires: python3-flask-login +Requires: python3-flask-wtf +Requires: python3-flask-oidc +Requires: python3-flask-restful +Requires: python3-flask-sqlalchemy +Requires: python3-crypto + +BuildRequires: python3-devel +BuildRequires: python3-setuptools %description -Vault stores and controls encrypted data like passwords, +Vault stores and controls encrypted data like passwords, API keys or other secrets. Implements bucket-based access control, and secret versioning. %prep @@ -41,10 +36,10 @@ Implements bucket-based access control, and secret versioning. rm -f %{buildroot}%{_sysconfdir}/vault/*.py{c,o} %build -%py2_build +%py3_build %install -%py2_install +%py3_install # apache and wsgi settings install -d %{buildroot}%{_datadir}/vault/conf @@ -62,8 +57,8 @@ install -p -m 0644 conf/settings.py.example %{buildroot}%{_sysconfdir}/vault/set %files %doc README.md %license LICENSE -%{python2_sitelib}/vault -%{python2_sitelib}/*.egg-info +%{python3_sitelib}/vault +%{python3_sitelib}/*.egg-info %{_bindir}/vault %dir %{_sysconfdir}/vault diff --git a/vault/controllers/admin.py b/vault/controllers/admin.py index b85ffe9..da0f6c5 100644 --- a/vault/controllers/admin.py +++ b/vault/controllers/admin.py @@ -18,7 +18,7 @@ # Josef Skladanka from flask import Blueprint, render_template, abort -from flask.ext.login import login_required, current_user +from flask_login import login_required, current_user admin = Blueprint('admin', __name__) diff --git a/vault/controllers/login_page.py b/vault/controllers/login_page.py index 15d3176..261e428 100644 --- a/vault/controllers/login_page.py +++ b/vault/controllers/login_page.py @@ -19,12 +19,12 @@ import flask from flask import Blueprint, render_template, redirect, flash, url_for, request -from flask.ext.wtf import Form +from flask_wtf import Form from wtforms import TextField, PasswordField, HiddenField from wtforms.validators import Required import flask_login -from flask.ext.login import login_user, logout_user -from flask.ext.login import current_user, AnonymousUserMixin +from flask_login import login_user, logout_user +from flask_login import current_user, AnonymousUserMixin import munch diff --git a/vault/controllers/main.py b/vault/controllers/main.py index 18d9d41..8eadd78 100644 --- a/vault/controllers/main.py +++ b/vault/controllers/main.py @@ -23,8 +23,8 @@ from flask import Blueprint, render_template, request, jsonify, redirect, flash, import werkzeug.exceptions from sqlalchemy.orm import exc as orm_exc -from flask.ext.restful import reqparse -from flask.ext.login import login_user, logout_user, login_required, current_user +from flask_restful import reqparse +from flask_login import login_user, logout_user, login_required, current_user from werkzeug.exceptions import HTTPException from werkzeug.exceptions import BadRequest as JSONBadRequest @@ -146,7 +146,7 @@ def show_buckets(): -from flask.ext.wtf import Form +from flask_wtf import Form from wtforms import Label, TextField, SelectField, TextAreaField, HiddenField, FieldList, FormField from wtforms.validators import Required diff --git a/vault/models/secrets.py b/vault/models/secrets.py index 717f52e..0339b2b 100644 --- a/vault/models/secrets.py +++ b/vault/models/secrets.py @@ -30,23 +30,28 @@ from vault import db, app from vault.serializers import DBSerialize from .user import User -pad = lambda s: s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size) +pad = lambda s: s + (AES.block_size - len(s) % AES.block_size) * chr(AES.block_size - len(s) % AES.block_size).encode("utf-8") unpad = lambda s: s[:-ord(s[len(s)-1:])] MASTERKEY = base64.b64decode(app.config['MASTERKEY']) def encrypt(value, key): + if isinstance(value, str): + value = value.encode("utf-8") iv = Random.new().read(AES.block_size) cipher = AES.new(key, AES.MODE_CBC, iv) ciphertext = (iv + cipher.encrypt(pad(value))) return base64.b64encode(ciphertext) -def decrypt(ciphertext, key): +def decrypt(ciphertext, key, output_bytes=False): ciphertext = base64.b64decode(ciphertext) dec_iv = ciphertext[:AES.block_size] dec_cipher = AES.new(key, AES.MODE_CBC, dec_iv) - return unpad(dec_cipher.decrypt(ciphertext[16:])) + if output_bytes: + return unpad(dec_cipher.decrypt(ciphertext[16:])) + else: + return unpad(dec_cipher.decrypt(ciphertext[16:])).decode("utf-8") class Secret(db.Model, DBSerialize): @@ -102,7 +107,7 @@ class Bucket(db.Model, DBSerialize): @property def access_key(self): if not hasattr(self, '_access_key'): - self._access_key = decrypt(self.ciphertext, MASTERKEY) + self._access_key = decrypt(self.ciphertext, MASTERKEY, output_bytes=True) return self._access_key @property diff --git a/vault/models/user.py b/vault/models/user.py index ca0b75d..d14b931 100644 --- a/vault/models/user.py +++ b/vault/models/user.py @@ -18,7 +18,7 @@ # Josef Skladanka from vault import db -from flask.ext.login import UserMixin +from flask_login import UserMixin from werkzeug.security import generate_password_hash, check_password_hash USERNAME_OIDC_GROUP_PREFIX = u"FAS GROUP: " diff --git a/vault/serializers/__init__.py b/vault/serializers/__init__.py index 6482ea3..c10a91e 100644 --- a/vault/serializers/__init__.py +++ b/vault/serializers/__init__.py @@ -19,6 +19,10 @@ from datetime import date, datetime +try: + basestring +except NameError: + basestring = (str, bytes) class DBSerialize(object): pass @@ -38,10 +42,14 @@ class BaseSerializer(object): if isinstance(value, dict): ret = {} - for k, v in value.iteritems(): + for k, v in value.items(): ret[k] = self.serialize(v, **kwargs) return ret + #in py3 string-like types have __iter__ causing endless loops + if isinstance(value, basestring): + return value + # convert iterables to list of serialized stuff if hasattr(value, '__iter__'): ret = [] diff --git a/vault/serializers/api_v1.py b/vault/serializers/api_v1.py index 554f646..b380580 100644 --- a/vault/serializers/api_v1.py +++ b/vault/serializers/api_v1.py @@ -32,7 +32,7 @@ class Serializer(BaseSerializer): value=o.value, ) - return {key: self.serialize(value) for key, value in rv.iteritems()} + return {key: self.serialize(value) for key, value in rv.items()} def _serialize_Bucket(self, o, **kwargs): rv = dict( @@ -44,7 +44,7 @@ class Serializer(BaseSerializer): secrets=dict([(s.name, s.value) for s in o.secrets if s.active]), ) - return {key: self.serialize(value) for key, value in rv.iteritems()} + return {key: self.serialize(value) for key, value in rv.items()} def _serialize_BucketRoles(self, o, **kwargs): @@ -53,4 +53,4 @@ class Serializer(BaseSerializer): role=o.role, ) - return {key: self.serialize(value) for key, value in rv.iteritems()} + return {key: self.serialize(value) for key, value in rv.items()} From e0802fbf2ad03edcd521c84483dbe35d1199c4df Mon Sep 17 00:00:00 2001 From: František Zatloukal Date: Jan 22 2019 14:32:44 +0000 Subject: [PATCH 3/3] Add missing dep: python3-munch --- diff --git a/vault.spec b/vault.spec index 1d3908e..1619bb3 100644 --- a/vault.spec +++ b/vault.spec @@ -18,6 +18,7 @@ Requires: python3-flask-oidc Requires: python3-flask-restful Requires: python3-flask-sqlalchemy Requires: python3-crypto +Requires: python3-munch BuildRequires: python3-devel BuildRequires: python3-setuptools