From d166b7e21331ca6a0775880c6b13c0087d04a85f Mon Sep 17 00:00:00 2001 From: Filip Valder Date: Fri, 25 Nov 2016 19:46:40 +0100 Subject: [PATCH] move & lint --- module_build_service/manage.py | 274 +++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 module_build_service/manage.py diff --git a/module_build_service/manage.py b/module_build_service/manage.py new file mode 100644 index 00000000..b0647324 --- /dev/null +++ b/module_build_service/manage.py @@ -0,0 +1,274 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2016 Red Hat, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Written by Matt Prahl except for the test functions + +from flask_script import Manager +import flask_migrate +import logging +import os +import ssl +from shutil import rmtree +import getpass + +from module_build_service import app, conf, db +from module_build_service import models +from module_build_service.pdc import ( + get_pdc_client_session, get_module, get_module_runtime_dependencies, + get_module_tag, get_module_build_dependencies) +import module_build_service.auth +import module_build_service.scheduler.main +from module_build_service.utils import submit_module_build +from module_build_service.messaging import RidaModule + + +manager = Manager(app) +migrate = flask_migrate.Migrate(app, db) +manager.add_command('db', flask_migrate.MigrateCommand) + + +def _establish_ssl_context(): + if not conf.ssl_enabled: + return None + # First, do some validation of the configuration + attributes = ( + 'ssl_certificate_file', + 'ssl_certificate_key_file', + 'ssl_ca_certificate_file', + ) + + for attribute in attributes: + value = getattr(conf, attribute, None) + if not value: + raise ValueError("%r could not be found" % attribute) + if not os.path.exists(value): + raise OSError("%s: %s file not found." % (attribute, value)) + + # Then, establish the ssl context and return it + ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + ssl_ctx.load_cert_chain(conf.ssl_certificate_file, + conf.ssl_certificate_key_file) + ssl_ctx.verify_mode = ssl.CERT_OPTIONAL + ssl_ctx.load_verify_locations(cafile=conf.ssl_ca_certificate_file) + return ssl_ctx + + +@manager.command +def testpdc(): + """ A helper function to test pdc interaction + """ + cfg = conf + cfg.pdc_url = "http://modularity.fedorainfracloud.org:8080/rest_api/v1" + cfg.pdc_insecure = True + cfg.pdc_develop = True + + pdc_session = get_pdc_client_session(cfg) + module = get_module(pdc_session, {'name': 'testmodule', 'version': '4.3.43', + 'release': '1'}) + + if module: + print("pdc_data=%s" % str(module)) + print("deps=%s" % get_module_runtime_dependencies(pdc_session, module)) + print("build_deps=%s" % get_module_build_dependencies( + pdc_session, module)) + print("tag=%s" % get_module_tag(pdc_session, module)) + else: + print('module was not found') + + +@manager.command +def upgradedb(): + """ Upgrades the database schema to the latest revision + """ + flask_migrate.upgrade() + + +@manager.command +def cleardb(): + models.ModuleBuild.query.delete() + models.ComponentBuild.query.delete() + + +@manager.command +def build_module_locally(url): + conf.set_item("system", "mock") + username = getpass.getuser() + + cleardb() + submit_module_build(username, url) + + msgs = [] + msgs.append(RidaModule("fake msg", 1, 1)) + module_build_service.scheduler.main.main(msgs, True) + + +@manager.command +def gendevfedmsgcert(pki_dir='/opt/module_build_service/pki', force=False): + """ + Creates a CA, a certificate signed by that CA, and generates a CRL. + """ + from OpenSSL import crypto + + if os.path.exists(pki_dir): + if force: + rmtree(pki_dir) + else: + print('The directory "{}" already exists'.format(pki_dir)) + return + + os.mkdir(pki_dir) + + ca_crt_path = os.path.join(pki_dir, 'ca.crt') + ca_key_path = os.path.join(pki_dir, 'ca.key') + msg_key_path = os.path.join(pki_dir, 'localhost.key') + msg_crt_path = os.path.join(pki_dir, 'localhost.crt') + ca_crl = os.path.join(pki_dir, 'ca.crl') + + # Create a key pair for the CA + ca_key = crypto.PKey() + ca_key.generate_key(crypto.TYPE_RSA, 2048) + + with open(ca_key_path, 'w') as ca_key_file: + ca_key_file.write( + crypto.dump_privatekey(crypto.FILETYPE_PEM, ca_key)) + + # Create a self-signed CA cert + ca_cert = crypto.X509() + ca_subject = ca_cert.get_subject() + ca_subject.C = 'US' + ca_subject.ST = 'MA' + ca_subject.L = 'Boston' + ca_subject.O = 'Development' + ca_subject.CN = 'Dev-CA' + ca_cert.set_serial_number(1) + ca_cert.gmtime_adj_notBefore(0) + ca_cert.gmtime_adj_notAfter(315360000) # 10 years + ca_cert.set_issuer(ca_cert.get_subject()) + ca_cert.set_pubkey(ca_key) + ca_cert.add_extensions([ + crypto.X509Extension('basicConstraints', True, 'CA:true')]) + ca_cert.sign(ca_key, 'sha256') + + with open(ca_crt_path, 'w') as ca_crt_file: + ca_crt_file.write( + crypto.dump_certificate(crypto.FILETYPE_PEM, ca_cert)) + + # Create a key pair for the message signing cert + msg_key = crypto.PKey() + msg_key.generate_key(crypto.TYPE_RSA, 2048) + + with open(msg_key_path, 'w') as msg_key_file: + msg_key_file.write( + crypto.dump_privatekey(crypto.FILETYPE_PEM, msg_key)) + + # Create a cert signed by the CA + msg_cert = crypto.X509() + msg_cert_subject = msg_cert.get_subject() + msg_cert_subject.C = 'US' + msg_cert_subject.ST = 'MA' + msg_cert_subject.L = 'Boston' + msg_cert_subject.O = 'Development' + msg_cert_subject.CN = 'localhost' + msg_cert.set_serial_number(2) + msg_cert.gmtime_adj_notBefore(0) + msg_cert.gmtime_adj_notAfter(315360000) # 10 years + msg_cert.set_issuer(ca_cert.get_subject()) + msg_cert.set_pubkey(msg_key) + cert_extensions = [ + crypto.X509Extension( + 'keyUsage', True, + 'digitalSignature, keyEncipherment, nonRepudiation'), + crypto.X509Extension('extendedKeyUsage', True, 'serverAuth'), + crypto.X509Extension('basicConstraints', True, 'CA:false'), + crypto.X509Extension('crlDistributionPoints', False, + 'URI:http://localhost/crl/ca.crl'), + crypto.X509Extension('authorityInfoAccess', False, + 'caIssuers;URI:http://localhost/crl/ca.crt'), + crypto.X509Extension('subjectKeyIdentifier', False, 'hash', + subject=ca_cert) + ] + msg_cert.add_extensions(cert_extensions) + msg_cert.sign(ca_key, 'sha256') + + with open(msg_crt_path, 'w') as msg_crt_file: + msg_crt_file.write( + crypto.dump_certificate(crypto.FILETYPE_PEM, msg_cert)) + + # Generate the CRL + with open(ca_crl, 'w') as ca_crl_file: + ca_crl_file.write( + crypto.CRL().export(ca_cert, ca_key, type=crypto.FILETYPE_PEM, + days=3650, digest='sha256')) + + +@manager.command +def generatelocalhostcert(): + # Create a key pair for the message signing cert + from OpenSSL import crypto + cert_key = crypto.PKey() + cert_key.generate_key(crypto.TYPE_RSA, 2048) + + with open('server.key', 'w') as cert_key_file: + cert_key_file.write( + crypto.dump_privatekey(crypto.FILETYPE_PEM, cert_key)) + + cert = crypto.X509() + msg_cert_subject = cert.get_subject() + msg_cert_subject.C = 'US' + msg_cert_subject.ST = 'MA' + msg_cert_subject.L = 'Boston' + msg_cert_subject.O = 'Development' + msg_cert_subject.CN = 'localhost' + cert.set_serial_number(2) + cert.gmtime_adj_notBefore(0) + cert.gmtime_adj_notAfter(315360000) # 10 years + cert.set_issuer(cert.get_subject()) + cert.set_pubkey(cert_key) + cert_extensions = [ + crypto.X509Extension( + 'keyUsage', True, + 'digitalSignature, keyEncipherment, nonRepudiation'), + crypto.X509Extension('extendedKeyUsage', True, 'serverAuth'), + ] + cert.add_extensions(cert_extensions) + cert.sign(cert_key, 'sha256') + + with open('server.crt', 'w') as cert_file: + cert_file.write( + crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) + + +@manager.command +def runssl(host=conf.host, port=conf.port, debug=False): + """ Runs the Flask app with the HTTPS settings configured in config.py + """ + logging.info('Starting Rida') + ssl_ctx = _establish_ssl_context() + app.run( + host=host, + port=port, + request_handler=module_build_service.auth.ClientCertRequestHandler, + ssl_context=ssl_ctx, + debug=debug + ) + +if __name__ == "__main__": + manager.run()