fix: stabilize console scrolling and protect administrator login
This commit is contained in:
@@ -25,10 +25,20 @@ const (
|
||||
// ConsoleAuthStore 管理控制台的人类账号和 HttpOnly 会话。
|
||||
// 账号绑定一个已有的 Orbit 业务凭据,登录后沿用该凭据的权限范围;
|
||||
// 因此控制台登录不会改变 SDK 令牌,也不会绕过原有的 API 授权。
|
||||
type ConsoleAuthStore struct{ db *sql.DB }
|
||||
type ConsoleAuthStore struct {
|
||||
db *sql.DB
|
||||
policy consoleauth.LoginPolicy
|
||||
}
|
||||
|
||||
// NewConsoleAuthStore 创建控制台认证存储。
|
||||
func NewConsoleAuthStore(db *sql.DB) *ConsoleAuthStore { return &ConsoleAuthStore{db: db} }
|
||||
func NewConsoleAuthStore(db *sql.DB, policies ...consoleauth.LoginPolicy) *ConsoleAuthStore {
|
||||
policy := consoleauth.DefaultLoginPolicy()
|
||||
if len(policies) > 0 {
|
||||
policy = policies[0]
|
||||
}
|
||||
return &ConsoleAuthStore{db: db, policy: policy}
|
||||
}
|
||||
func (s *ConsoleAuthStore) LoginPolicy() consoleauth.LoginPolicy { return s.policy }
|
||||
|
||||
var _ consoleauth.Store = (*ConsoleAuthStore)(nil)
|
||||
|
||||
@@ -108,59 +118,6 @@ func (s *ConsoleAuthStore) CreateConsoleUser(ctx context.Context, in ConsoleUser
|
||||
return ConsoleUser{ID: string(id), Username: in.Username, DisplayName: name}, nil
|
||||
}
|
||||
|
||||
// Login 校验账号密码并建立一个独立会话。失败时统一返回未认证,避免泄露账号存在性。
|
||||
func (s *ConsoleAuthStore) Login(ctx context.Context, username, password, userAgent, remoteAddr string) (ConsoleLogin, error) {
|
||||
if s == nil || s.db == nil || username == "" || password == "" || len(password) > 1024 {
|
||||
return ConsoleLogin{}, fault.Unauthorized
|
||||
}
|
||||
var user ConsoleUser
|
||||
var userID core.ID
|
||||
var namespace, credential core.ID
|
||||
var hash string
|
||||
var enabled bool
|
||||
err := s.db.QueryRowContext(ctx, `SELECT u.id,u.username,u.display_name,u.password_hash,u.enabled,u.namespace_id,u.credential_id
|
||||
FROM orbit_console_users u
|
||||
JOIN orbit_credentials c ON c.namespace_id=u.namespace_id AND c.id=u.credential_id
|
||||
JOIN orbit_namespaces n ON n.id=u.namespace_id
|
||||
JOIN orbit_applications a ON a.id=n.application_id
|
||||
WHERE u.username=? AND c.revoked_at IS NULL
|
||||
AND (c.expires_at IS NULL OR c.expires_at>UTC_TIMESTAMP(6))
|
||||
AND n.enabled=TRUE AND a.enabled=TRUE`, username).
|
||||
Scan(&userID, &user.Username, &user.DisplayName, &hash, &enabled, &namespace, &credential)
|
||||
if err != nil || !enabled || bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) != nil {
|
||||
return ConsoleLogin{}, fault.Unauthorized
|
||||
}
|
||||
user.ID = string(userID)
|
||||
token, secretDigest, err := auth.Issue(namespace, credential)
|
||||
if err != nil {
|
||||
return ConsoleLogin{}, err
|
||||
}
|
||||
var now time.Time
|
||||
if err := s.db.QueryRowContext(ctx, "SELECT UTC_TIMESTAMP(6)").Scan(&now); err != nil {
|
||||
return ConsoleLogin{}, err
|
||||
}
|
||||
now = now.UTC()
|
||||
expires := now.Add(ConsoleSessionLifetime)
|
||||
sessionID, err := core.NewID()
|
||||
if err != nil {
|
||||
return ConsoleLogin{}, err
|
||||
}
|
||||
if len(userAgent) > 512 {
|
||||
userAgent = userAgent[:512]
|
||||
}
|
||||
if len(remoteAddr) > 64 {
|
||||
remoteAddr = remoteAddr[:64]
|
||||
}
|
||||
_, err = s.db.ExecContext(ctx, `INSERT INTO orbit_console_sessions
|
||||
(id,user_id,namespace_id,credential_id,token_digest,expires_at,last_seen_at,user_agent,remote_addr)
|
||||
VALUES (?,?,?,?,?,?,UTC_TIMESTAMP(6),?,?)`,
|
||||
sessionID, userID, namespace, credential, secretDigest, expires, userAgent, remoteAddr)
|
||||
if err != nil {
|
||||
return ConsoleLogin{}, err
|
||||
}
|
||||
return ConsoleLogin{User: user, Token: token, ExpiresAt: expires}, nil
|
||||
}
|
||||
|
||||
// ValidateSession 检查会话是否仍然有效,并更新最近使用时间。
|
||||
// API 授权还会再次读取该会话对应凭据的权限,不信任浏览器提交的身份字段。
|
||||
func (s *ConsoleAuthStore) ValidateSession(ctx context.Context, token auth.Token) error {
|
||||
|
||||
Reference in New Issue
Block a user