846 lines
24 KiB
Go
846 lines
24 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
type milestoneRoleResponse struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
DisplayName string `json:"displayName"`
|
|
Description string `json:"description"`
|
|
Users []milestoneRoleUserItem `json:"users,omitempty"`
|
|
UserCount int `json:"userCount"`
|
|
CanEdit bool `json:"canEdit"`
|
|
CanDelete bool `json:"canDelete"`
|
|
}
|
|
|
|
type milestoneRoleUserItem struct {
|
|
ID string `json:"id"`
|
|
DisplayName string `json:"displayName"`
|
|
Name string `json:"name"`
|
|
UserName string `json:"userName"`
|
|
Username string `json:"username"`
|
|
Email string `json:"email"`
|
|
Domain string `json:"domain"`
|
|
SID string `json:"sid"`
|
|
DistinguishedName string `json:"distinguishedName"`
|
|
Source string `json:"source"`
|
|
}
|
|
|
|
type saveMilestoneRoleRequest struct {
|
|
Name string `json:"name"`
|
|
DisplayName string `json:"displayName"`
|
|
Description string `json:"description"`
|
|
}
|
|
|
|
type addMilestoneRoleUsersRequest struct {
|
|
Users []milestoneRoleUserInput `json:"users"`
|
|
}
|
|
|
|
type milestoneRoleUserInput struct {
|
|
ID string `json:"id"`
|
|
DisplayName string `json:"displayName"`
|
|
Username string `json:"username"`
|
|
UserName string `json:"userName"`
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
Domain string `json:"domain"`
|
|
DistinguishedName string `json:"distinguishedName"`
|
|
SID string `json:"sid"`
|
|
Source string `json:"source"`
|
|
}
|
|
|
|
func (s *Server) handleAdminListMilestoneRoles(w http.ResponseWriter, r *http.Request) {
|
|
currentUser, _ := userFromContext(r.Context())
|
|
isAdministrator := userHasRight(currentUser, "admin")
|
|
|
|
config, err := s.getMilestoneRuntimeConfig(r.Context())
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Konfiguration konnte nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
roles, err := listOperationMilestoneRoles(r.Context(), config)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rollen konnten nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
responseRoles := make([]milestoneRoleResponse, 0, len(roles))
|
|
for _, role := range roles {
|
|
if milestoneRoleIsAdministrators(role) && !isAdministrator {
|
|
continue
|
|
}
|
|
|
|
responseRole := milestoneRoleResponseFromRole(role, nil)
|
|
responseRoles = append(responseRoles, responseRole)
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"roles": responseRoles,
|
|
})
|
|
}
|
|
|
|
func (s *Server) handleAdminGetMilestoneRole(w http.ResponseWriter, r *http.Request) {
|
|
roleID := strings.TrimSpace(r.PathValue("id"))
|
|
if roleID == "" {
|
|
writeError(w, http.StatusBadRequest, "Rollen-ID fehlt")
|
|
return
|
|
}
|
|
currentUser, _ := userFromContext(r.Context())
|
|
isAdministrator := userHasRight(currentUser, "admin")
|
|
|
|
config, err := s.getMilestoneRuntimeConfig(r.Context())
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Konfiguration konnte nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
role, err := getOperationMilestoneRole(r.Context(), config, roleID)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle konnte nicht geladen werden")
|
|
return
|
|
}
|
|
if milestoneRoleIsAdministrators(*role) && !isAdministrator {
|
|
writeError(w, http.StatusNotFound, "Milestone-Rolle wurde nicht gefunden")
|
|
return
|
|
}
|
|
|
|
users, err := listOperationMilestoneRoleUsers(r.Context(), config, roleID)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rollenbenutzer konnten nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"role": milestoneRoleResponseFromRole(*role, users),
|
|
})
|
|
}
|
|
|
|
func (s *Server) handleAdminCreateMilestoneRole(w http.ResponseWriter, r *http.Request) {
|
|
var input saveMilestoneRoleRequest
|
|
if err := readJSON(r, &input); err != nil {
|
|
writeError(w, http.StatusBadRequest, "Invalid JSON")
|
|
return
|
|
}
|
|
|
|
roleName := strings.TrimSpace(input.Name)
|
|
if roleName == "" {
|
|
roleName = strings.TrimSpace(input.DisplayName)
|
|
}
|
|
if roleName == "" {
|
|
writeError(w, http.StatusBadRequest, "Rollenname ist erforderlich")
|
|
return
|
|
}
|
|
|
|
config, err := s.getMilestoneRuntimeConfig(r.Context())
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Konfiguration konnte nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
existingRole, err := findOperationMilestoneRoleByName(r.Context(), config, roleName)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rollen konnten nicht geprüft werden")
|
|
return
|
|
}
|
|
if existingRole != nil {
|
|
writeError(w, http.StatusConflict, "Eine Rolle mit diesem Namen existiert bereits")
|
|
return
|
|
}
|
|
|
|
payload := map[string]any{
|
|
"name": roleName,
|
|
"displayName": strings.TrimSpace(input.DisplayName),
|
|
"description": strings.TrimSpace(input.Description),
|
|
}
|
|
if strings.TrimSpace(input.DisplayName) == "" {
|
|
payload["displayName"] = roleName
|
|
}
|
|
|
|
body, _, err := operationMilestoneRequestJSON(
|
|
r.Context(),
|
|
config,
|
|
http.MethodPost,
|
|
"/API/rest/v1/roles",
|
|
payload,
|
|
)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle konnte nicht angelegt werden")
|
|
return
|
|
}
|
|
|
|
role := operationMilestoneRoleFromItem(decodeOperationMilestoneObject(body))
|
|
if role.ID == "" {
|
|
roleFromList, err := findOperationMilestoneRoleByName(r.Context(), config, roleName)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle wurde angelegt, konnte aber nicht geladen werden")
|
|
return
|
|
}
|
|
if roleFromList == nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone hat keine Rollen-ID zurückgegeben")
|
|
return
|
|
}
|
|
role = *roleFromList
|
|
}
|
|
|
|
roleDetail, err := getOperationMilestoneRole(r.Context(), config, role.ID)
|
|
if err == nil && roleDetail != nil {
|
|
role = *roleDetail
|
|
}
|
|
|
|
writeJSON(w, http.StatusCreated, map[string]any{
|
|
"role": milestoneRoleResponseFromRole(role, nil),
|
|
})
|
|
}
|
|
|
|
func (s *Server) handleAdminUpdateMilestoneRole(w http.ResponseWriter, r *http.Request) {
|
|
roleID := strings.TrimSpace(r.PathValue("id"))
|
|
if roleID == "" {
|
|
writeError(w, http.StatusBadRequest, "Rollen-ID fehlt")
|
|
return
|
|
}
|
|
currentUser, _ := userFromContext(r.Context())
|
|
isAdministrator := userHasRight(currentUser, "admin")
|
|
|
|
var input saveMilestoneRoleRequest
|
|
if err := readJSON(r, &input); err != nil {
|
|
writeError(w, http.StatusBadRequest, "Invalid JSON")
|
|
return
|
|
}
|
|
|
|
roleName := strings.TrimSpace(input.Name)
|
|
if roleName == "" {
|
|
roleName = strings.TrimSpace(input.DisplayName)
|
|
}
|
|
if roleName == "" {
|
|
writeError(w, http.StatusBadRequest, "Rollenname ist erforderlich")
|
|
return
|
|
}
|
|
|
|
config, err := s.getMilestoneRuntimeConfig(r.Context())
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Konfiguration konnte nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
role, err := getOperationMilestoneRole(r.Context(), config, roleID)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle konnte nicht geladen werden")
|
|
return
|
|
}
|
|
if milestoneRoleIsAdministrators(*role) && !isAdministrator {
|
|
writeError(w, http.StatusNotFound, "Milestone-Rolle wurde nicht gefunden")
|
|
return
|
|
}
|
|
|
|
users, err := listOperationMilestoneRoleUsers(r.Context(), config, roleID)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rollenbenutzer konnten nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
role.Name = roleName
|
|
role.DisplayName = strings.TrimSpace(input.DisplayName)
|
|
if role.DisplayName == "" {
|
|
role.DisplayName = roleName
|
|
}
|
|
if role.Data == nil {
|
|
role.Data = map[string]any{}
|
|
}
|
|
role.Data["name"] = roleName
|
|
role.Data["displayName"] = role.DisplayName
|
|
role.Data["description"] = strings.TrimSpace(input.Description)
|
|
|
|
if err := putOperationMilestoneRole(r.Context(), config, *role, users); err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle konnte nicht gespeichert werden")
|
|
return
|
|
}
|
|
|
|
role, err = getOperationMilestoneRole(r.Context(), config, roleID)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle wurde gespeichert, konnte aber nicht geladen werden")
|
|
return
|
|
}
|
|
users, _ = listOperationMilestoneRoleUsers(r.Context(), config, roleID)
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"role": milestoneRoleResponseFromRole(*role, users),
|
|
})
|
|
}
|
|
|
|
func (s *Server) handleAdminDeleteMilestoneRole(w http.ResponseWriter, r *http.Request) {
|
|
roleID := strings.TrimSpace(r.PathValue("id"))
|
|
if roleID == "" {
|
|
writeError(w, http.StatusBadRequest, "Rollen-ID fehlt")
|
|
return
|
|
}
|
|
|
|
config, err := s.getMilestoneRuntimeConfig(r.Context())
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Konfiguration konnte nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
role, err := getOperationMilestoneRole(r.Context(), config, roleID)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle konnte nicht geladen werden")
|
|
return
|
|
}
|
|
if milestoneRoleIsAdministrators(*role) {
|
|
writeError(w, http.StatusForbidden, "Die Rolle Administrators darf nicht gelöscht werden")
|
|
return
|
|
}
|
|
|
|
_, _, err = operationMilestoneRequestJSON(
|
|
r.Context(),
|
|
config,
|
|
http.MethodDelete,
|
|
"/API/rest/v1/roles/"+url.PathEscape(roleID),
|
|
nil,
|
|
)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle konnte nicht gelöscht werden")
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{"ok": true})
|
|
}
|
|
|
|
func (s *Server) handleAdminAddMilestoneRoleUsers(w http.ResponseWriter, r *http.Request) {
|
|
roleID := strings.TrimSpace(r.PathValue("id"))
|
|
if roleID == "" {
|
|
writeError(w, http.StatusBadRequest, "Rollen-ID fehlt")
|
|
return
|
|
}
|
|
currentUser, _ := userFromContext(r.Context())
|
|
isAdministrator := userHasRight(currentUser, "admin")
|
|
|
|
var input addMilestoneRoleUsersRequest
|
|
if err := readJSON(r, &input); err != nil {
|
|
writeError(w, http.StatusBadRequest, "Invalid JSON")
|
|
return
|
|
}
|
|
if len(input.Users) == 0 {
|
|
writeError(w, http.StatusBadRequest, "Keine Benutzer ausgewählt")
|
|
return
|
|
}
|
|
|
|
config, err := s.getMilestoneRuntimeConfig(r.Context())
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Konfiguration konnte nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
role, users, err := getMilestoneAdminRoleWithUsers(r.Context(), config, roleID)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle konnte nicht geladen werden")
|
|
return
|
|
}
|
|
if milestoneRoleIsAdministrators(*role) && !isAdministrator {
|
|
writeError(w, http.StatusNotFound, "Milestone-Rolle wurde nicht gefunden")
|
|
return
|
|
}
|
|
|
|
nextUsers := users
|
|
for _, userInput := range input.Users {
|
|
user := milestoneRoleUserReferenceFromInput(userInput)
|
|
if milestoneItemID(user) == "" || milestoneRoleUserItemIsHidden(milestoneRoleUserItemFromObject(user)) {
|
|
continue
|
|
}
|
|
nextUsers = appendOperationMilestoneObjectByID(nextUsers, user)
|
|
}
|
|
if len(nextUsers) == len(users) {
|
|
writeError(w, http.StatusBadRequest, "Kein gültiger AD-Benutzer ausgewählt")
|
|
return
|
|
}
|
|
|
|
if err := putOperationMilestoneRole(r.Context(), config, *role, nextUsers); err != nil {
|
|
writeError(w, http.StatusBadGateway, "AD-Benutzer konnten der Milestone-Rolle nicht hinzugefügt werden")
|
|
return
|
|
}
|
|
|
|
role, users, err = getMilestoneAdminRoleWithUsers(r.Context(), config, roleID)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle wurde gespeichert, konnte aber nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"role": milestoneRoleResponseFromRole(*role, users),
|
|
})
|
|
}
|
|
|
|
func (s *Server) handleAdminRemoveMilestoneRoleUser(w http.ResponseWriter, r *http.Request) {
|
|
roleID := strings.TrimSpace(r.PathValue("id"))
|
|
userID := strings.TrimSpace(r.PathValue("userId"))
|
|
if roleID == "" || userID == "" {
|
|
writeError(w, http.StatusBadRequest, "Rollen-ID oder Benutzer-ID fehlt")
|
|
return
|
|
}
|
|
currentUser, _ := userFromContext(r.Context())
|
|
isAdministrator := userHasRight(currentUser, "admin")
|
|
|
|
config, err := s.getMilestoneRuntimeConfig(r.Context())
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Konfiguration konnte nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
role, users, err := getMilestoneAdminRoleWithUsers(r.Context(), config, roleID)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle konnte nicht geladen werden")
|
|
return
|
|
}
|
|
if milestoneRoleIsAdministrators(*role) && !isAdministrator {
|
|
writeError(w, http.StatusNotFound, "Milestone-Rolle wurde nicht gefunden")
|
|
return
|
|
}
|
|
|
|
nextUsers := make([]map[string]any, 0, len(users))
|
|
for _, user := range users {
|
|
if strings.EqualFold(milestoneItemID(user), userID) {
|
|
if milestoneRoleUserItemIsHidden(milestoneRoleUserItemFromObject(user)) {
|
|
writeError(w, http.StatusForbidden, "Dieser Benutzer darf nicht entfernt werden")
|
|
return
|
|
}
|
|
continue
|
|
}
|
|
nextUsers = append(nextUsers, user)
|
|
}
|
|
if len(nextUsers) == len(users) {
|
|
writeError(w, http.StatusNotFound, "Benutzer wurde in der Rolle nicht gefunden")
|
|
return
|
|
}
|
|
|
|
if err := putOperationMilestoneRole(r.Context(), config, *role, nextUsers); err != nil {
|
|
writeError(w, http.StatusBadGateway, "Benutzer konnte nicht aus der Milestone-Rolle entfernt werden")
|
|
return
|
|
}
|
|
|
|
role, users, err = getMilestoneAdminRoleWithUsers(r.Context(), config, roleID)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Rolle wurde gespeichert, konnte aber nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"role": milestoneRoleResponseFromRole(*role, users),
|
|
})
|
|
}
|
|
|
|
func (s *Server) handleAdminListActiveDirectoryUsers(w http.ResponseWriter, r *http.Request) {
|
|
credentials, err := s.getActiveDirectoryCredentials(r.Context())
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"configured": false,
|
|
"users": []activeDirectoryUser{},
|
|
})
|
|
return
|
|
}
|
|
if err != nil {
|
|
writeError(w, http.StatusInternalServerError, "AD-Einstellungen konnten nicht geladen werden")
|
|
return
|
|
}
|
|
if !credentials.Configured() {
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"configured": false,
|
|
"users": []activeDirectoryUser{},
|
|
})
|
|
return
|
|
}
|
|
|
|
users, err := listActiveDirectoryUsers(r.Context(), credentials)
|
|
if err != nil {
|
|
logError("AD-Benutzer konnten nicht geladen werden", err, LogFields{
|
|
"baseDn": credentials.BaseDN,
|
|
})
|
|
writeError(w, http.StatusBadGateway, "AD-Benutzer konnten nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"configured": true,
|
|
"baseDn": credentials.BaseDN,
|
|
"users": users,
|
|
})
|
|
}
|
|
|
|
func (s *Server) handleAdminListMilestoneBasicUsers(w http.ResponseWriter, r *http.Request) {
|
|
config, err := s.getMilestoneRuntimeConfig(r.Context())
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Konfiguration konnte nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
items, err := listOperationMilestoneObjectsAtPath(r.Context(), config, "/API/rest/v1/basicUsers")
|
|
if err != nil {
|
|
writeError(w, http.StatusBadGateway, "Milestone-Basisbenutzer konnten nicht geladen werden")
|
|
return
|
|
}
|
|
|
|
users := make([]milestoneRoleUserItem, 0, len(items))
|
|
for _, item := range items {
|
|
user := milestoneRoleUserItemFromObject(item)
|
|
if user.ID == "" || milestoneRoleUserItemIsHidden(user) {
|
|
continue
|
|
}
|
|
user.Source = "basic"
|
|
if user.Domain == "" {
|
|
user.Domain = "Basic"
|
|
}
|
|
users = append(users, user)
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"users": users,
|
|
})
|
|
}
|
|
|
|
func getMilestoneAdminRoleWithUsers(
|
|
ctx context.Context,
|
|
config milestoneRuntimeConfig,
|
|
roleID string,
|
|
) (*operationMilestoneRole, []map[string]any, error) {
|
|
role, err := getOperationMilestoneRole(ctx, config, roleID)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
users, err := listOperationMilestoneRoleUsers(ctx, config, roleID)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return role, users, nil
|
|
}
|
|
|
|
func milestoneRoleResponseFromRole(
|
|
role operationMilestoneRole,
|
|
users []map[string]any,
|
|
) milestoneRoleResponse {
|
|
roleData := role.Data
|
|
if roleData == nil {
|
|
roleData = map[string]any{}
|
|
}
|
|
|
|
if users == nil {
|
|
users = operationMilestoneObjectListFromValue(roleData["users"])
|
|
}
|
|
|
|
responseUsers := make([]milestoneRoleUserItem, 0, len(users))
|
|
for _, user := range users {
|
|
if item := milestoneRoleUserItemFromObject(user); item.ID != "" {
|
|
if milestoneRoleUserItemIsHidden(item) {
|
|
continue
|
|
}
|
|
responseUsers = append(responseUsers, item)
|
|
}
|
|
}
|
|
canDelete := !milestoneRoleIsAdministrators(role)
|
|
|
|
return milestoneRoleResponse{
|
|
ID: role.ID,
|
|
Name: role.Name,
|
|
DisplayName: operationMilestoneRoleDisplayName(role),
|
|
Description: strings.TrimSpace(milestoneStringValue(roleData["description"])),
|
|
Users: responseUsers,
|
|
UserCount: len(responseUsers),
|
|
CanEdit: true,
|
|
CanDelete: canDelete,
|
|
}
|
|
}
|
|
|
|
func milestoneRoleUserItemFromObject(user map[string]any) milestoneRoleUserItem {
|
|
id := milestoneItemID(user)
|
|
displayName := strings.TrimSpace(operationMilestoneItemDisplayName(user))
|
|
name := strings.TrimSpace(milestoneStringValue(user["name"]))
|
|
userName := strings.TrimSpace(milestoneStringValue(user["userName"]))
|
|
if userName == "" {
|
|
userName = strings.TrimSpace(milestoneStringValue(user["username"]))
|
|
}
|
|
if userName == "" {
|
|
userName = strings.TrimSpace(milestoneStringValue(user["accountName"]))
|
|
}
|
|
if userName == "" {
|
|
userName = strings.TrimSpace(milestoneStringValue(user["loginName"]))
|
|
}
|
|
email := strings.TrimSpace(milestoneStringValue(user["email"]))
|
|
if email == "" {
|
|
email = strings.TrimSpace(milestoneStringValue(user["mail"]))
|
|
}
|
|
sid := strings.TrimSpace(milestoneStringValue(user["sid"]))
|
|
if sid == "" {
|
|
sid = strings.TrimSpace(milestoneStringValue(user["objectSid"]))
|
|
}
|
|
distinguishedName := strings.TrimSpace(milestoneStringValue(user["distinguishedName"]))
|
|
source := milestoneRoleUserSourceFromObject(user)
|
|
domain := milestoneRoleUserDomainFromObject(user)
|
|
|
|
if splitDomain, splitUserName := splitMilestoneDomainUser(userName); splitDomain != "" {
|
|
if domain == "" {
|
|
domain = splitDomain
|
|
}
|
|
userName = splitUserName
|
|
}
|
|
if splitDomain, splitName := splitMilestoneDomainUser(name); splitDomain != "" {
|
|
if domain == "" {
|
|
domain = splitDomain
|
|
}
|
|
name = splitName
|
|
}
|
|
if splitDomain, splitDisplayName := splitMilestoneDomainUser(displayName); splitDomain != "" {
|
|
if domain == "" {
|
|
domain = splitDomain
|
|
}
|
|
if userName == "" {
|
|
userName = splitDisplayName
|
|
}
|
|
displayName = splitDisplayName
|
|
}
|
|
if domain == "" {
|
|
domain = activeDirectoryDomainFromPrincipal(milestoneStringValue(user["userPrincipalName"]))
|
|
}
|
|
if domain == "" && email != "" {
|
|
domain = activeDirectoryDomainFromPrincipal(email)
|
|
}
|
|
if domain == "" && distinguishedName != "" {
|
|
domain = activeDirectoryDomainFromDN(distinguishedName)
|
|
}
|
|
if domain == "" && source == "basic" {
|
|
domain = "Basic"
|
|
}
|
|
|
|
if displayName == "" {
|
|
displayName = userName
|
|
}
|
|
if displayName == "" {
|
|
displayName = name
|
|
}
|
|
if displayName == "" {
|
|
displayName = id
|
|
}
|
|
|
|
return milestoneRoleUserItem{
|
|
ID: id,
|
|
DisplayName: displayName,
|
|
Name: name,
|
|
UserName: userName,
|
|
Username: userName,
|
|
Email: email,
|
|
Domain: domain,
|
|
SID: sid,
|
|
DistinguishedName: distinguishedName,
|
|
Source: source,
|
|
}
|
|
}
|
|
|
|
func milestoneRoleUserReferenceFromInput(input milestoneRoleUserInput) map[string]any {
|
|
userID := strings.TrimSpace(input.ID)
|
|
userSID := strings.TrimSpace(input.SID)
|
|
userDN := strings.TrimSpace(input.DistinguishedName)
|
|
displayName := strings.TrimSpace(input.DisplayName)
|
|
username := strings.TrimSpace(input.Username)
|
|
if username == "" {
|
|
username = strings.TrimSpace(input.UserName)
|
|
}
|
|
name := strings.TrimSpace(input.Name)
|
|
email := strings.TrimSpace(input.Email)
|
|
domain := strings.TrimSpace(input.Domain)
|
|
source := milestoneRoleUserSource(input.Source)
|
|
if source == "" {
|
|
source = "ad"
|
|
}
|
|
|
|
if userID == "" {
|
|
userID = userSID
|
|
}
|
|
if userID == "" {
|
|
userID = userDN
|
|
}
|
|
if userID == "" {
|
|
userID = username
|
|
}
|
|
if displayName == "" {
|
|
displayName = name
|
|
}
|
|
if displayName == "" {
|
|
displayName = username
|
|
}
|
|
if displayName == "" {
|
|
displayName = email
|
|
}
|
|
if displayName == "" {
|
|
displayName = userID
|
|
}
|
|
|
|
user := map[string]any{
|
|
"id": userID,
|
|
"name": displayName,
|
|
"displayName": displayName,
|
|
"userName": username,
|
|
"username": username,
|
|
"email": email,
|
|
"domain": domain,
|
|
"source": source,
|
|
"relations": map[string]any{
|
|
"self": map[string]any{
|
|
"type": milestoneRoleUserRelationType(source),
|
|
"id": userID,
|
|
},
|
|
},
|
|
}
|
|
if userSID != "" {
|
|
user["sid"] = userSID
|
|
user["objectSid"] = userSID
|
|
}
|
|
if userDN != "" {
|
|
user["distinguishedName"] = userDN
|
|
}
|
|
|
|
return user
|
|
}
|
|
|
|
func milestoneRoleUserSourceFromObject(user map[string]any) string {
|
|
source := milestoneRoleUserSource(milestoneStringValue(user["source"]))
|
|
if source != "" {
|
|
return source
|
|
}
|
|
|
|
if relations, ok := user["relations"].(map[string]any); ok {
|
|
if self, ok := relations["self"].(map[string]any); ok {
|
|
relationType := strings.TrimSpace(milestoneStringValue(self["type"]))
|
|
if strings.EqualFold(relationType, "basicUsers") ||
|
|
strings.EqualFold(relationType, "basicUser") {
|
|
return "basic"
|
|
}
|
|
}
|
|
}
|
|
|
|
itemType := strings.TrimSpace(milestoneStringValue(user["type"]))
|
|
if strings.EqualFold(itemType, "basicUsers") ||
|
|
strings.EqualFold(itemType, "basicUser") {
|
|
return "basic"
|
|
}
|
|
|
|
return "ad"
|
|
}
|
|
|
|
func milestoneRoleUserSource(source string) string {
|
|
source = strings.TrimSpace(strings.ToLower(source))
|
|
switch source {
|
|
case "basic", "basicuser", "basicusers":
|
|
return "basic"
|
|
case "ad", "active-directory", "activedirectory", "directory":
|
|
return "ad"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func milestoneRoleUserRelationType(source string) string {
|
|
if milestoneRoleUserSource(source) == "basic" {
|
|
return "basicUsers"
|
|
}
|
|
|
|
return "users"
|
|
}
|
|
|
|
func milestoneRoleUserDomainFromObject(user map[string]any) string {
|
|
for _, key := range []string{
|
|
"domain",
|
|
"domainName",
|
|
"accountDomain",
|
|
"windowsDomain",
|
|
"netbiosDomain",
|
|
"directoryDomain",
|
|
} {
|
|
if value := strings.TrimSpace(milestoneStringValue(user[key])); value != "" {
|
|
return value
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func milestoneRoleIsAdministrators(role operationMilestoneRole) bool {
|
|
for _, value := range []string{role.Name, role.DisplayName, operationMilestoneRoleDisplayName(role)} {
|
|
if normalizeMilestoneRoleProtectionValue(value) == "administrators" {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func milestoneRoleUserItemIsHidden(user milestoneRoleUserItem) bool {
|
|
candidates := []string{
|
|
milestoneProtectedUserQualifiedName(user.Domain, user.Username),
|
|
milestoneProtectedUserQualifiedName(user.Domain, user.UserName),
|
|
milestoneProtectedUserQualifiedName(user.Domain, user.Name),
|
|
milestoneProtectedUserQualifiedName(user.Domain, user.DisplayName),
|
|
}
|
|
|
|
for _, candidate := range candidates {
|
|
if milestoneProtectedUserNameIsHidden(candidate) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func milestoneProtectedUserNameIsHidden(value string) bool {
|
|
value = normalizeMilestoneRoleProtectionValue(value)
|
|
switch value {
|
|
case "nt-autorität\\netzwerkdienst",
|
|
"nt authority\\network service",
|
|
"tegdssd\\tegadmin",
|
|
"vordefiniert\\administratoren",
|
|
"builtin\\administrators",
|
|
"tegdssd\\milestone_administratoren":
|
|
return true
|
|
}
|
|
|
|
domain, account, ok := strings.Cut(value, "\\")
|
|
return ok && domain == "tegdssd" && strings.HasSuffix(account, "$")
|
|
}
|
|
|
|
func milestoneProtectedUserQualifiedName(domain string, account string) string {
|
|
domain = strings.TrimSpace(domain)
|
|
account = strings.TrimSpace(account)
|
|
if account == "" {
|
|
return ""
|
|
}
|
|
if domain == "" {
|
|
return account
|
|
}
|
|
|
|
return domain + "\\" + account
|
|
}
|
|
|
|
func normalizeMilestoneRoleProtectionValue(value string) string {
|
|
return strings.ToLower(strings.Join(strings.Fields(strings.TrimSpace(value)), " "))
|
|
}
|
|
|
|
func splitMilestoneDomainUser(value string) (string, string) {
|
|
value = strings.TrimSpace(value)
|
|
if value == "" {
|
|
return "", ""
|
|
}
|
|
|
|
domain, username, ok := strings.Cut(value, "\\")
|
|
if !ok || strings.TrimSpace(domain) == "" || strings.TrimSpace(username) == "" {
|
|
return "", value
|
|
}
|
|
|
|
return strings.TrimSpace(domain), strings.TrimSpace(username)
|
|
}
|