Merge branch 'master' into dependabot/npm_and_yarn/pbkdf2-3.1.3

This commit is contained in:
Tsuneo Yoshioka
2025-07-29 23:38:08 +09:00
committed by GitHub
5 changed files with 56 additions and 19 deletions

View File

@@ -121,7 +121,7 @@ jobs:
context: .
build-args: |
test_all_deps=true
outputs: type=image,push-by-digest=true,push=true
outputs: type=image,push-by-digest=false,push=true
cache-from: type=gha,scope=${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=${{ matrix.arch }}
env:

View File

@@ -4,7 +4,7 @@ import requests
from authlib.integrations.flask_client import OAuth
from flask import Blueprint, flash, redirect, request, session, url_for
from redash import models
from redash import models, settings
from redash.authentication import (
create_and_login_user,
get_next_path,
@@ -29,6 +29,41 @@ def verify_profile(org, profile):
return False
def get_user_profile(access_token, logger):
headers = {"Authorization": f"OAuth {access_token}"}
response = requests.get("https://www.googleapis.com/oauth2/v1/userinfo", headers=headers)
if response.status_code == 401:
logger.warning("Failed getting user profile (response code 401).")
return None
return response.json()
def build_redirect_uri():
scheme = settings.GOOGLE_OAUTH_SCHEME_OVERRIDE or None
return url_for(".callback", _external=True, _scheme=scheme)
def build_next_path(org_slug=None):
next_path = request.args.get("next")
if not next_path:
if org_slug is None:
org_slug = session.get("org_slug")
scheme = None
if settings.GOOGLE_OAUTH_SCHEME_OVERRIDE:
scheme = settings.GOOGLE_OAUTH_SCHEME_OVERRIDE
next_path = url_for(
"redash.index",
org_slug=org_slug,
_external=True,
_scheme=scheme,
)
return next_path
def create_google_oauth_blueprint(app):
oauth = OAuth(app)
@@ -36,23 +71,12 @@ def create_google_oauth_blueprint(app):
blueprint = Blueprint("google_oauth", __name__)
CONF_URL = "https://accounts.google.com/.well-known/openid-configuration"
oauth = OAuth(app)
oauth.register(
name="google",
server_metadata_url=CONF_URL,
client_kwargs={"scope": "openid email profile"},
)
def get_user_profile(access_token):
headers = {"Authorization": "OAuth {}".format(access_token)}
response = requests.get("https://www.googleapis.com/oauth2/v1/userinfo", headers=headers)
if response.status_code == 401:
logger.warning("Failed getting user profile (response code 401).")
return None
return response.json()
@blueprint.route("/<org_slug>/oauth/google", endpoint="authorize_org")
def org_login(org_slug):
session["org_slug"] = current_org.slug
@@ -60,9 +84,9 @@ def create_google_oauth_blueprint(app):
@blueprint.route("/oauth/google", endpoint="authorize")
def login():
redirect_uri = url_for(".callback", _external=True)
redirect_uri = build_redirect_uri()
next_path = request.args.get("next", url_for("redash.index", org_slug=session.get("org_slug")))
next_path = build_next_path()
logger.debug("Callback url: %s", redirect_uri)
logger.debug("Next is: %s", next_path)
@@ -86,7 +110,7 @@ def create_google_oauth_blueprint(app):
flash("Validation error. Please retry.")
return redirect(url_for("redash.login"))
profile = get_user_profile(access_token)
profile = get_user_profile(access_token, logger)
if profile is None:
flash("Validation error. Please retry.")
return redirect(url_for("redash.login"))
@@ -110,7 +134,9 @@ def create_google_oauth_blueprint(app):
if user is None:
return logout_and_redirect_to_index()
unsafe_next_path = session.get("next_url") or url_for("redash.index", org_slug=org.slug)
unsafe_next_path = session.get("next_url")
if not unsafe_next_path:
unsafe_next_path = build_next_path(org.slug)
next_path = get_next_path(unsafe_next_path)
return redirect(next_path)

View File

@@ -564,7 +564,7 @@ class Query(ChangeTrackingMixin, TimestampMixin, BelongsToOrgMixin, db.Model):
db.session.query(tag_column, usage_count)
.group_by(tag_column)
.filter(Query.id.in_(queries.options(load_only("id"))))
.order_by(usage_count.desc())
.order_by(tag_column)
)
return query
@@ -1137,7 +1137,7 @@ class Dashboard(ChangeTrackingMixin, TimestampMixin, BelongsToOrgMixin, db.Model
db.session.query(tag_column, usage_count)
.group_by(tag_column)
.filter(Dashboard.id.in_(dashboards.options(load_only("id"))))
.order_by(usage_count.desc())
.order_by(tag_column)
)
return query

View File

@@ -313,6 +313,10 @@ class BigQuery(BaseSQLQueryRunner):
queries = []
for dataset in datasets:
dataset_id = dataset["datasetReference"]["datasetId"]
location = dataset["location"]
if self._get_location() and location != self._get_location():
logger.debug("dataset location is different: %s", location)
continue
query = query_base.format(dataset_id=dataset_id)
queries.append(query)

View File

@@ -136,6 +136,13 @@ FEATURE_POLICY = os.environ.get("REDASH_FEATURE_POLICY", "")
MULTI_ORG = parse_boolean(os.environ.get("REDASH_MULTI_ORG", "false"))
# If Redash is behind a proxy it might sometimes receive a X-Forwarded-Proto of HTTP
# even if your actual Redash URL scheme is HTTPS. This will cause Flask to build
# the OAuth redirect URL incorrectly thus failing auth. This is especially common if
# you're behind a SSL/TCP configured AWS ELB or similar.
# This setting will force the URL scheme.
GOOGLE_OAUTH_SCHEME_OVERRIDE = os.environ.get("REDASH_GOOGLE_OAUTH_SCHEME_OVERRIDE", "")
GOOGLE_CLIENT_ID = os.environ.get("REDASH_GOOGLE_CLIENT_ID", "")
GOOGLE_CLIENT_SECRET = os.environ.get("REDASH_GOOGLE_CLIENT_SECRET", "")
GOOGLE_OAUTH_ENABLED = bool(GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET)