ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Harbor DB 模式用户登录登出实战指南:从测试用例 1-02 到源码级认证链路解析

Harbor DB 模式用户登录登出实战指南:从测试用例 1-02 到源码级认证链路解析 Harbor DB 模式用户登录登出实战指南从测试用例 1-02 到源码级认证链路解析【免费下载链接】harborAn open source trusted cloud native registry project that stores, signs, and scans content.项目地址: https://gitcode.com/GitHub_Trending/ha/harbor本文以 Harbor 测试用例库中的 1-02-DB-user-log-in-log-out.md 为主体完整还原DB 模式db_auth下非管理员用户登录/登出这一用户管理场景的测试目标、环境要求、操作步骤与验收标准并结合 UI 登录控制器、认证路由层、DB 认证器 等源码讲清从表单提交到密码校验、会话建立的完整底层链路帮助读者既掌握可复现的验收方法又理解 Harbor 本地认证的实现原理。1. 用例定位验证 DB 模式下的登录登出能力该用例出自 tests/testcases/Group1-user-management/ 用户管理测试组属于手工/BAATBAT测试脚本体系中的一环。其Purpose测试目的是验证在用户由 Harbor 本地数据库托管DB 模式时一个非管理员用户能够正常登录并登出。需要注意用例开头的显式提示本用例必须使用非管理员用户执行管理员账号有独立用例覆盖。测试关注的是普通用户的视角——登录后看到的仪表盘dashboard与导航栏应当是非管理员版本不应出现任何管理员选项。用例的 References 指向 Harbor 用户指南Environment 一节明确了三项前提条件下面逐项展开。2. 环境准备与 auth_mode 配置2.1 用例声明的环境要求原用例 Environment 部分列出一个正在运行且可访问的 Harbor 实例Harbor 使用本地数据库做认证即auth_mode设置为db_auth用户数据存储在本地数据库中一台安装了 Docker CLI 的 Linux 主机Docker client用于第 6、7 步的docker login验证。2.2auth_mode在源码中的定义与取值auth_mode不是随意字符串Harbor 对其做了严格元数据定义。在 src/lib/config/metadata/metadatalist.go 中可以看到其配置元数据{Name: common.AUTHMode, Scope: UserScope, Group: BasicGroup, EnvKey: AUTH_MODE, DefaultValue: db_auth, ItemType: AuthModeType{}, Editable: false, Description: The auth mode of current system, such as db_auth, ldap_auth, oidc_auth},从中可以确认三个关键事实对应环境变量为AUTH_MODE通常出现在harbor.yml部署配置中默认值就是db_auth——即使未显式配置系统也回退到本地数据库认证见 src/lib/config/userconfig.goAuthMode()在环境值为空时返回db_auth该配置不可在运行时通过 API 在线编辑Editable: false与认证模式切换属于部署期配置一致。合法取值由 src/lib/config/metadata/type.go 中的AuthModeType.validate限定为取值含义db_auth本地数据库认证本用例使用ldap_authLDAP 目录认证uaa_authUAACloud Foundry认证http_auth外部 HTTP 认证服务oidc_authOIDC 单点登录此外src/lib/config/metadata/metadatalist.go 还定义了PRIMARY_AUTH_MODE默认false用于多认证主模式语义本用例不涉及。2.3 测试基础设施仓库tests/目录下提供了支撑这套用例运行的设施tests/docker-compose.test.yml 用于拉起测试实例、tests/configharbor.py 承载测试参数tests/ci/下的 ui_ut_run.sh、ut_run.sh 等脚本负责 CI 侧的 UI/单元测试执行。tests/testcases/中这些 Markdown 用例则是面向 QA 的 BAT 测试脚本正文。3. 完整测试步骤原用例 7 步完整继承以下 7 步完整继承原用例 Test Steps 一节执行者为一个非管理员用户用用户名username登录 UI非管理员用户在登录页输入用户名登录从 UI 登出用邮箱email登录 UI同一用户改用邮箱作为登录名再次登录从 UI 登出错误凭据登录使用错误的密码配合该用户的用户名或邮箱登录 UI检查错误提示文案Docker 客户端登录在 Docker client 主机上执行docker login harbor_host分别使用用户名和邮箱两种方式登录两种方式都要验证Docker 客户端错误密码登录使用docker login harbor_host以错误的密码、配合用户名或邮箱登录预期失败。其中第 6 步的示例命令# 用户名方式 docker login harbor_host # Username: username # Password: password # 邮箱方式Harbor 允许以邮箱作为 principal 登录 docker login harbor_host # Username: email # Password: password4. 预期结果与验收标准原用例 Expected Outcome 一节给出 5 条验收标准逐条列示步骤预期结果步骤 1 3用户可分别以用户名、邮箱通过 UI 登录登录后确认仪表盘与导航栏为非管理员样式不应看到任何管理员选项步骤 2 4登出后重新显示登录页步骤 5错误提示不得泄露哪个输入项是错误的只应显示用户名(邮箱)与密码组合不正确步骤 6Docker 客户端使用用户名或邮箱均可登录成功步骤 7Docker 客户端使用错误密码登录失败用例 Possible Problems 一节标注为None即该用例没有已知的干扰项或环境陷阱。5. 源码级链路解析登录请求在 Harbor 内部发生了什么以下结合当前仓库源码还原上述 UI/Docker 登录背后的实现链路文件路径均相对仓库根目录。5.1 UI 登录入口CommonController.LoginUI 表单提交由 src/core/controllers/base.go 中的CommonController.Login处理核心逻辑约 30 行func (cc *CommonController) Login() { principal : cc.GetString(principal) password : cc.GetString(password) // OIDC 模式下且该用户为 OIDC 用户时重定向到 OIDC provider 登录页 if redirectForOIDC(cc.Ctx.Request.Context(), principal) { ... } user, err : auth.Login(cc.Context(), models.AuthModel{ Principal: principal, Password: password, }) if err ! nil { log.Errorf(Error occurred in UserLogin: %v, err) cc.CustomAbort(http.StatusUnauthorized, ) } if user nil { cc.CustomAbort(http.StatusUnauthorized, ) } cc.PopulateUserSession(*user) }三个要点登录名参数名是principal与用户名或邮箱均可登录的用例步骤 1/3 对应——服务端并不区分二者交由认证器做模糊匹配见 5.4 节认证失败时CustomAbort(http.StatusUnauthorized, )——响应体为空这正是用例步骤 5错误提示不泄露具体哪个字段错误的服务端依据UI 只能收到 401随后展示统一的用户名(邮箱)或密码不正确文案认证成功后调用cc.PopulateUserSession(*user)建立会话。5.2 认证路由层auth.Login按模式分发src/core/auth/authenticator.go 是各认证模式的统一入口func Login(ctx context.Context, m models.AuthModel) (*models.User, error) { authMode, err : config.AuthMode(ctx) ... if authMode || IsSuperUser(ctx, m.Principal) { authMode common.DBAuth } ... authenticator, ok : registry[authMode] if !ok { return nil, fmt.Errorf(unrecognized auth_mode: %s, authMode) } if lock.IsLocked(m.Principal) { return nil, nil } user, err : authenticator.Authenticate(ctx, m) if err ! nil { if _, ok err.(ErrAuth); ok { log.Warningf(Login failed, locking %s, and sleep for %v, m.Principal, frozenTime) lock.Lock(m.Principal) time.Sleep(frozenTime) } return nil, err } err authenticator.PostAuthenticate(ctx, user) return user, err }值得注意的实现细节注册表机制各认证模式通过auth.Register(name, h)注册进全局registrymapL124-L134Login按当前auth_mode取出对应AuthenticateHelper执行空模式或超级用户回退authMode为空、或登录者恰好是内置超级用户IsSuperUser约定user_id 1时强制走db_auth保证初始管理员在 LDAP/OIDC 环境下仍可登录失败锁定防暴力破解文件顶部定义frozenTime 1500 * time.MillisecondL33密码错误返回ErrAuth类型错误时对该 principal 加锁并延迟 1.5 秒锁实现见 src/core/auth/lock.go被锁期间再次登录直接返回nil, nil上层同样以 401 处理。这对用例步骤 5/7 的快速重试场景有实际影响。5.3 DB 认证器db.Authdb_auth模式的具体实现在 src/core/auth/db/db.gofunc (d *Auth) Authenticate(ctx context.Context, m models.AuthModel) (*models.User, error) { u, err : d.userMgr.MatchLocalPassword(ctx, m.Principal, m.Password) if err ! nil { return nil, err } if u nil { return nil, auth.NewErrAuth(Invalid credentials) } return u, nil } func init() { auth.Register(common.DBAuth, Auth{ userMgr: user.New(), }) }init()把db.Auth注册为db_auth模式的认证器。当用户不存在或密码不匹配时返回auth.NewErrAuth(Invalid credentials)——注意ErrAuth在接口注释中被明确定义为bad credentials用户凭据错误类错误与数据库连接失败等服务端错误区分开见 authenticator.go L67-L84这决定了上层是否触发失败锁定。5.4 用户名或邮箱匹配与密码校验真正的密码比对在 src/pkg/user/manager.go 的MatchLocalPasswordfunc (m *manager) MatchLocalPassword(ctx context.Context, usernameOrEmail, password string) (*commonmodels.User, error) { l, err : m.dao.List(ctx, q.New(q.KeyWords{username_or_email: usernameOrEmail})) ... for _, entry : range l { if utils.Encrypt(password, entry.Salt, entry.PasswordVersion) entry.Password { entry.Password return entry, nil } } return nil, nil }这段代码直接支撑了用例的两条设计username_or_email查询条件DAO 层支持按用户名或邮箱任一定位用户记录因此步骤 1用户名与步骤 3邮箱能走同一入口登录加盐 版本化哈希密码用utils.Encrypt(password, salt, password_version)实现位于 src/common/utils/encrypt.go与库中存储值比对匹配成功前会先将entry.Password置空再返回避免密码哈希随用户对象外泄。5.5 会话建立与登出认证成功后PopulateUserSessionsrc/core/api/base.go负责会话func (b *BaseController) PopulateUserSession(u models.User) { err : b.SessionRegenerateID() // 重新生成 session ID防止会话固定攻击 ... if err : b.SetSession(userSessionKey, u); err ! nil { ... } }即先轮换会话 ID再把用户模型写入 session键为常量userSessionKey userL40。登出则由同文件的CommonController.LogOut处理销毁会话后浏览器回到登录页——对应用例步骤 2/4登出后重新显示登录页的预期。5.6docker login的认证通道步骤 6/7 的docker login harbor_host走的是 Harbor 的 v2 registry API 认证链路。从源码结构看v2 API 的 token 签发服务位于 src/core/service/token/含token.go、creator.go、authutils.gov2.0 HTTP API 路由与 handler 位于 src/server/v2.0/。Docker CLI 在docker login时会向 registry 的 token 端点提交凭据其背后的用户凭据校验与 UI 登录同源同样是db_auth认证器 MatchLocalPassword因此用户名与邮箱在docker login中同样有效——这正是用例要求两种 principal 都验证的原因。6. 执行建议与相邻用例该用例执行时的实操建议先确认实例的认证模式部署配置中auth_mode环境变量AUTH_MODE为db_auth且待测用户已存在于 Harbor 本地数据库准备一个非管理员账号避免与管理员专用用例混淆按第 3 节 7 步顺序执行逐条对照第 4 节验收表打勾若登录连续失败注意 5.2 节所述的 1.5 秒 principal 级锁定短时间内快速重试会出现看似随机的失败间隔 2 秒以上重试更稳定。同一测试组内与该用例强相关的相邻用例均位于 tests/testcases/Group1-user-management/1-01-DB-user-registration.mdDB 模式用户注册1-03-DB-user-update-password.md修改密码后再验证登录可与本用例组合覆盖改密后凭据生效1-07-LDAP-mode-general.md切换为ldap_auth后的对应用例便于对比两种认证模式的行为差异1-09-admin-create-delete-user.md 等管理员侧用例覆盖管理员账号的登录路径。7. 小结本用例围绕db_auth模式下普通用户的登录/登出正确性用 7 个步骤覆盖了三个关键维度用户名与邮箱双 principal 登录、错误凭据的模糊化报错、UI 与 Docker 客户端两条认证通道的一致性。结合源码可以看到这些验收标准背后都有明确的实现支撑username_or_email查询条件src/pkg/user/manager.go、空响应体的 401src/core/controllers/base.go、db_auth认证器注册与ErrAuth语义src/core/auth/db/db.go以及 1.5 秒失败锁定带来的暴力破解防护src/core/auth/authenticator.go。理解这条链路后无论是执行该用例、排查登录问题还是扩展 Harbor 的认证模式都有了源码级的抓手。【免费下载链接】harborAn open source trusted cloud native registry project that stores, signs, and scans content.项目地址: https://gitcode.com/GitHub_Trending/ha/harbor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表