github-advanced-security[bot] commented on code in PR #72647:
URL: https://github.com/apache/airflow/pull/72647#discussion_r4066722378


##########
providers/amazon/src/airflow/providers/amazon/aws/auth_manager/routes/login.py:
##########
@@ -59,6 +70,101 @@
 log = logging.getLogger(__name__)
 login_router = AirflowRouter(tags=["AWSAuthManagerLogin"])
 
+# Name of the short-lived cookie recording which logins this browser has 
started.
+COOKIE_NAME_LOGIN_STATE = "_awsam_login_state"
+
+# The login flow is a redirect to the IdP and back. Ten minutes is generous 
for that and
+# keeps a stale request id from lingering.
+LOGIN_STATE_MAX_AGE = 600
+
+# One entry per login started and not yet completed, so opening a second tab 
does not
+# invalidate the first. The cap bounds the cookie; the oldest pending login is 
dropped.
+MAX_PENDING_LOGINS = 5
+
+LOGIN_MODE_REDIRECT = "login-redirect"
+LOGIN_MODE_TOKEN = "login-token"
+LOGIN_MODES = (LOGIN_MODE_REDIRECT, LOGIN_MODE_TOKEN)
+
+NO_LOGIN_IN_PROGRESS = "No login in progress for this browser. Start the login 
from Airflow and try again."
+
+
+def _is_secure_request(request: Request) -> bool:
+    return request.base_url.scheme == "https" or bool(conf.get("api", 
"ssl_cert", fallback=""))
+
+
+def _allows_idp_initiated_login() -> bool:
+    return conf.getboolean(CONF_SECTION_NAME, 
CONF_ALLOW_IDP_INITIATED_LOGIN_KEY, fallback=False)
+
+
+def _sign_login_state(payload: str) -> str:
+    # The API server secret key is already required to be identical across API 
servers, so a
+    # login may start on one instance and finish on another.
+    secret = conf.get("api", "secret_key", fallback="")
+    return hmac.new(secret.encode(), payload.encode(), sha256).hexdigest()
+
+
+def _read_pending_logins(request: Request) -> list[dict[str, Any]]:
+    """
+    Return the logins this browser started and has not yet completed.
+
+    This cookie is the browser's half of the binding: it states that *this* 
browser asked for
+    these AuthnRequests. A SAML assertion is signed by the identity provider, 
which
+    authenticates *the identity in the response* -- it says nothing about 
*which browser
+    asked*. Without this, an assertion obtained by an attacker can be replayed 
into a
+    victim's browser, logging the victim into the attacker's account.
+
+    Entries are signed so a response cannot contribute one of its own, and 
each carries its
+    own deadline so an abandoned tab expires without affecting the others.
+    """
+    raw = request.cookies.get(COOKIE_NAME_LOGIN_STATE)
+    if not raw:
+        return []
+    payload, _, signature = raw.rpartition(".")
+    if not payload or not hmac.compare_digest(signature, 
_sign_login_state(payload)):
+        log.warning("Ignoring a login state cookie that this deployment did 
not sign.")
+        return []
+    try:
+        entries = json.loads(base64.urlsafe_b64decode(payload))
+    except (ValueError, binascii.Error):
+        log.warning("Ignoring a login state cookie that could not be decoded.")
+        return []
+    if not isinstance(entries, list):
+        return []
+    now = time.time()
+    return [
+        entry
+        for entry in entries
+        if isinstance(entry, dict) and isinstance(entry.get("exp"), (int, 
float)) and entry["exp"] > now
+    ]
+
+
+def _write_pending_logins(request: Request, response: Any, entries: 
list[dict[str, Any]]) -> None:
+    cookie_path = get_cookie_path()
+    if not entries:
+        response.delete_cookie(COOKIE_NAME_LOGIN_STATE, path=cookie_path)
+        return
+    payload = base64.urlsafe_b64encode(json.dumps(entries, separators=(",", 
":")).encode()).decode()
+    response.set_cookie(
+        COOKIE_NAME_LOGIN_STATE,
+        f"{payload}.{_sign_login_state(payload)}",

Review Comment:
   ## CodeQL / Construction of a cookie using user-supplied input
   
   Cookie is constructed from a [user-supplied input](1).
   Cookie is constructed from a [user-supplied input](2).
   
   [Show more 
details](https://github.com/apache/airflow/security/code-scanning/657)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to