CTFd / CTFd

CTFs as you need them
https://ctfd.io
Apache License 2.0
5.7k stars 2.1k forks source link

MySQL password is being ignored, server fails to start when database has password #645

Closed nierardi closed 6 years ago

nierardi commented 6 years ago

Environment:

What happened?

It appears that the config.py is blatantly ignoring the MySQL password I enter. I'm using gunicorn to run CTFd.

Here is my SQLALCHEMY_DATABASE_URI config value:

SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:ctfdctfd@localhost/ctfd' note: this is just a temporary password

I have consulted the create_engine() statement example from http://docs.sqlalchemy.org/en/latest/dialects/mysql.html#transaction-isolation-level, as well as http://flask-sqlalchemy.pocoo.org/2.1/config/#configuration-keys. The format should be mysql+pymysql://<user>:<password>@<ip>/<database>.

On startup, I get this error as the very last line, before it stops:

OperationalError: (pymysql.err.OperationalError) (1045, u"Access denied for user 'root'@'localhost' (using password: NO)") (Background on this error at: http://sqlalche.me/e/e3q8)

The only way I can run CTFd is with an unsecured database, with no password at all. I cannot use CTFd in a production environment with no database security.

What did you expect to happen?

No error, startup as normal.

How to reproduce your issue

  1. Clone repo.
  2. Create a MySQL database named ctfd.
  3. Fill out SQLALCHEMY_DATABASE_URI in config.py
  4. Use gunicorn to start server.

Any associated stack traces or error logs

Entire console output from server start to stop:

[root@localhost CTFd]# gunicorn --bind 0.0.0.0:8009 -w 1 "CTFd:create_app()"
[2018-06-22 14:19:06 +0000] [3562] [INFO] Starting gunicorn 19.7.1
[2018-06-22 14:19:06 +0000] [3562] [INFO] Listening at: http://0.0.0.0:8009 (3562)
[2018-06-22 14:19:06 +0000] [3562] [INFO] Using worker: sync
[2018-06-22 14:19:06 +0000] [3567] [INFO] Booting worker with pid: 3567
[2018-06-22 14:19:06 +0000] [3567] [ERROR] Exception in worker process
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/gunicorn/arbiter.py", line 578, in spawn_worker
    worker.init_process()
  File "/usr/lib/python2.7/site-packages/gunicorn/workers/base.py", line 126, in init_process
    self.load_wsgi()
  File "/usr/lib/python2.7/site-packages/gunicorn/workers/base.py", line 135, in load_wsgi
    self.wsgi = self.app.wsgi()
  File "/usr/lib/python2.7/site-packages/gunicorn/app/base.py", line 67, in wsgi
    self.callable = self.load()
  File "/usr/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 65, in load
    return self.load_wsgiapp()
  File "/usr/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 52, in load_wsgiapp
    return util.import_app(self.app_uri)
  File "/usr/lib/python2.7/site-packages/gunicorn/util.py", line 364, in import_app
    app = eval(obj, vars(mod))
  File "<string>", line 1, in <module>
  File "/root/CTFd/CTFd/__init__.py", line 103, in create_app
    if not database_exists(url):
  File "/usr/lib/python2.7/site-packages/sqlalchemy_utils/functions/database.py", line 477, in database_exists
    return bool(get_scalar_result(engine, text))
  File "/usr/lib/python2.7/site-packages/sqlalchemy_utils/functions/database.py", line 455, in get_scalar_result
    result_proxy = engine.execute(sql)
  File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 2074, in execute
    connection = self.contextual_connect(close_with_result=True)
  File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 2123, in contextual_connect
    self._wrap_pool_connect(self.pool.connect, None),
  File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 2162, in _wrap_pool_connect
    e, dialect, self)
  File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1476, in _handle_dbapi_exception_noconnection
    exc_info
  File "/usr/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 203, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb, cause=cause)
  File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 2158, in _wrap_pool_connect
    return fn()
  File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 403, in connect
    return _ConnectionFairy._checkout(self)
  File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 782, in _checkout
    fairy = _ConnectionRecord.checkout(pool)
  File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 532, in checkout
    rec = pool._do_get()
  File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 1186, in _do_get
    self._dec_overflow()
  File "/usr/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 66, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 1183, in _do_get
    return self._create_connection()
  File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 350, in _create_connection
    return _ConnectionRecord(self)
  File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 477, in __init__
    self.__connect(first_connect_check=True)
  File "/usr/lib/python2.7/site-packages/sqlalchemy/pool.py", line 667, in __connect
    connection = pool._invoke_creator(self)
  File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/strategies.py", line 105, in connect
    return dialect.connect(*cargs, **cparams)
  File "/usr/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 410, in connect
    return self.dbapi.connect(*cargs, **cparams)
  File "/usr/lib/python2.7/site-packages/pymysql/__init__.py", line 90, in Connect
    return Connection(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/pymysql/connections.py", line 699, in __init__
    self.connect()
  File "/usr/lib/python2.7/site-packages/pymysql/connections.py", line 936, in connect
    self._request_authentication()
  File "/usr/lib/python2.7/site-packages/pymysql/connections.py", line 1156, in _request_authentication
    auth_packet = self._read_packet()
  File "/usr/lib/python2.7/site-packages/pymysql/connections.py", line 1018, in _read_packet
    packet.check_error()
  File "/usr/lib/python2.7/site-packages/pymysql/connections.py", line 384, in check_error
    err.raise_mysql_exception(self._data)
  File "/usr/lib/python2.7/site-packages/pymysql/err.py", line 107, in raise_mysql_exception
    raise errorclass(errno, errval)
OperationalError: (pymysql.err.OperationalError) (1045, u"Access denied for user 'root'@'localhost' (using password: NO)") (Background on this error at: http://sqlalche.me/e/e3q8)
[2018-06-22 14:19:06 +0000] [3567] [INFO] Worker exiting (pid: 3567)
[2018-06-22 14:19:06 +0000] [3562] [INFO] Shutting down: Master
[2018-06-22 14:19:06 +0000] [3562] [INFO] Reason: Worker failed to boot.
ColdHeat commented 6 years ago

It's very unlikely that CTFd is failing to use the provided config because this code hasn't changed in a long time and it's worked for myself and others.

Have you installed all dependencies? Can you perhaps try this with a new less privileged user? I have seen issues wehre MySQL is unhappy with people using root to connect to the database.

nierardi commented 6 years ago

I've installed requirements.txt already. All dependencies are satisfied.

I just made a new user "ctfd" and granted it appropriate privileges, changed it in the config, and I am getting the same error message. Any ideas why?

EDIT reinstalling did not appear to fix the problem

ANOTHER EDIT the url object created in create_app() does contain the specified username and password, as expected: <<< DEBUG >>> url username: root url password: ctfdctfd

nierardi commented 6 years ago

I have downgraded MySQL to 5.7.21 and it will now authenticate properly.

Are other users able to authenticate their databases when using MySQL 8?