Индикатор «Шлюз НРД», проверка ключа ИШ, папки шлюза по сети, сотрудники из домена, переключатель QUIK в настройках

- журнал ИШ: номер процесса выравнивается пробелами — опросы НРД не распознавались (серый индикатор)
- «Проверить СКЗИ и ключ»: Валидата, датчик случайных чисел, подпись профилем ИШ (а не старый bj-crypto);
  индикатор «Криптографии» — по готовности ключа; карточка автозагрузки УЦ — только для разработки
- шаг «Шлюз НРД»: папки обмена по сети (Samba): логин/пароль, ручная настройка не трогается
- «Учётные записи»: необязательно — подключить домен, проверить связь, найти сотрудника и добавить с ролью;
  роль из bj действует, пока группы домена с ролями не сопоставлены
- настройка QUIK МНП: «Только чтение / Чтение и запись», тонкая настройка цикла свёрнута
- индикатор «Обновления» — только когда есть что обновить; «Мастер настройки» в меню и в настройках

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
zuevav
2026-10-07 00:24:19 +03:00
parent 6a48f7e7a4
commit afc5776347
17 changed files with 421 additions and 55 deletions
+18 -4
View File
@@ -20,6 +20,7 @@ import (
"crypto/x509"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"html"
"html/template"
@@ -179,7 +180,10 @@ type User struct {
CreatedAt time.Time `json:"created_at"`
LastLogin time.Time `json:"last_login,omitempty"`
ADGroups []string `json:"ad_groups,omitempty"`
Note string `json:"note,omitempty"`
// BJRole — роль доменного пользователя, назначенная в bj (мастер, «Добавить из домена»): действует, когда
// ни одна группа домена не сопоставлена с ролью; сопоставленные группы — главнее.
BJRole string `json:"bj_role,omitempty"`
Note string `json:"note,omitempty"`
}
func (u *User) Can(perm string) bool {
@@ -785,9 +789,6 @@ func authenticate(rc *RuntimeConfig, login, password string) (*User, error) {
return nil, fmt.Errorf("неверный логин или пароль")
}
res, err := adAuthenticate(a, login, password)
if err != nil {
return nil, err
}
key := login
if i := strings.Index(key, "@"); i > 0 {
key = key[:i]
@@ -795,6 +796,15 @@ func authenticate(rc *RuntimeConfig, login, password string) (*User, error) {
if i := strings.Index(key, `\`); i > 0 {
key = key[i+1:]
}
var noGroup *adNoGroupError
if err != nil && res != nil && errors.As(err, &noGroup) {
if pre := globalUsers.Get(key); pre != nil && pre.Source == "ad" && pre.BJRole != "" && roleAvailable(pre.BJRole) {
res.Role, res.MatchedBy, err = pre.BJRole, "роль, назначенная в bj", nil
}
}
if err != nil {
return nil, err
}
if u = globalUsers.Get(key); u == nil {
u = &User{Login: key, Source: "ad", Active: true, CreatedAt: time.Now(), Role: res.Role}
} else if !u.Active {
@@ -1280,6 +1290,9 @@ func (h *setupHandlers) saveUser(w http.ResponseWriter, r *http.Request) {
if src := r.FormValue("source"); src == "ad" || src == "local" {
u.Source = src
}
if u.Source == "ad" {
u.BJRole = role // роль из bj — пока ни одна группа домена не сопоставлена
}
pw := r.FormValue("password")
if u.Source == "local" {
if pw != "" {
@@ -1445,6 +1458,7 @@ func (h *setupHandlers) testAD(w http.ResponseWriter, r *http.Request) {
func registerUsersSetup(mux *http.ServeMux, h *setupHandlers) {
mux.HandleFunc("/admin/setup/users", h.saveUser)
h.registerADWizard(mux)
mux.HandleFunc("/admin/setup/users/delete", h.deleteUser)
mux.HandleFunc("/admin/setup/users/session-drop", h.dropSession)
mux.HandleFunc("/admin/setup/auth", h.saveAuth)