prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  API keys should be supported in the HTTP headers
  Currently it seems that all API calls must include the `api_key` in the query string. Ideally the HTTP headers could also be used (e.g. `Authorization: Key XXXX` or `X-Api-Key`) so that Web server logs don't log the API key in the clear.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `redash/authentication.py`
  Content:
  ```
  1 import hashlib
  2 import hmac
  3 import time
  4 import logging
  5 
  6 from flask.ext.login import LoginManager
  7 from flask.ext.login import user_logged_in
  8 
  9 from redash import models, settings, google_oauth, saml_auth
  10 from redash.tasks import record_event
  11 
  12 login_manager = LoginManager()
  13 logger = logging.getLogger('authentication')
  14 
  15 
  16 def sign(key, path, expires):
  17     if not key:
  18         return None
  19 
  20     h = hmac.new(str(key), msg=path, digestmod=hashlib.sha1)
  21     h.update(str(expires))
  22 
  23     return h.hexdigest()
  24 
  25 
  26 @login_manager.user_loader
  27 def load_user(user_id):
  28     return models.User.get_by_id(user_id)
  29 
  30 
  31 def hmac_load_user_from_request(request):
  32     signature = request.args.get('signature')
  33     expires = float(request.args.get('expires') or 0)
  34     query_id = request.view_args.get('query_id', None)
  35     user_id = request.args.get('user_id', None)
  36 
  37     # TODO: 3600 should be a setting
  38     if signature and time.time() < expires <= time.time() + 3600:
  39         if user_id:
  40             user = models.User.get_by_id(user_id)
  41             calculated_signature = sign(user.api_key, request.path, expires)
  42 
  43             if user.api_key and signature == calculated_signature:
  44                 return user
  45 
  46         if query_id:
  47             query = models.Query.get(models.Query.id == query_id)
  48             calculated_signature = sign(query.api_key, request.path, expires)
  49 
  50             if query.api_key and signature == calculated_signature:
  51                 return models.ApiUser(query.api_key)
  52 
  53     return None
  54 
  55 def get_user_from_api_key(api_key, query_id):
  56     if not api_key:
  57         return None
  58 
  59     user = None
  60     try:
  61         user = models.User.get_by_api_key(api_key)
  62     except models.User.DoesNotExist:
  63         if query_id:
  64             query = models.Query.get_by_id(query_id)
  65             if query and query.api_key == api_key:
  66                 user = models.ApiUser(api_key)
  67 
  68     return user
  69 
  70 def api_key_load_user_from_request(request):
  71     api_key = request.args.get('api_key', None)
  72     query_id = request.view_args.get('query_id', None)
  73 
  74     user = get_user_from_api_key(api_key, query_id)
  75     return user
  76 
  77 
  78 def log_user_logged_in(app, user):
  79     event = {
  80         'user_id': user.id,
  81         'action': 'login',
  82         'object_type': 'redash',
  83         'timestamp': int(time.time()),
  84     }
  85 
  86     record_event.delay(event)
  87 
  88 
  89 def setup_authentication(app):
  90     login_manager.init_app(app)
  91     login_manager.anonymous_user = models.AnonymousUser
  92     login_manager.login_view = 'login'
  93     app.secret_key = settings.COOKIE_SECRET
  94     app.register_blueprint(google_oauth.blueprint)
  95     app.register_blueprint(saml_auth.blueprint)
  96 
  97     user_logged_in.connect(log_user_logged_in)
  98 
  99     if settings.AUTH_TYPE == 'hmac':
  100         login_manager.request_loader(hmac_load_user_from_request)
  101     elif settings.AUTH_TYPE == 'api_key':
  102         login_manager.request_loader(api_key_load_user_from_request)
  103     else:
  104         logger.warning("Unknown authentication type ({}). Using default (HMAC).".format(settings.AUTH_TYPE))
  105         login_manager.request_loader(hmac_load_user_from_request)
  106 
  107 
  108
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/redash/authentication.py b/redash/authentication.py
  --- a/redash/authentication.py
  +++ b/redash/authentication.py
  @@ -52,6 +52,7 @@
   
       return None
   
  +
   def get_user_from_api_key(api_key, query_id):
       if not api_key:
           return None
  @@ -67,8 +68,19 @@
   
       return user
   
  -def api_key_load_user_from_request(request):
  +
  +def get_api_key_from_request(request):
       api_key = request.args.get('api_key', None)
  +
  +    if api_key is None and request.headers.get('Authorization'):
  +        auth_header = request.headers.get('Authorization')
  +        api_key = auth_header.replace('Key ', '', 1)
  +
  +    return api_key
  +
  +
  +def api_key_load_user_from_request(request):
  +    api_key = get_api_key_from_request(request)
       query_id = request.view_args.get('query_id', None)
   
       user = get_user_from_api_key(api_key, query_id)
  
verification_info: {"golden_diff": "diff --git a/redash/authentication.py b/redash/authentication.py\n--- a/redash/authentication.py\n+++ b/redash/authentication.py\n@@ -52,6 +52,7 @@\n \n     return None\n \n+\n def get_user_from_api_key(api_key, query_id):\n     if not api_key:\n         return None\n@@ -67,8 +68,19 @@\n \n     return user\n \n-def api_key_load_user_from_request(request):\n+\n+def get_api_key_from_request(request):\n     api_key = request.args.get('api_key', None)\n+\n+    if api_key is None and request.headers.get('Authorization'):\n+        auth_header = request.headers.get('Authorization')\n+        api_key = auth_header.replace('Key ', '', 1)\n+\n+    return api_key\n+\n+\n+def api_key_load_user_from_request(request):\n+    api_key = get_api_key_from_request(request)\n     query_id = request.view_args.get('query_id', None)\n \n     user = get_user_from_api_key(api_key, query_id)\n", "issue": "API keys should be supported in the HTTP headers\nCurrently it seems that all API calls must include the `api_key` in the query string. Ideally the HTTP headers could also be used (e.g. `Authorization: Key XXXX` or `X-Api-Key`) so that Web server logs don't log the API key in the clear.\n\n", "before_files": [{"content": "import hashlib\nimport hmac\nimport time\nimport logging\n\nfrom flask.ext.login import LoginManager\nfrom flask.ext.login import user_logged_in\n\nfrom redash import models, settings, google_oauth, saml_auth\nfrom redash.tasks import record_event\n\nlogin_manager = LoginManager()\nlogger = logging.getLogger('authentication')\n\n\ndef sign(key, path, expires):\n    if not key:\n        return None\n\n    h = hmac.new(str(key), msg=path, digestmod=hashlib.sha1)\n    h.update(str(expires))\n\n    return h.hexdigest()\n\n\n@login_manager.user_loader\ndef load_user(user_id):\n    return models.User.get_by_id(user_id)\n\n\ndef hmac_load_user_from_request(request):\n    signature = request.args.get('signature')\n    expires = float(request.args.get('expires') or 0)\n    query_id = request.view_args.get('query_id', None)\n    user_id = request.args.get('user_id', None)\n\n    # TODO: 3600 should be a setting\n    if signature and time.time() < expires <= time.time() + 3600:\n        if user_id:\n            user = models.User.get_by_id(user_id)\n            calculated_signature = sign(user.api_key, request.path, expires)\n\n            if user.api_key and signature == calculated_signature:\n                return user\n\n        if query_id:\n            query = models.Query.get(models.Query.id == query_id)\n            calculated_signature = sign(query.api_key, request.path, expires)\n\n            if query.api_key and signature == calculated_signature:\n                return models.ApiUser(query.api_key)\n\n    return None\n\ndef get_user_from_api_key(api_key, query_id):\n    if not api_key:\n        return None\n\n    user = None\n    try:\n        user = models.User.get_by_api_key(api_key)\n    except models.User.DoesNotExist:\n        if query_id:\n            query = models.Query.get_by_id(query_id)\n            if query and query.api_key == api_key:\n                user = models.ApiUser(api_key)\n\n    return user\n\ndef api_key_load_user_from_request(request):\n    api_key = request.args.get('api_key', None)\n    query_id = request.view_args.get('query_id', None)\n\n    user = get_user_from_api_key(api_key, query_id)\n    return user\n\n\ndef log_user_logged_in(app, user):\n    event = {\n        'user_id': user.id,\n        'action': 'login',\n        'object_type': 'redash',\n        'timestamp': int(time.time()),\n    }\n\n    record_event.delay(event)\n\n\ndef setup_authentication(app):\n    login_manager.init_app(app)\n    login_manager.anonymous_user = models.AnonymousUser\n    login_manager.login_view = 'login'\n    app.secret_key = settings.COOKIE_SECRET\n    app.register_blueprint(google_oauth.blueprint)\n    app.register_blueprint(saml_auth.blueprint)\n\n    user_logged_in.connect(log_user_logged_in)\n\n    if settings.AUTH_TYPE == 'hmac':\n        login_manager.request_loader(hmac_load_user_from_request)\n    elif settings.AUTH_TYPE == 'api_key':\n        login_manager.request_loader(api_key_load_user_from_request)\n    else:\n        logger.warning(\"Unknown authentication type ({}). Using default (HMAC).\".format(settings.AUTH_TYPE))\n        login_manager.request_loader(hmac_load_user_from_request)\n\n\n", "path": "redash/authentication.py"}], "after_files": [{"content": "import hashlib\nimport hmac\nimport time\nimport logging\n\nfrom flask.ext.login import LoginManager\nfrom flask.ext.login import user_logged_in\n\nfrom redash import models, settings, google_oauth, saml_auth\nfrom redash.tasks import record_event\n\nlogin_manager = LoginManager()\nlogger = logging.getLogger('authentication')\n\n\ndef sign(key, path, expires):\n    if not key:\n        return None\n\n    h = hmac.new(str(key), msg=path, digestmod=hashlib.sha1)\n    h.update(str(expires))\n\n    return h.hexdigest()\n\n\n@login_manager.user_loader\ndef load_user(user_id):\n    return models.User.get_by_id(user_id)\n\n\ndef hmac_load_user_from_request(request):\n    signature = request.args.get('signature')\n    expires = float(request.args.get('expires') or 0)\n    query_id = request.view_args.get('query_id', None)\n    user_id = request.args.get('user_id', None)\n\n    # TODO: 3600 should be a setting\n    if signature and time.time() < expires <= time.time() + 3600:\n        if user_id:\n            user = models.User.get_by_id(user_id)\n            calculated_signature = sign(user.api_key, request.path, expires)\n\n            if user.api_key and signature == calculated_signature:\n                return user\n\n        if query_id:\n            query = models.Query.get(models.Query.id == query_id)\n            calculated_signature = sign(query.api_key, request.path, expires)\n\n            if query.api_key and signature == calculated_signature:\n                return models.ApiUser(query.api_key)\n\n    return None\n\n\ndef get_user_from_api_key(api_key, query_id):\n    if not api_key:\n        return None\n\n    user = None\n    try:\n        user = models.User.get_by_api_key(api_key)\n    except models.User.DoesNotExist:\n        if query_id:\n            query = models.Query.get_by_id(query_id)\n            if query and query.api_key == api_key:\n                user = models.ApiUser(api_key)\n\n    return user\n\n\ndef get_api_key_from_request(request):\n    api_key = request.args.get('api_key', None)\n\n    if api_key is None and request.headers.get('Authorization'):\n        auth_header = request.headers.get('Authorization')\n        api_key = auth_header.replace('Key ', '', 1)\n\n    return api_key\n\n\ndef api_key_load_user_from_request(request):\n    api_key = get_api_key_from_request(request)\n    query_id = request.view_args.get('query_id', None)\n\n    user = get_user_from_api_key(api_key, query_id)\n    return user\n\n\ndef log_user_logged_in(app, user):\n    event = {\n        'user_id': user.id,\n        'action': 'login',\n        'object_type': 'redash',\n        'timestamp': int(time.time()),\n    }\n\n    record_event.delay(event)\n\n\ndef setup_authentication(app):\n    login_manager.init_app(app)\n    login_manager.anonymous_user = models.AnonymousUser\n    login_manager.login_view = 'login'\n    app.secret_key = settings.COOKIE_SECRET\n    app.register_blueprint(google_oauth.blueprint)\n    app.register_blueprint(saml_auth.blueprint)\n\n    user_logged_in.connect(log_user_logged_in)\n\n    if settings.AUTH_TYPE == 'hmac':\n        login_manager.request_loader(hmac_load_user_from_request)\n    elif settings.AUTH_TYPE == 'api_key':\n        login_manager.request_loader(api_key_load_user_from_request)\n    else:\n        logger.warning(\"Unknown authentication type ({}). Using default (HMAC).\".format(settings.AUTH_TYPE))\n        login_manager.request_loader(hmac_load_user_from_request)\n\n\n", "path": "redash/authentication.py"}]}