rucioにおいて、URLの署名を行うREST APIのエンドポイントに、認証バイパスの脆弱性があります。

## 概要
`/credentials/signurl`エンドポイントは、認証されたトークンのアカウント情報ではなく、クライアントから提供されるHTTPヘッダー`X-Rucio-Account`の値に基づいて認証を行います。 したがって、**任意の**有効な認証トークン(たとえ、正当に所有している低権限のアカウントであっても)を持つクライアントが、`X-Rucio-Account: root`というヘッダーを送信することで、rootユーザーのみが許可されるチェックを回避し、RSE(ストレージシステム)に保存されているS3/GCS/Swiftの認証情報を使用して、**任意の**オブジェクトに対する、あらかじめ署名された**読み取り/書き込み/削除**URLをRucioサーバーから取得することができます。

## 詳細
`SignURL.get()`メソッドは、リクエストヘッダーから認証主体を取得し、トークン認証されたユーザーの情報を一切使用しません。

```python
# lib/rucio/web/rest/flaskapi/v1/credentials.py
account = request.headers.get('X-Rucio-Account', default=None) # L165 (攻撃者によって制御可能)
...
result = get_signed_url(account, rse=rse, service=service, # L194
operation=operation, url=url, lifetime=lifetime, vo=vo)
```

その後、ゲートウェイはこのヘッダーの値を、権限チェックの`issuer`として使用します。

```python
# lib/rucio/gateway/credential.py
auth_result = permission.has_permission(issuer=account, vo=vo, # L57
action='get_signed_url', kwargs=kwargs, ...)
```

そして、この権限チェックを行う関数は、rootユーザーのみが許可されます。

```python
# lib/rucio/core/permission/generic.py
def perm_get_signed_url(issuer, kwargs, session):
return _is_root(issuer) # _is_root(x) -> x.external == 'root'
```

`InternalAccount('root', vo).external == 'root'`は常に真であるため、ヘッダーが`root`の場合、常に権限チェックを通過します。 このエンドポイントは`AuthenticatedBlueprint`上に構築されており、`before_request`フックによってトークンが検証され、`request.environ['issuer']`が**トークンから取得**されます。 しかし、`X-Rucio-Account`の値は、この`request.environ['issuer']`と比較されることはありません。

```python
# lib/rucio/web/rest/flaskapi/v1/common.py (request_auth_env)
flask.request.environ['issuer'] = auth.get('account') # L168 (実際のアカウント。SignURLでは使用されない)
```

これは異常な点です。他の認証ハンドラでは、`request.environ['issuer']`からアカウントを派生させていますが、`credentials.py`だけがヘッダーを信頼しています。さらに、`core.credential.get_signed_url`は、提供された`url`のホスト/バケットがターゲットのRSEに属しているかどうかを一切確認しません。そのため、正当な`root`ユーザーでも、任意のオブジェクトの署名を取得できてしまいます。マルチVO環境では、VOも`X-Rucio-VO`ヘッダーから読み取られ、テナント間のアクセスを可能にします。

## 実証
リクエスト(有効なトークン + 偽装されたアカウント):
```
GET /credentials/signurl?rse=<cloudRSE>&svc=s3&op=delete&url=https://victim-bucket.s3.amazonaws.com/important/dataset.root HTTP/1.1
X-Rucio-Auth-Token: <有効なトークン、たとえ権限の低いアカウントでも>
X-Rucio-Account: root
Accept: application/octet-stream
```
レスポンス:`200 OK`。攻撃者は、このプリサインドされたDELETE URLを直接ストレージバックエンドに対して再利用できます。

## 影響
権限の低いRucioユーザーは、サーバーが保持する認証情報を使用して、クラウドベース(S3/GCS/Swift)の任意のRSE上の任意のオブジェクトを読み取り、上書き、削除できます。これにより、データの漏洩、改ざん、破壊、およびマルチVO環境でのテナント間のアクセスが可能になります。

## 報告者
seankohjs氏が報告。静的解析と手動検証により発見。

影響を受けるパッケージ:
- pip (Python) rucio: 影響を受けるバージョン >= 1.16.1, < 35.9.0、修正バージョン 35.9.0
- pip (Python) rucio: 影響を受けるバージョン >= 36.0.0rc1, < 38.6.0、修正バージョン 38.6.0
- pip (Python) rucio: 影響を受けるバージョン >= 39.0.0rc1, < 41.0.0rc1、修正バージョン 41.0.0rc1