73b246831c
- Безопасность: в мастере подпись к паролю выводила сам сохранённый пароль служебной записи домена — теперь только «задан/введён» (тест: пароль не попадает в HTML). Список сессий в настройках больше не содержит токены (по ним можно было войти под чужим именем) — короткий ID. - Домен: после подключения и «Доверять» блок остаётся открытым, страница возвращается к нему; карточка «Домен подключён» и «Найден домен» — крупно; поиск сотрудников и групп; группе — доступ с ролью (ADGroups), список групп с «убрать». - «Обмен с DEPO»: справочник FTV_M2M_HANDBOOK считается и когда переводов ещё нет (на свежей установке писало «не создана»). - Модуль 1С: onec-back «1С: база бэк-офиса (тест)» вместо мидл-офиса (в лицензиях не выдавался). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
115 lines
4.7 KiB
Go
115 lines
4.7 KiB
Go
package lkgateway
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestADDNToDomain(t *testing.T) {
|
|
if got := adDNToDomain("DC=corp,DC=fontvielle,DC=ru"); got != "corp.fontvielle.ru" {
|
|
t.Fatal(got)
|
|
}
|
|
if v := adVariants("dc1.corp.local"); len(v) != 2 || v[0].url != "ldaps://dc1.corp.local" || !v[1].startTLS {
|
|
t.Fatalf("%+v", v)
|
|
}
|
|
if v := adVariants("ldaps://dc1:636"); len(v) != 1 || v[0].startTLS {
|
|
t.Fatalf("%+v", v)
|
|
}
|
|
}
|
|
|
|
func TestADExplain(t *testing.T) {
|
|
a := AuthSettings{ADServer: "ldaps://10.10.10.6", ADDomain: "corp.local"}
|
|
for _, c := range []struct{ err, want string }{
|
|
{"x509: cannot validate certificate for 10.10.10.6 because it doesn't contain any IP SANs", "укажите имя контроллера"},
|
|
{"x509: certificate is valid for dc1.corp.local, not dc9", "dc1.corp.local"},
|
|
{"dial tcp 10.10.10.6:636: connect: connection refused", "порту 636"},
|
|
{"dial tcp: lookup dc9.corp.local: no such host", "не находится в DNS"},
|
|
} {
|
|
if got := adExplain(errors.New(c.err), a, nil); !strings.Contains(got, c.want) {
|
|
t.Errorf("%s → %s", c.err, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Контроллер с сертификатом неизвестного центра: введённое не теряется, «Доверять» запоминает сертификат,
|
|
// прежние настройки входа не портятся.
|
|
func TestADConnectKeepsDraftAndTrust(t *testing.T) {
|
|
adDraftClear()
|
|
defer adDraftClear()
|
|
dc := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
|
|
defer dc.Close()
|
|
srv := "ldaps://" + strings.TrimPrefix(dc.URL, "https://")
|
|
rc := testRC(t)
|
|
h := &setupHandlers{rc: rc}
|
|
post := func(path string, v url.Values) string {
|
|
w := httptest.NewRecorder()
|
|
r := httptest.NewRequest(http.MethodPost, path, strings.NewReader(v.Encode()))
|
|
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
switch path {
|
|
case "/admin/setup/users/ad-connect":
|
|
h.adConnect(w, r)
|
|
default:
|
|
h.adTrust(w, r)
|
|
}
|
|
loc, _ := url.QueryUnescape(w.Header().Get("Location"))
|
|
return loc
|
|
}
|
|
loc := post("/admin/setup/users/ad-connect", url.Values{"ad_bind_user": {"svc-bj"}, "ad_bind_password": {"pw1"}, "ad_domain": {"corp.test"}, "ad_server": {srv}})
|
|
if !strings.Contains(loc, "центром сертификации") {
|
|
t.Fatalf("нет понятной причины: %s", loc)
|
|
}
|
|
d := adDraftForView()
|
|
if d == nil || d.Cert == nil || d.BindUser != "svc-bj" || !d.HasPassword || d.Form.Server != srv || d.Form.Domain != "corp.test" {
|
|
t.Fatalf("черновик: %+v", d)
|
|
}
|
|
if rc.Snapshot().Auth.ADEnabled || rc.Snapshot().Auth.ADServer != "" {
|
|
t.Fatal("неудачная попытка изменила настройки входа")
|
|
}
|
|
// повтор без пароля — пароль берётся из черновика
|
|
post("/admin/setup/users/ad-connect", url.Values{"ad_bind_user": {"svc-bj"}, "ad_domain": {"corp.test"}, "ad_server": {srv}})
|
|
if a := adDraftAuth(); a == nil || a.ADBindPassword != "pw1" {
|
|
t.Fatal("пароль из черновика потерян")
|
|
}
|
|
// чужой отпечаток не принимается
|
|
if loc := post("/admin/setup/users/ad-trust", url.Values{"fp": {"00:11"}}); !strings.Contains(loc, "устарел") {
|
|
t.Fatalf("чужой отпечаток: %s", loc)
|
|
}
|
|
fp := adDraftForView().Cert.SHA256
|
|
loc = post("/admin/setup/users/ad-trust", url.Values{"fp": {fp}})
|
|
if strings.Contains(loc, "центром сертификации") {
|
|
t.Fatalf("после «Доверять» TLS всё ещё не проходит: %s", loc)
|
|
}
|
|
if a := adDraftAuth(); a == nil || a.ADCAPEM == "" {
|
|
t.Fatal("сертификат не запомнен в черновике")
|
|
}
|
|
}
|
|
|
|
// Группа домена из мастера: доступ с ролью, повтор меняет роль (без дублей), «убрать» — снимает.
|
|
func TestADGroupSave(t *testing.T) {
|
|
rc := testRC(t)
|
|
h := &setupHandlers{rc: rc}
|
|
post := func(v url.Values) {
|
|
w := httptest.NewRecorder()
|
|
r := httptest.NewRequest(http.MethodPost, "/admin/setup/users/ad-group", strings.NewReader(v.Encode()))
|
|
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
h.adGroupSave(w, r)
|
|
}
|
|
post(url.Values{"group": {"Depo"}, "role": {"operator"}})
|
|
post(url.Values{"group": {"depo"}, "role": {"viewer"}})
|
|
g := rc.Snapshot().Auth.ADGroups
|
|
if len(g) != 1 || g[0].Role != "viewer" {
|
|
t.Fatalf("группы: %+v", g)
|
|
}
|
|
if adGroupRoleOf(rc.Snapshot().Auth, "DEPO") != "viewer" {
|
|
t.Fatal("роль группы не находится")
|
|
}
|
|
post(url.Values{"group": {"Depo"}, "remove": {"1"}})
|
|
if len(rc.Snapshot().Auth.ADGroups) != 0 {
|
|
t.Fatal("группа не убрана")
|
|
}
|
|
}
|