Ejemplo n.º 1
0
def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    read_users(settings['auth.file'])
    config = Configurator(
        settings=settings,
        authentication_policy=BasicAuthAuthenticationPolicy(
            auth_check, __name__),
        authorization_policy=ACLAuthorizationPolicy(),
        root_factory=Root,
    )
    config.add_request_method(request_params, 'params', reify=True)
    config.add_subscriber(new_request_subscriber, NewRequest)
    config.add_subscriber(add_logging_context, ContextFound)
    config.include('pyramid_exclog')
    config.add_route('status', '/')
    config.add_route('register', '/register')
    config.add_route('upload', '/upload')
    config.add_route('upload_file', '/upload/{doc_id}')
    config.add_route('get', '/get/{doc_id}')
    config.scan(ignore='openprocurement.documentservice.tests')

    config.registry.signer = signer = Signer(
        settings.get('dockey', '').decode('hex'))
    config.registry.dockey = dockey = signer.hex_vk()[:8]
    verifier = Verifier(signer.hex_vk())
    config.registry.dockeyring = dockeyring = {dockey: verifier}
    dockeys = settings.get(
        'dockeys') if 'dockeys' in settings else Signer().hex_vk()
    for key in dockeys.split('\0'):
        dockeyring[key[:8]] = Verifier(key)
    config.registry.keyring = keyring = {dockey: verifier}
    apikeys = settings.get(
        'apikeys') if 'apikeys' in settings else Signer().hex_vk()
    for key in apikeys.split('\0'):
        keyring[key[:8]] = Verifier(key)
    config.registry.apikey = key[:8]

    config.registry.upload_host = settings.get('upload_host')
    config.registry.get_host = settings.get('get_host')

    # search for storage
    storage = settings.get('storage')
    for entry_point in iter_entry_points(
            'openprocurement.documentservice.plugins', storage):
        plugin = entry_point.load()
        config.registry.storage = plugin(config)

    return config.make_wsgi_app()
Ejemplo n.º 2
0
def bid_id_signature_verified_active_bid(self):
    if self.initial_organization == self.test_financial_organization:
        response = self.app.post_json(
            '/auctions/{}/bids'.format(self.auction_id), {
                'data': {
                    'tenderers': [self.initial_organization],
                    'qualified': True,
                    'eligible': True
                }
            })
    else:
        response = self.app.post_json(
            '/auctions/{}/bids'.format(self.auction_id), {
                'data': {
                    'tenderers': [self.initial_organization],
                    'qualified': True
                }
            })
    bidder = response.json['data']
    signature = bidder['participationUrl']
    before, sep, sig = signature.partition('signature=')
    sig = b64decode(unquote(str(sig)))
    signer = Signer(
        'fe3b3b5999a08e68dfe62687c2ae147f62712ceace58c1ffca8ea819eabcb5d1'.
        decode('hex'))
    ver = Verifier(signer.hex_vk())
    verified = ver.verify(sig +
                          str('{}_{}'.format(self.auction_id, bidder['id'])))
    self.assertEqual(verified, '{}_{}'.format(self.auction_id, bidder['id']))
def migrate_from0to1(self):
    set_db_schema_version(self.db, 0)
    u = Auction(test_auction_data)
    u.auctionID = "UA-X"
    u.store(self.db)
    data = self.db.get(u.id)
    url = "/tenders/{}/documents/ebcb5dd7f7384b0fbfbed2dc4252fa6e?download=10367238a2964ee18513f209d9b6d1d3"
    data["documents"] = [{
        "id": "ebcb5dd7f7384b0fbfbed2dc4252fa6e",
        "title": "name.txt",
        "url": url.format(u.id),
        "datePublished": "2016-06-01T00:00:00+03:00",
        "dateModified": "2016-06-01T00:00:00+03:00",
        "format": "text/plain",
    }]
    _id, _rev = self.db.save(data)
    self.app.app.registry.docservice_url = 'http://localhost'
    self.app.app.registry.use_docservice = True
    self.app.app.registry.docservice_key = Signer()
    migrate_data(self.app.app.registry, 1)
    migrated_item = self.db.get(u.id)
    self.assertIn('http://localhost/get/10367238a2964ee18513f209d9b6d1d3?',
                  migrated_item['documents'][0]['url'])
    self.assertIn('Prefix={}%2Febcb5dd7f7384b0fbfbed2dc4252fa6e'.format(u.id),
                  migrated_item['documents'][0]['url'])
    self.assertIn('KeyID=', migrated_item['documents'][0]['url'])
    self.assertIn('Signature=', migrated_item['documents'][0]['url'])
Ejemplo n.º 4
0
 def _login_jwt_user(self,
                     web_request: WebRequest,
                     create: bool = False) -> Dict[str, Any]:
     username: str = web_request.get_str('username')
     password: str = web_request.get_str('password')
     user_info: Dict[str, Any]
     if username in RESERVED_USERS:
         raise self.server.error(f"Invalid Request for user {username}")
     if create:
         if username in self.users:
             raise self.server.error(f"User {username} already exists")
         salt = secrets.token_bytes(32)
         hashed_pass = hashlib.pbkdf2_hmac('sha256', password.encode(),
                                           salt, HASH_ITER).hex()
         user_info = {
             'username': username,
             'password': hashed_pass,
             'salt': salt.hex(),
             'created_on': time.time()
         }
         self.users[username] = user_info
         action = "user_created"
     else:
         if username not in self.users:
             raise self.server.error(f"Unregistered User: {username}")
         user_info = self.users[username]
         salt = bytes.fromhex(user_info['salt'])
         hashed_pass = hashlib.pbkdf2_hmac('sha256', password.encode(),
                                           salt, HASH_ITER).hex()
         action = "user_logged_in"
     if hashed_pass != user_info['password']:
         raise self.server.error("Invalid Password")
     jwt_secret_hex: Optional[str] = user_info.get('jwt_secret', None)
     if jwt_secret_hex is None:
         private_key = Signer()
         jwk_id = base64url_encode(secrets.token_bytes()).decode()
         user_info['jwt_secret'] = private_key.hex_seed().decode()
         user_info['jwk_id'] = jwk_id
         self.users[username] = user_info
         self.public_jwks[jwk_id] = self._generate_public_jwk(private_key)
     else:
         private_key = self._load_private_key(jwt_secret_hex)
         jwk_id = user_info['jwk_id']
     token = self._generate_jwt(username, jwk_id, private_key)
     refresh_token = self._generate_jwt(
         username,
         jwk_id,
         private_key,
         token_type="refresh",
         exp_time=datetime.timedelta(days=self.login_timeout))
     if create:
         IOLoop.current().call_later(.005, self.server.send_event,
                                     "authorization:user_created",
                                     {'username': username})
     return {
         'username': username,
         'token': token,
         'refresh_token': refresh_token,
         'action': action
     }
Ejemplo n.º 5
0
 def _load_private_key(self, secret: str) -> Signer:
     try:
         key = Signer(bytes.fromhex(secret))
     except Exception:
         raise self.server.error(
             "Error decoding private key, user data may"
             " be corrupt", 500) from None
     return key
def prepare_users_data(tender_data):
    auction_worker_defaults = BuiltIn().get_variable_value("${auction_worker_defaults}")
    with open(auction_worker_defaults) as auction_worker_defaults_file:
        auction_worker_defaults_info = yaml.load(auction_worker_defaults_file)
    users_data = {}
    for index, bid in enumerate(tender_data["bids"]):
        signer = Signer(auction_worker_defaults_info["SIGNATURE_KEY"].decode('hex'))
        signature = quote(b64encode(signer.signature("{}_{}".format("11111111111111111111111111111111", str(bid['id'])))))
        users_data[bid["id"]] = {
            'login_url': auction_worker_defaults_info['AUCTIONS_URL'].format(auction_id="11111111111111111111111111111111") +  '/login?bidder_id={}&signature={}'.format(
                bid["id"], signature
            ),
            'amount': bid.get('value', {}).get('amount', ''),
            'position': positions[index],
            'size': size
        }
    return users_data
Ejemplo n.º 7
0
    def test_generate_docservice_url(self):
        request = mock.MagicMock()
        request.registry = mock.MagicMock()
        request.registry.docservice_key = Signer(
            '1234567890abcdef1234567890abcdef')
        request.registry.docservice_url = 'url'
        doc_id = '1234567890abcdef1234567890abcdef'

        expected_result = '/get/1234567890abcdef1234567890abcdef?KeyID=c6c4f29c&Signature=t8L5VW%252BK5vvDwMsxHBhzs%252BcBXFsYAZ%2FM9WJmzgYLVpc8HC9mPbQhsshgGK94XaCtvKFTb9IiTLlW59TM9mV7Bg%253D%253D'
        result = generate_docservice_url(request,
                                         '1234567890abcdef1234567890abcdef',
                                         False)
        self.assertEqual(result, expected_result)

        expected_result = [
            '/get/1234567890abcdef1234567890abcdef?Prefix=test_prefix',
            '&KeyID=c6c4f29c&Signature=', '&Expires='
        ]
        result = generate_docservice_url(request,
                                         '1234567890abcdef1234567890abcdef',
                                         True, 'test_prefix')
        for item in expected_result:
            self.assertIn(item, result)
Ejemplo n.º 8
0
def main(global_config, **settings):
    config = Configurator(
        autocommit=True,
        settings=settings,
        authentication_policy=AuthenticationPolicy(settings['auth.file'], __name__),
        authorization_policy=AuthorizationPolicy(),
        route_prefix=route_prefix(settings),
    )
    config.include('pyramid_exclog')
    config.include("cornice")
    config.add_forbidden_view(forbidden)
    config.add_request_method(request_params, 'params', reify=True)
    config.add_request_method(authenticated_role, reify=True)
    config.add_request_method(extract_tender, 'tender', reify=True)
    config.add_request_method(check_accreditation)
    config.add_request_method(json_body, 'json_body', reify=True)
    config.add_renderer('json', JSON(serializer=simplejson.dumps))
    config.add_renderer('prettyjson', JSON(indent=4, serializer=simplejson.dumps))
    config.add_renderer('jsonp', JSONP(param_name='opt_jsonp', serializer=simplejson.dumps))
    config.add_renderer('prettyjsonp', JSONP(indent=4, param_name='opt_jsonp', serializer=simplejson.dumps))
    config.add_subscriber(add_logging_context, NewRequest)
    config.add_subscriber(set_logging_context, ContextFound)
    config.add_subscriber(set_renderer, NewRequest)
    config.add_subscriber(beforerender, BeforeRender)
    config.scan("openprocurement.api.views.spore")
    config.scan("openprocurement.api.views.health")

    # tender procurementMethodType plugins support
    config.add_route_predicate('procurementMethodType', isTender)
    config.registry.tender_procurementMethodTypes = {}
    config.add_request_method(tender_from_data)
    config.add_directive('add_tender_procurementMethodType', register_tender_procurementMethodType)

    # search for plugins
    plugins = settings.get('plugins') and settings['plugins'].split(',')
    for entry_point in iter_entry_points('openprocurement.api.plugins'):
        if not plugins or entry_point.name in plugins:
            plugin = entry_point.load()
            plugin(config)

    # CouchDB connection
    db_name = os.environ.get('DB_NAME', settings['couchdb.db_name'])
    server = Server(settings.get('couchdb.url'), session=Session(retry_delays=range(10)))
    if 'couchdb.admin_url' not in settings and server.resource.credentials:
        try:
            server.version()
        except Unauthorized:
            server = Server(extract_credentials(settings.get('couchdb.url'))[0])
    config.registry.couchdb_server = server
    if 'couchdb.admin_url' in settings and server.resource.credentials:
        aserver = Server(settings.get('couchdb.admin_url'), session=Session(retry_delays=range(10)))
        config.registry.admin_couchdb_server = aserver
        users_db = aserver['_users']
        if SECURITY != users_db.security:
            LOGGER.info("Updating users db security", extra={'MESSAGE_ID': 'update_users_security'})
            users_db.security = SECURITY
        username, password = server.resource.credentials
        user_doc = users_db.get('org.couchdb.user:{}'.format(username), {'_id': 'org.couchdb.user:{}'.format(username)})
        if not user_doc.get('derived_key', '') or PBKDF2(password, user_doc.get('salt', ''), user_doc.get('iterations', 10)).hexread(int(len(user_doc.get('derived_key', '')) / 2)) != user_doc.get('derived_key', ''):
            user_doc.update({
                "name": username,
                "roles": [],
                "type": "user",
                "password": password
            })
            LOGGER.info("Updating api db main user", extra={'MESSAGE_ID': 'update_api_main_user'})
            users_db.save(user_doc)
        security_users = [username, ]
        if 'couchdb.reader_username' in settings and 'couchdb.reader_password' in settings:
            reader_username = settings.get('couchdb.reader_username')
            reader = users_db.get('org.couchdb.user:{}'.format(reader_username), {'_id': 'org.couchdb.user:{}'.format(reader_username)})
            if not reader.get('derived_key', '') or PBKDF2(settings.get('couchdb.reader_password'), reader.get('salt', ''), reader.get('iterations', 10)).hexread(int(len(reader.get('derived_key', '')) / 2)) != reader.get('derived_key', ''):
                reader.update({
                    "name": reader_username,
                    "roles": ['reader'],
                    "type": "user",
                    "password": settings.get('couchdb.reader_password')
                })
                LOGGER.info("Updating api db reader user", extra={'MESSAGE_ID': 'update_api_reader_user'})
                users_db.save(reader)
            security_users.append(reader_username)
        if db_name not in aserver:
            aserver.create(db_name)
        db = aserver[db_name]
        SECURITY[u'members'][u'names'] = security_users
        if SECURITY != db.security:
            LOGGER.info("Updating api db security", extra={'MESSAGE_ID': 'update_api_security'})
            db.security = SECURITY
        auth_doc = db.get(VALIDATE_DOC_ID, {'_id': VALIDATE_DOC_ID})
        if auth_doc.get('validate_doc_update') != VALIDATE_DOC_UPDATE % username:
            auth_doc['validate_doc_update'] = VALIDATE_DOC_UPDATE % username
            LOGGER.info("Updating api db validate doc", extra={'MESSAGE_ID': 'update_api_validate_doc'})
            db.save(auth_doc)
        # sync couchdb views
        sync_design(db)
        db = server[db_name]
    else:
        if db_name not in server:
            server.create(db_name)
        db = server[db_name]
        # sync couchdb views
        sync_design(db)
    config.registry.db = db
    # readjust couchdb json decoder
    couchdb_json_decode()

    # Document Service key
    config.registry.docservice_url = settings.get('docservice_url')
    config.registry.docservice_username = settings.get('docservice_username')
    config.registry.docservice_password = settings.get('docservice_password')
    config.registry.docservice_upload_url = settings.get('docservice_upload_url')
    config.registry.docservice_key = dockey = Signer(settings.get('dockey', '').decode('hex'))
    config.registry.keyring = keyring = {}
    dockeys = settings.get('dockeys') if 'dockeys' in settings else dockey.hex_vk()
    for key in dockeys.split('\0'):
        keyring[key[:8]] = Verifier(key)

    # migrate data
    if not os.environ.get('MIGRATION_SKIP'):
        for entry_point in iter_entry_points('openprocurement.api.migrations'):
            plugin = entry_point.load()
            plugin(config.registry)

    config.registry.server_id = settings.get('id', '')
    config.registry.health_threshold = float(settings.get('health_threshold', 99))
    config.registry.update_after = asbool(settings.get('update_after', True))
    return config.make_wsgi_app()
Ejemplo n.º 9
0
def main(global_config, **settings):
    config = Configurator(
        autocommit=True,
        settings=settings,
        authentication_policy=AuthenticationPolicy(settings['auth.file'],
                                                   __name__),
        authorization_policy=AuthorizationPolicy(),
        route_prefix=ROUTE_PREFIX,
    )
    config.include('pyramid_exclog')
    config.include("cornice")
    config.add_forbidden_view(forbidden)
    config.add_request_method(request_params, 'params', reify=True)
    config.add_request_method(authenticated_role, reify=True)
    config.add_request_method(check_accreditation)
    config.add_request_method(json_body, 'json_body', reify=True)
    config.add_renderer('json', JSON(serializer=simplejson.dumps))
    config.add_renderer('prettyjson',
                        JSON(indent=4, serializer=simplejson.dumps))
    config.add_renderer(
        'jsonp', JSONP(param_name='opt_jsonp', serializer=simplejson.dumps))
    config.add_renderer(
        'prettyjsonp',
        JSONP(indent=4, param_name='opt_jsonp', serializer=simplejson.dumps))

    # search for plugins
    plugins = settings.get('plugins') and settings['plugins'].split(',')
    load_plugins(config, group='openregistry.api.plugins', plugins=plugins)

    # CouchDB connection
    aserver, server, db = set_api_security(settings)
    config.registry.couchdb_server = server
    if aserver:
        config.registry.admin_couchdb_server = aserver
    config.registry.db = db
    couchdb_json_decode()

    # Document Service key
    config.registry.docservice_url = settings.get('docservice_url')
    config.registry.docservice_username = settings.get('docservice_username')
    config.registry.docservice_password = settings.get('docservice_password')
    config.registry.docservice_upload_url = settings.get(
        'docservice_upload_url')
    config.registry.docservice_key = dockey = Signer(
        settings.get('dockey', '').decode('hex'))
    config.registry.keyring = keyring = {}
    dockeys = settings.get(
        'dockeys') if 'dockeys' in settings else dockey.hex_vk()
    for key in dockeys.split('\0'):
        keyring[key[:8]] = Verifier(key)

    # migrate data
    if not os.environ.get('MIGRATION_SKIP'):
        load_plugins(config.registry, group='openregistry.api.migrations')

    config.registry.server_id = settings.get('id', '')

    # search subscribers
    subscribers_keys = [k for k in settings if k.startswith('subscribers.')]
    for k in subscribers_keys:
        subscribers = settings[k].split(',')
        for subscriber in subscribers:
            load_plugins(config,
                         group='openregistry.{}'.format(k),
                         name=subscriber)

    config.registry.health_threshold = float(
        settings.get('health_threshold', 512))
    config.registry.health_threshold_func = settings.get(
        'health_threshold_func', 'all')
    config.registry.update_after = asbool(settings.get('update_after', True))
    return config.make_wsgi_app()
Ejemplo n.º 10
0
 def key_decode_sk(string):
     return Signer(b64_decode(string))
Ejemplo n.º 11
0
Archivo: app.py Proyecto: lttga/op2
def main(global_config, **settings):
    dsn = settings.get("sentry.dsn", None)
    if dsn:
        LOGGER.info("Init sentry sdk for {}".format(dsn))
        sentry_sdk.init(
            dsn=dsn,
            integrations=[
                LoggingIntegration(level=None, event_level=None),
                PyramidIntegration()
            ],
            send_default_pii=True,
            request_bodies="always",
            environment=settings.get("sentry.environment", None),
            debug=settings.get("sentry.debug", False),
        )

    config = Configurator(
        autocommit=True,
        settings=settings,
        authentication_policy=AuthenticationPolicy(settings["auth.file"],
                                                   __name__),
        authorization_policy=AuthorizationPolicy(),
        route_prefix=ROUTE_PREFIX,
    )
    config.include("pyramid_exclog")
    config.include("cornice")
    config.add_forbidden_view(forbidden)
    config.add_view(precondition, context=HTTPPreconditionFailed)
    config.add_request_method(request_params, "params", reify=True)
    config.add_request_method(authenticated_role, reify=True)
    config.add_request_method(check_accreditations)
    config.add_request_method(get_currency_rates,
                              name="currency_rates",
                              reify=True)
    config.add_renderer("json", JSON(serializer=simplejson.dumps))
    config.add_renderer("prettyjson",
                        JSON(indent=4, serializer=simplejson.dumps))
    config.add_renderer(
        "jsonp", JSONP(param_name="opt_jsonp", serializer=simplejson.dumps))
    config.add_renderer(
        "prettyjsonp",
        JSONP(indent=4, param_name="opt_jsonp", serializer=simplejson.dumps))

    # search for plugins
    plugins = settings.get("plugins") and [
        plugin.strip() for plugin in settings["plugins"].split(",")
    ]
    for entry_point in iter_entry_points("openprocurement.api.plugins"):
        if not plugins or entry_point.name in plugins:
            plugin = entry_point.load()
            plugin(config)

    # CouchDB connection
    aserver, server, db = set_api_security(settings)
    config.registry.couchdb_server = server
    if aserver:
        config.registry.admin_couchdb_server = aserver
    config.registry.db = db
    # readjust couchdb json decoder
    couchdb_json_decode()

    # Document Service key
    config.registry.docservice_url = settings.get("docservice_url")
    config.registry.docservice_username = settings.get("docservice_username")
    config.registry.docservice_password = settings.get("docservice_password")
    config.registry.docservice_upload_url = settings.get(
        "docservice_upload_url")
    config.registry.docservice_key = dockey = Signer(
        settings.get("dockey", "").decode("hex"))
    config.registry.keyring = keyring = {}
    dockeys = settings.get(
        "dockeys") if "dockeys" in settings else dockey.hex_vk()
    for key in dockeys.split("\0"):
        keyring[key[:8]] = Verifier(key)

    # Archive keys
    arch_pubkey = settings.get("arch_pubkey", None)
    config.registry.arch_pubkey = PublicKey(
        arch_pubkey.decode("hex") if arch_pubkey else SecretKey().pk)

    # migrate data
    if not os.environ.get("MIGRATION_SKIP"):
        for entry_point in iter_entry_points("openprocurement.api.migrations"):
            plugin = entry_point.load()
            plugin(config.registry)

    config.registry.server_id = settings.get("id", "")

    # search subscribers
    subscribers_keys = [k for k in settings if k.startswith("subscribers.")]
    for k in subscribers_keys:
        subscribers = settings[k].split(",")
        for subscriber in subscribers:
            for entry_point in iter_entry_points(
                    "openprocurement.{}".format(k), subscriber):
                if entry_point:
                    plugin = entry_point.load()
                    plugin(config)

    config.registry.health_threshold = float(
        settings.get("health_threshold", 512))
    config.registry.health_threshold_func = settings.get(
        "health_threshold_func", "all")
    config.registry.update_after = asbool(settings.get("update_after", True))
    return config.make_wsgi_app()
Ejemplo n.º 12
0
 async def _login_jwt_user(self,
                           web_request: WebRequest,
                           create: bool = False) -> Dict[str, Any]:
     username: str = web_request.get_str('username')
     password: str = web_request.get_str('password')
     source: str = web_request.get_str('source',
                                       self.default_source).lower()
     if source not in AUTH_SOURCES:
         raise self.server.error(f"Invalid 'source': {source}")
     user_info: Dict[str, Any]
     if username in RESERVED_USERS:
         raise self.server.error(f"Invalid Request for user {username}")
     if source == "ldap":
         if create:
             raise self.server.error("Cannot Create LDAP User")
         if self.ldap is None:
             raise self.server.error("LDAP authentication not available",
                                     401)
         await self.ldap.authenticate_ldap_user(username, password)
         if username not in self.users:
             create = True
     if create:
         if username in self.users:
             raise self.server.error(f"User {username} already exists")
         salt = secrets.token_bytes(32)
         hashed_pass = hashlib.pbkdf2_hmac('sha256', password.encode(),
                                           salt, HASH_ITER).hex()
         user_info = {
             'username': username,
             'password': hashed_pass,
             'salt': salt.hex(),
             'source': source,
             'created_on': time.time()
         }
         self.users[username] = user_info
         self._sync_user(username)
         action = "user_created"
         if source == "ldap":
             # Dont notify user created
             action = "user_logged_in"
             create = False
     else:
         if username not in self.users:
             raise self.server.error(f"Unregistered User: {username}")
         user_info = self.users[username]
         auth_src = user_info.get("source", "moonraker")
         if auth_src != source:
             raise self.server.error(
                 f"Moonraker cannot authenticate user '{username}', must "
                 f"specify source '{auth_src}'", 401)
         salt = bytes.fromhex(user_info['salt'])
         hashed_pass = hashlib.pbkdf2_hmac('sha256', password.encode(),
                                           salt, HASH_ITER).hex()
         action = "user_logged_in"
         if hashed_pass != user_info['password']:
             raise self.server.error("Invalid Password")
     jwt_secret_hex: Optional[str] = user_info.get('jwt_secret', None)
     if jwt_secret_hex is None:
         private_key = Signer()
         jwk_id = base64url_encode(secrets.token_bytes()).decode()
         user_info['jwt_secret'] = private_key.hex_seed().decode()
         user_info['jwk_id'] = jwk_id
         self.users[username] = user_info
         self._sync_user(username)
         self.public_jwks[jwk_id] = self._generate_public_jwk(private_key)
     else:
         private_key = self._load_private_key(jwt_secret_hex)
         jwk_id = user_info['jwk_id']
     token = self._generate_jwt(username, jwk_id, private_key)
     refresh_token = self._generate_jwt(
         username,
         jwk_id,
         private_key,
         token_type="refresh",
         exp_time=datetime.timedelta(days=self.login_timeout))
     if create:
         event_loop = self.server.get_event_loop()
         event_loop.delay_callback(.005, self.server.send_event,
                                   "authorization:user_created",
                                   {'username': username})
     return {
         'username': username,
         'token': token,
         'source': user_info.get("source", "moonraker"),
         'refresh_token': refresh_token,
         'action': action
     }
class AuctionInsiderAuthorizedTest(TaskSet):
    signer = Signer(SIGNATURE_KEY.decode('hex'))

    auction_src = None
    auction_id = None
    saved_cookies = None
    last_change = 0
    csses = []
    dutch_winner = ''
    dutch_winner_amount = 0
    auction_doc = {}
    ind = False
    current_phase = None
    current_stage = None
    initial_value = 0
    current_time = '2000-01-01T00:00:00.000000+02:00'
    next_stage_start = '2000-01-01T00:00:00+02:00'

    def __init__(self, parent):
        self.auction_id = \
            auction_id_template.format(random.randint(0, AUCTIONS_NUMBER - 1))
        self.bidder_id = BIDDERS[random.randint(0, len(BIDDERS) - 1)]
        msg = '{}_{}'.format(self.auction_id, self.bidder_id)
        self.signature = quote(b64encode(self.signer.signature(str(msg))))
        self.auth_params = {
            "bidder_id": self.bidder_id,
            "signature": self.signature
        }
        super(AuctionInsiderAuthorizedTest, self).__init__(parent)

    def post_bid(self, params):
        self.client.post(
            '/insider-auctions/{}/postbid'.format(self.auction_id),
            data=json.dumps(params),
            headers={'Content-Type': 'application/json'},
            name='Place bid to auction. Phase: {}, id: {}'.
                format(self.current_phase, self.auction_id)
        )

    @task(1)
    def main_task(self):
        self.get_auction_doc_from_couchdb()

        if self.current_phase != u'announcement':  # and self.current_stage >= 0:
            response = self.client.get(
                '/insider-auctions/{}/login'.format(self.auction_id),
                params=self.auth_params, name="Login to auction",
                allow_redirects=False, catch_response=True
            )
            if response.ok and 'Location' in response.headers:
                if response.headers['Location'].\
                        startswith(self.client.base_url):
                    sleep(10)
                    return

                response = self.client.get(response.headers['Location'],
                                           name="Get EULA page")
                if not response.ok:
                    raise Exception('Client could not get EULA page')

                redirect_url = urlparse(response.request.url)
                query = parse_qs(redirect_url.query)

                params = {
                    "client_id": query['client_id'][0],
                    "scope": query['scope'][0],
                    "bidder_id": query['bidder_id'][0],
                    "response_type": query['response_type'][0],
                    "redirect_uri": query['redirect_uri'][0],
                    "confirm": "yes"
                }
                response = self.client.post(
                    '{0.scheme}://{0.netloc}{0.path}'.format(redirect_url),
                    data=params, name="Click yes on EULA"
                )
                if response.ok:
                    self.saved_cookies = copy.copy(self.client.cookies)
                    self.get_auction_page()
                    self.load_all_css()
                    self.load_all_js()
                    self.get_auctions_db_info()
                    long_pool = spawn(self.changes_multiple)
                    self.read_event_source(self.saved_cookies)
                    joinall([long_pool])
                else:
                    raise Exception('Client could not click yes on EULA')
        sleep(10)

    def get_auction_page(self):
        resp = self.client.get('/insider-auctions/{}'.format(self.auction_id),
                               name='Get auction page')
        self.auction_src = resp.content

    def load_all_css(self):
        pq = PyQuery(self.auction_src)
        for style in pq('link[rel="stylesheet"]'):
            href = style.get('href')
            if href and href.startswith('/') and not href.startswith('//'):
                resp = self.client.get(href)
                if resp.status_code == 200:
                    css = resp.content
                    self.csses.append(
                        tinycss2.parse_stylesheet_bytes(
                            css, skip_comments=True)
                    )

    def load_all_js(self):
        pq = PyQuery(self.auction_src)

        for script in pq('script'):
            src = script.get('src')
            if src and src.startswith('/') and not src.startswith('//'):
                self.client.get(src)

    def get_auction_doc_from_couchdb(self):
        resp = self.client.get(
            '/database/{0}?_nonce={0}'.format(self.auction_id,
                                              random.random()),
            name="Get document from couch")
        doc = json.loads(resp.content)

        self.current_stage = doc['current_stage']
        self.current_phase = doc['current_phase']
        self.initial_value = doc['initial_value']

        if len(doc['stages']) > int(doc['current_stage']) + 1:
            self.next_stage_start = \
                doc['stages'][doc['current_stage'] + 1]['start']

    def get_auctions_db_info(self):
        self.client.get('/database?_nonce={0}'.format(random.random()),
                        name="Get db info")

    def read_event_source(self, cookies):
        start_time = time()
        response = self.client.get(
            "/insider-auctions/{0}/event_source?lastEventId=&r={1}".format(
                self.auction_id,
                random.randint(1000000000000000, 9999999999999999)
            ),
            stream=True, cookies=requests.utils.dict_from_cookiejar(cookies),
            name="Get event_source stream"
        )
        response_length = 0
        try:
            if response.ok:
                for line in response.iter_lines():
                    response_length += len(line)
                    sleep(0.1)
        except:
            pass
        total_time = int((time() - start_time) * 1000)
        events.request_success.fire(
            request_type="GET",
            name="Get event_source stream (Finish read)",
            response_time=total_time,
            response_length=response_length
        )
        sleep(3)

    def changes_multiple(self):
        while self.current_phase != u'announcement':
            params = {}
            self.changes()
            self.get_current_server_time()

            if self.current_phase == u'dutch' and \
                    self.auction_doc['current_stage'] >= dutch_steps/2 and \
                    not self.dutch_winner and \
                    self.before_time(self.current_time,
                                     parse_date(self.next_stage_start)):

                stage = self.auction_doc['stages'][
                    self.auction_doc['current_stage']]
                params['bidder_id'] = self.bidder_id
                params['bid'] = stage['amount']

            elif self.current_phase == u'sealedbid' and \
                    self.bidder_id != self.dutch_winner and \
                    self.before_time(self.current_time,
                                     parse_date(self.next_stage_start)):

                params['bidder_id'] = self.bidder_id
                params['bid'] = random.randint(self.dutch_winner_amount,
                                               99*self.initial_value/100 - 2)

            elif self.current_phase == u'bestbid' and \
                    self.bidder_id == self.dutch_winner and \
                    self.before_time(self.current_time,
                                     parse_date(self.next_stage_start)):
                params['bidder_id'] = self.bidder_id
                params['bid'] = int(self.initial_value - 1)

            if params:
                self.post_bid(params)

    def get_current_server_time(self):
        resp = self.client.get(
            '/get_current_server_time?_nonce={0}'.format(random.random()),
            name="Get current server time")
        if resp.status_code == 200:
            current_time_str = resp.headers['date']
            self.current_time = parser.parse(current_time_str)

    def changes(self):
        params = {
            'timeout': 25000,
            'style': 'main_only',
            'heartbeat': 10000,
            'include_docs': 'true',
            'feed': 'longpoll',
            'filter': '_doc_ids',
            'since': self.last_change,
            'limit': 25,
            '_nonce': random.random(),
            'doc_ids': '["{0}"]'.format(self.auction_id)
        }
        if self.last_change == 0:
            name = "Get first change from couch"
        else:
            name = "Get change from couch (longpoll)"

        resp = self.client.get('/database/_changes', params=params, name=name)
        if resp.status_code == 200:
            doc = json.loads(resp.content)
            if len(doc['results']) > 0:
                self.auction_doc = doc['results'][-1]['doc']
                self.current_phase = self.auction_doc['current_phase']
                self.current_stage = self.auction_doc['current_stage']

                if not self.dutch_winner:
                    for result in self.auction_doc['results']:
                        if 'dutch_winner' in result:
                            self.dutch_winner = result['bidder_id']
                            self.dutch_winner_amount = result['amount']

            self.last_change = doc['last_seq']

    @staticmethod
    def before_time(time1, time2):
        return time1 < time2 - timedelta(seconds=3)