From 6d072b3718b570238d822f4dcec9220571a59cc6 Mon Sep 17 00:00:00 2001 From: Nitload <105042599+Nitload-NSI@users.noreply.github.com> Date: Tue, 6 Oct 2026 11:28:13 +0800 Subject: [PATCH] Add Android OIDC callback broker for Termux --- docs/authentication.md | 5 +++ docs/platforms/android-client.md | 2 + src/android/MainActivity.cs | 77 ++++++++++++++++++++++++++++++++ src/client/OidcLogin.cs | 62 ++++++++++++++++++++----- src/client/Program.cs | 24 ++++++++++ 5 files changed, 160 insertions(+), 10 deletions(-) diff --git a/docs/authentication.md b/docs/authentication.md index dc70e97..f2824bb 100644 --- a/docs/authentication.md +++ b/docs/authentication.md @@ -1,5 +1,10 @@ # 身份认证与授权 +桌面 Client 使用动态 loopback URI `http://127.0.0.1:<动态端口>/callback`;Termux +Client 使用 `com.nitload.charac://oauth/callback`,由 Android APK 接收 authentik +回调,再通过 Termux `RUN_COMMAND` 转回 CLI。authentik Provider 必须同时允许这两类 +Redirect URI。 + CLI 已实现 authentik OIDC Authorization Code + PKCE 的浏览器登录和本机回调;令牌仅保存在当前 CLI 进程内。Server 使用 JWT Bearer 中间件从 HTTPS OIDC discovery 获取签名密钥,校验签名、issuer、audience 和有效期,再以稳定的 `(iss, sub)` 识别用户。资源列表、创建、附着、结束工作区均重新查询数据库授权。需在 authentik 创建 public client、启用 PKCE、设置允许的 `http://127.0.0.1:<动态端口>/callback` 回调,并为 Provider 配置非对称 JWT 签名密钥。Server 配置 `[oidc] issuer` 和 `client_id`;若采用 authentik 的全局 issuer 模式,还需设置指向应用 slug 下 discovery 文档的 `discovery_url`。正式 Client 的 `login` 已通过真实 authentik 浏览器登录及 Server 令牌校验;2026-10-05 已在 `.100 → .101` 实测目标授权、资源选择和交互式 `ls`;正常退出及重新附着待复测。 管理员将外部身份映射到允许访问的目标机器和系统账户。Windows 目标使用账户 SID,Linux 目标使用 UID/GID;实际登录环境及文件权限由目标 sshd 和操作系统建立。不同外部身份即使映射到同一个系统账户,工作区归属仍独立。 diff --git a/docs/platforms/android-client.md b/docs/platforms/android-client.md index c417365..fbffa7d 100644 --- a/docs/platforms/android-client.md +++ b/docs/platforms/android-client.md @@ -1,5 +1,7 @@ # Android CLI 客户端 +Termux 登录不让浏览器直接访问 Termux 的 `127.0.0.1`:CLI 通过 `/system/bin/am` 启动 APK,APK 注册 `com.nitload.charac://oauth/callback` 并接收 authentik 回调,再用 `RUN_COMMAND` 调用 `charac callback` 将授权码转回 CLI 的本地监听器。 + 推荐把 Android CLI 作为 Termux DEB 分发,而不是把 CLI 当成普通 Android APK。APK 只是可选的 One UI 启动器:它不能单独运行 CLI,必须与 Termux、Termux DEB、运行命令权限和 `allow-external-apps=true` 配置一起使用。直接安装 APK 后点击图标不能替代 Termux 环境,也不会自动安装 .NET 或 `charac`。 Android 首期支持 ARM64 设备上的 Termux 终端,CLI 使用 `linux-bionic-arm64` RID。另有独立的 .NET Android 启动器项目 `src/android/CharacAndroid.csproj`,包 ID 为 `com.nitload.charac`;Server 仍只部署在 Windows 或 Linux。 diff --git a/src/android/MainActivity.cs b/src/android/MainActivity.cs index 0f08cd6..93b441e 100644 --- a/src/android/MainActivity.cs +++ b/src/android/MainActivity.cs @@ -9,12 +9,17 @@ using Android.Widget; namespace Charac.Android; [Activity(Label = "@string/app_name", MainLauncher = true, Exported = true, LaunchMode = LaunchMode.SingleTop)] +[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable }, + DataScheme = "com.nitload.charac", DataHost = "oauth")] public sealed class MainActivity : Activity { private const string TermuxPackage = "com.termux"; private const string TermuxHome = "/data/data/com.termux/files/home"; private const string TermuxBin = "/data/data/com.termux/files/usr/bin"; private const string ResultAction = "com.nitload.charac.TERMUX_CHECK_RESULT"; + private const string AuthUrlExtra = "charac_auth_url"; + private const string CallbackPortExtra = "charac_callback_port"; + private const string CallbackPortPreference = "oidc_callback_port"; private TextView? _status; private bool _cliReady; @@ -28,7 +33,10 @@ public sealed class MainActivity : Activity FindViewById