/* Technitium DNS Server Copyright (C) 2024 Shreyas Zare (shreyas@technitium.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ using DnsServerCore.Auth; using Microsoft.AspNetCore.Http; using System; using System.Collections.Generic; using System.Net; using System.Text.Json; using System.Threading.Tasks; namespace DnsServerCore { sealed class WebServiceAuthApi { #region variables readonly DnsWebService _dnsWebService; #endregion #region constructor public WebServiceAuthApi(DnsWebService dnsWebService) { _dnsWebService = dnsWebService; } #endregion #region private private void WriteCurrentSessionDetails(Utf8JsonWriter jsonWriter, UserSession currentSession, bool includeInfo) { if (currentSession.Type == UserSessionType.ApiToken) { jsonWriter.WriteString("username", currentSession.User.Username); jsonWriter.WriteString("tokenName", currentSession.TokenName); jsonWriter.WriteString("token", currentSession.Token); } else { jsonWriter.WriteString("displayName", currentSession.User.DisplayName); jsonWriter.WriteString("username", currentSession.User.Username); jsonWriter.WriteString("token", currentSession.Token); } if (includeInfo) { jsonWriter.WritePropertyName("info"); jsonWriter.WriteStartObject(); jsonWriter.WriteString("version", _dnsWebService.GetServerVersion()); jsonWriter.WriteString("uptimestamp", _dnsWebService._uptimestamp); jsonWriter.WriteString("dnsServerDomain", _dnsWebService.DnsServer.ServerDomain); jsonWriter.WriteNumber("defaultRecordTtl", _dnsWebService._zonesApi.DefaultRecordTtl); jsonWriter.WriteBoolean("useSoaSerialDateScheme", _dnsWebService.DnsServer.AuthZoneManager.UseSoaSerialDateScheme); jsonWriter.WriteBoolean("dnssecValidation", _dnsWebService.DnsServer.DnssecValidation); jsonWriter.WritePropertyName("permissions"); jsonWriter.WriteStartObject(); for (int i = 1; i <= 11; i++) { PermissionSection section = (PermissionSection)i; jsonWriter.WritePropertyName(section.ToString()); jsonWriter.WriteStartObject(); jsonWriter.WriteBoolean("canView", _dnsWebService._authManager.IsPermitted(section, currentSession.User, PermissionFlag.View)); jsonWriter.WriteBoolean("canModify", _dnsWebService._authManager.IsPermitted(section, currentSession.User, PermissionFlag.Modify)); jsonWriter.WriteBoolean("canDelete", _dnsWebService._authManager.IsPermitted(section, currentSession.User, PermissionFlag.Delete)); jsonWriter.WriteEndObject(); } jsonWriter.WriteEndObject(); jsonWriter.WriteEndObject(); } } private void WriteUserDetails(Utf8JsonWriter jsonWriter, User user, UserSession currentSession, bool includeMoreDetails, bool includeGroups) { jsonWriter.WriteString("displayName", user.DisplayName); jsonWriter.WriteString("username", user.Username); jsonWriter.WriteBoolean("disabled", user.Disabled); jsonWriter.WriteString("previousSessionLoggedOn", user.PreviousSessionLoggedOn); jsonWriter.WriteString("previousSessionRemoteAddress", user.PreviousSessionRemoteAddress.ToString()); jsonWriter.WriteString("recentSessionLoggedOn", user.RecentSessionLoggedOn); jsonWriter.WriteString("recentSessionRemoteAddress", user.RecentSessionRemoteAddress.ToString()); if (includeMoreDetails) { jsonWriter.WriteNumber("sessionTimeoutSeconds", user.SessionTimeoutSeconds); jsonWriter.WritePropertyName("memberOfGroups"); jsonWriter.WriteStartArray(); List memberOfGroups = new List(user.MemberOfGroups); memberOfGroups.Sort(); foreach (Group group in memberOfGroups) { if (group.Name.Equals("Everyone", StringComparison.OrdinalIgnoreCase)) continue; jsonWriter.WriteStringValue(group.Name); } jsonWriter.WriteEndArray(); jsonWriter.WritePropertyName("sessions"); jsonWriter.WriteStartArray(); List sessions = _dnsWebService._authManager.GetSessions(user); sessions.Sort(); foreach (UserSession session in sessions) WriteUserSessionDetails(jsonWriter, session, currentSession); jsonWriter.WriteEndArray(); } if (includeGroups) { List groups = new List(_dnsWebService._authManager.Groups); groups.Sort(); jsonWriter.WritePropertyName("groups"); jsonWriter.WriteStartArray(); foreach (Group group in groups) { if (group.Name.Equals("Everyone", StringComparison.OrdinalIgnoreCase)) continue; jsonWriter.WriteStringValue(group.Name); } jsonWriter.WriteEndArray(); } } private static void WriteUserSessionDetails(Utf8JsonWriter jsonWriter, UserSession session, UserSession currentSession) { jsonWriter.WriteStartObject(); jsonWriter.WriteString("username", session.User.Username); jsonWriter.WriteBoolean("isCurrentSession", session.Equals(currentSession)); jsonWriter.WriteString("partialToken", session.Token.AsSpan(0, 16)); jsonWriter.WriteString("type", session.Type.ToString()); jsonWriter.WriteString("tokenName", session.TokenName); jsonWriter.WriteString("lastSeen", session.LastSeen); jsonWriter.WriteString("lastSeenRemoteAddress", session.LastSeenRemoteAddress.ToString()); jsonWriter.WriteString("lastSeenUserAgent", session.LastSeenUserAgent); jsonWriter.WriteEndObject(); } private void WriteGroupDetails(Utf8JsonWriter jsonWriter, Group group, bool includeMembers, bool includeUsers) { jsonWriter.WriteString("name", group.Name); jsonWriter.WriteString("description", group.Description); if (includeMembers) { jsonWriter.WritePropertyName("members"); jsonWriter.WriteStartArray(); List members = _dnsWebService._authManager.GetGroupMembers(group); members.Sort(); foreach (User user in members) jsonWriter.WriteStringValue(user.Username); jsonWriter.WriteEndArray(); } if (includeUsers) { List users = new List(_dnsWebService._authManager.Users); users.Sort(); jsonWriter.WritePropertyName("users"); jsonWriter.WriteStartArray(); foreach (User user in users) jsonWriter.WriteStringValue(user.Username); jsonWriter.WriteEndArray(); } } private void WritePermissionDetails(Utf8JsonWriter jsonWriter, Permission permission, string subItem, bool includeUsersAndGroups) { jsonWriter.WriteString("section", permission.Section.ToString()); if (subItem is not null) jsonWriter.WriteString("subItem", subItem.Length == 0 ? "." : subItem); jsonWriter.WritePropertyName("userPermissions"); jsonWriter.WriteStartArray(); List> userPermissions = new List>(permission.UserPermissions); userPermissions.Sort(delegate (KeyValuePair x, KeyValuePair y) { return x.Key.Username.CompareTo(y.Key.Username); }); foreach (KeyValuePair userPermission in userPermissions) { jsonWriter.WriteStartObject(); jsonWriter.WriteString("username", userPermission.Key.Username); jsonWriter.WriteBoolean("canView", userPermission.Value.HasFlag(PermissionFlag.View)); jsonWriter.WriteBoolean("canModify", userPermission.Value.HasFlag(PermissionFlag.Modify)); jsonWriter.WriteBoolean("canDelete", userPermission.Value.HasFlag(PermissionFlag.Delete)); jsonWriter.WriteEndObject(); } jsonWriter.WriteEndArray(); jsonWriter.WritePropertyName("groupPermissions"); jsonWriter.WriteStartArray(); List> groupPermissions = new List>(permission.GroupPermissions); groupPermissions.Sort(delegate (KeyValuePair x, KeyValuePair y) { return x.Key.Name.CompareTo(y.Key.Name); }); foreach (KeyValuePair groupPermission in groupPermissions) { jsonWriter.WriteStartObject(); jsonWriter.WriteString("name", groupPermission.Key.Name); jsonWriter.WriteBoolean("canView", groupPermission.Value.HasFlag(PermissionFlag.View)); jsonWriter.WriteBoolean("canModify", groupPermission.Value.HasFlag(PermissionFlag.Modify)); jsonWriter.WriteBoolean("canDelete", groupPermission.Value.HasFlag(PermissionFlag.Delete)); jsonWriter.WriteEndObject(); } jsonWriter.WriteEndArray(); if (includeUsersAndGroups) { List users = new List(_dnsWebService._authManager.Users); users.Sort(); List groups = new List(_dnsWebService._authManager.Groups); groups.Sort(); jsonWriter.WritePropertyName("users"); jsonWriter.WriteStartArray(); foreach (User user in users) jsonWriter.WriteStringValue(user.Username); jsonWriter.WriteEndArray(); jsonWriter.WritePropertyName("groups"); jsonWriter.WriteStartArray(); foreach (Group group in groups) jsonWriter.WriteStringValue(group.Name); jsonWriter.WriteEndArray(); } } #endregion #region public public async Task LoginAsync(HttpContext context, UserSessionType sessionType) { HttpRequest request = context.Request; string username = request.GetQueryOrForm("user"); string password = request.GetQueryOrForm("pass"); string tokenName = (sessionType == UserSessionType.ApiToken) ? request.GetQueryOrForm("tokenName") : null; bool includeInfo = request.GetQueryOrForm("includeInfo", bool.Parse, false); IPEndPoint remoteEP = context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader); UserSession session = await _dnsWebService._authManager.CreateSessionAsync(sessionType, tokenName, username, password, remoteEP.Address, request.Headers.UserAgent); _dnsWebService._log.Write(remoteEP, "[" + session.User.Username + "] User logged in."); _dnsWebService._authManager.SaveConfigFile(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteCurrentSessionDetails(jsonWriter, session, includeInfo); } public void Logout(HttpContext context) { string token = context.Request.GetQueryOrForm("token"); UserSession session = _dnsWebService._authManager.DeleteSession(token); if (session is not null) { _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User logged out."); _dnsWebService._authManager.SaveConfigFile(); } } public void GetCurrentSessionDetails(HttpContext context) { UserSession session = context.GetCurrentSession(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteCurrentSessionDetails(jsonWriter, session, true); } public void ChangePassword(HttpContext context) { UserSession session = context.GetCurrentSession(); if (session.Type != UserSessionType.Standard) throw new DnsWebServiceException("Access was denied."); string password = context.Request.GetQueryOrForm("pass"); session.User.ChangePassword(password); _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Password was changed successfully."); _dnsWebService._authManager.SaveConfigFile(); } public void GetProfile(HttpContext context) { UserSession session = context.GetCurrentSession(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteUserDetails(jsonWriter, session.User, session, true, false); } public void SetProfile(HttpContext context) { UserSession session = context.GetCurrentSession(); if (session.Type != UserSessionType.Standard) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; if (request.TryGetQueryOrForm("displayName", out string displayName)) session.User.DisplayName = displayName; if (request.TryGetQueryOrForm("sessionTimeoutSeconds", int.Parse, out int sessionTimeoutSeconds)) session.User.SessionTimeoutSeconds = sessionTimeoutSeconds; _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User profile was updated successfully."); _dnsWebService._authManager.SaveConfigFile(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteUserDetails(jsonWriter, session.User, session, true, false); } public void ListSessions(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WritePropertyName("sessions"); jsonWriter.WriteStartArray(); List sessions = new List(_dnsWebService._authManager.Sessions); sessions.Sort(); foreach (UserSession activeSession in sessions) { if (!activeSession.HasExpired()) WriteUserSessionDetails(jsonWriter, activeSession, session); } jsonWriter.WriteEndArray(); } public void CreateApiToken(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; string username = request.GetQueryOrForm("user"); string tokenName = request.GetQueryOrForm("tokenName"); IPEndPoint remoteEP = context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader); UserSession createdSession = _dnsWebService._authManager.CreateApiToken(tokenName, username, remoteEP.Address, request.Headers.UserAgent); _dnsWebService._log.Write(remoteEP, "[" + session.User.Username + "] API token [" + tokenName + "] was created successfully for user: " + username); _dnsWebService._authManager.SaveConfigFile(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WriteString("username", createdSession.User.Username); jsonWriter.WriteString("tokenName", createdSession.TokenName); jsonWriter.WriteString("token", createdSession.Token); } public void DeleteSession(HttpContext context, bool isAdminContext) { UserSession session = context.GetCurrentSession(); if (isAdminContext) { if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); } string strPartialToken = context.Request.GetQueryOrForm("partialToken"); if (session.Token.StartsWith(strPartialToken)) throw new InvalidOperationException("Invalid operation: cannot delete current session."); string token = null; foreach (UserSession activeSession in _dnsWebService._authManager.Sessions) { if (activeSession.Token.StartsWith(strPartialToken)) { token = activeSession.Token; break; } } if (token is null) throw new DnsWebServiceException("No such active session was found for partial token: " + strPartialToken); if (!isAdminContext) { UserSession sessionToDelete = _dnsWebService._authManager.GetSession(token); if (sessionToDelete.User != session.User) throw new DnsWebServiceException("Access was denied."); } UserSession deletedSession = _dnsWebService._authManager.DeleteSession(token); _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User session [" + strPartialToken + "] was deleted successfully for user: " + deletedSession.User.Username); _dnsWebService._authManager.SaveConfigFile(); } public void ListUsers(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); List users = new List(_dnsWebService._authManager.Users); users.Sort(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WritePropertyName("users"); jsonWriter.WriteStartArray(); foreach (User user in users) { jsonWriter.WriteStartObject(); WriteUserDetails(jsonWriter, user, null, false, false); jsonWriter.WriteEndObject(); } jsonWriter.WriteEndArray(); } public void CreateUser(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; string displayName = request.QueryOrForm("displayName"); string username = request.GetQueryOrForm("user"); string password = request.GetQueryOrForm("pass"); User user = _dnsWebService._authManager.CreateUser(displayName, username, password); _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User account was created successfully with username: " + user.Username); _dnsWebService._authManager.SaveConfigFile(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteUserDetails(jsonWriter, user, null, false, false); } public void GetUserDetails(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; string username = request.GetQueryOrForm("user"); bool includeGroups = request.GetQueryOrForm("includeGroups", bool.Parse, false); User user = _dnsWebService._authManager.GetUser(username); if (user is null) throw new DnsWebServiceException("No such user exists: " + username); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteUserDetails(jsonWriter, user, null, true, includeGroups); } public void SetUserDetails(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; string username = request.GetQueryOrForm("user"); User user = _dnsWebService._authManager.GetUser(username); if (user is null) throw new DnsWebServiceException("No such user exists: " + username); if (request.TryGetQueryOrForm("displayName", out string displayName)) user.DisplayName = displayName; if (request.TryGetQueryOrForm("newUser", out string newUsername)) _dnsWebService._authManager.ChangeUsername(user, newUsername); if (request.TryGetQueryOrForm("disabled", bool.Parse, out bool disabled) && (session.User != user)) //to avoid self lockout { user.Disabled = disabled; if (user.Disabled) { foreach (UserSession userSession in _dnsWebService._authManager.Sessions) { if (userSession.Type == UserSessionType.ApiToken) continue; if (userSession.User == user) _dnsWebService._authManager.DeleteSession(userSession.Token); } } } if (request.TryGetQueryOrForm("sessionTimeoutSeconds", int.Parse, out int sessionTimeoutSeconds)) user.SessionTimeoutSeconds = sessionTimeoutSeconds; string newPassword = request.QueryOrForm("newPass"); if (!string.IsNullOrWhiteSpace(newPassword)) { int iterations = request.GetQueryOrForm("iterations", int.Parse, User.DEFAULT_ITERATIONS); user.ChangePassword(newPassword, iterations); } string memberOfGroups = request.QueryOrForm("memberOfGroups"); if (memberOfGroups is not null) { string[] parts = memberOfGroups.Split(','); Dictionary groups = new Dictionary(parts.Length); foreach (string part in parts) { if (part.Length == 0) continue; Group group = _dnsWebService._authManager.GetGroup(part); if (group is null) throw new DnsWebServiceException("No such group exists: " + part); groups.Add(group.Name.ToLowerInvariant(), group); } //ensure user is member of everyone group Group everyone = _dnsWebService._authManager.GetGroup(Group.EVERYONE); groups[everyone.Name.ToLowerInvariant()] = everyone; if (session.User == user) { //ensure current admin user is member of administrators group to avoid self lockout Group admins = _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS); groups[admins.Name.ToLowerInvariant()] = admins; } user.SyncGroups(groups); } _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User account details were updated successfully for user: " + username); _dnsWebService._authManager.SaveConfigFile(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteUserDetails(jsonWriter, user, null, true, false); } public void DeleteUser(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string username = context.Request.GetQueryOrForm("user"); if (session.User.Username.Equals(username, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("Invalid operation: cannot delete current user."); if (!_dnsWebService._authManager.DeleteUser(username)) throw new DnsWebServiceException("Failed to delete user: " + username); _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User account was deleted successfully with username: " + username); _dnsWebService._authManager.SaveConfigFile(); } public void ListGroups(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); List groups = new List(_dnsWebService._authManager.Groups); groups.Sort(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WritePropertyName("groups"); jsonWriter.WriteStartArray(); foreach (Group group in groups) { if (group.Name.Equals("Everyone", StringComparison.OrdinalIgnoreCase)) continue; jsonWriter.WriteStartObject(); WriteGroupDetails(jsonWriter, group, false, false); jsonWriter.WriteEndObject(); } jsonWriter.WriteEndArray(); } public void CreateGroup(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; string groupName = request.GetQueryOrForm("group"); string description = request.GetQueryOrForm("description", ""); Group group = _dnsWebService._authManager.CreateGroup(groupName, description); _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Group was created successfully with name: " + group.Name); _dnsWebService._authManager.SaveConfigFile(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteGroupDetails(jsonWriter, group, false, false); } public void GetGroupDetails(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; string groupName = request.GetQueryOrForm("group"); bool includeUsers = request.GetQueryOrForm("includeUsers", bool.Parse, false); Group group = _dnsWebService._authManager.GetGroup(groupName); if (group is null) throw new DnsWebServiceException("No such group exists: " + groupName); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteGroupDetails(jsonWriter, group, true, includeUsers); } public void SetGroupDetails(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); HttpRequest request = context.Request; string groupName = request.GetQueryOrForm("group"); Group group = _dnsWebService._authManager.GetGroup(groupName); if (group is null) throw new DnsWebServiceException("No such group exists: " + groupName); if (request.TryGetQueryOrForm("newGroup", out string newGroup)) _dnsWebService._authManager.RenameGroup(group, newGroup); if (request.TryGetQueryOrForm("description", out string description)) group.Description = description; string members = request.QueryOrForm("members"); if (members is not null) { string[] parts = members.Split(','); Dictionary users = new Dictionary(); foreach (string part in parts) { if (part.Length == 0) continue; User user = _dnsWebService._authManager.GetUser(part); if (user is null) throw new DnsWebServiceException("No such user exists: " + part); users.Add(user.Username, user); } if (group.Name.Equals("administrators", StringComparison.OrdinalIgnoreCase)) users[session.User.Username] = session.User; //ensure current admin user is member of administrators group to avoid self lockout _dnsWebService._authManager.SyncGroupMembers(group, users); } _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Group details were updated successfully for group: " + groupName); _dnsWebService._authManager.SaveConfigFile(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WriteGroupDetails(jsonWriter, group, true, false); } public void DeleteGroup(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); string groupName = context.Request.GetQueryOrForm("group"); if (!_dnsWebService._authManager.DeleteGroup(groupName)) throw new DnsWebServiceException("Failed to delete group: " + groupName); _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Group was deleted successfully with name: " + groupName); _dnsWebService._authManager.SaveConfigFile(); } public void ListPermissions(HttpContext context) { UserSession session = context.GetCurrentSession(); if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); List permissions = new List(_dnsWebService._authManager.Permissions); permissions.Sort(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); jsonWriter.WritePropertyName("permissions"); jsonWriter.WriteStartArray(); foreach (Permission permission in permissions) { jsonWriter.WriteStartObject(); WritePermissionDetails(jsonWriter, permission, null, false); jsonWriter.WriteEndObject(); } jsonWriter.WriteEndArray(); } public void GetPermissionDetails(HttpContext context, PermissionSection section) { UserSession session = context.GetCurrentSession(); HttpRequest request = context.Request; string strSubItem = null; switch (section) { case PermissionSection.Unknown: if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); section = request.GetQueryOrFormEnum("section"); break; case PermissionSection.Zones: if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); strSubItem = request.GetQueryOrForm("zone").TrimEnd('.'); break; default: throw new InvalidOperationException(); } bool includeUsersAndGroups = request.GetQueryOrForm("includeUsersAndGroups", bool.Parse, false); if (strSubItem is not null) { if (!_dnsWebService._authManager.IsPermitted(section, strSubItem, session.User, PermissionFlag.View)) throw new DnsWebServiceException("Access was denied."); } Permission permission; if (strSubItem is null) permission = _dnsWebService._authManager.GetPermission(section); else permission = _dnsWebService._authManager.GetPermission(section, strSubItem); if (permission is null) throw new DnsWebServiceException("No permissions exists for section: " + section.ToString() + (strSubItem is null ? "" : "/" + strSubItem)); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WritePermissionDetails(jsonWriter, permission, strSubItem, includeUsersAndGroups); } public void SetPermissionsDetails(HttpContext context, PermissionSection section) { UserSession session = context.GetCurrentSession(); HttpRequest request = context.Request; string strSubItem = null; switch (section) { case PermissionSection.Unknown: if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); section = request.GetQueryOrFormEnum("section"); break; case PermissionSection.Zones: if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify)) throw new DnsWebServiceException("Access was denied."); strSubItem = request.GetQueryOrForm("zone").TrimEnd('.'); break; default: throw new InvalidOperationException(); } if (strSubItem is not null) { if (!_dnsWebService._authManager.IsPermitted(section, strSubItem, session.User, PermissionFlag.Delete)) throw new DnsWebServiceException("Access was denied."); } Permission permission; if (strSubItem is null) permission = _dnsWebService._authManager.GetPermission(section); else permission = _dnsWebService._authManager.GetPermission(section, strSubItem); if (permission is null) throw new DnsWebServiceException("No permissions exists for section: " + section.ToString() + (strSubItem is null ? "" : "/" + strSubItem)); string strUserPermissions = request.QueryOrForm("userPermissions"); if (strUserPermissions is not null) { string[] parts = strUserPermissions.Split('|'); Dictionary userPermissions = new Dictionary(); for (int i = 0; i < parts.Length; i += 4) { if (parts[i].Length == 0) continue; User user = _dnsWebService._authManager.GetUser(parts[i]); bool canView = bool.Parse(parts[i + 1]); bool canModify = bool.Parse(parts[i + 2]); bool canDelete = bool.Parse(parts[i + 3]); if (user is not null) { PermissionFlag permissionFlag = PermissionFlag.None; if (canView) permissionFlag |= PermissionFlag.View; if (canModify) permissionFlag |= PermissionFlag.Modify; if (canDelete) permissionFlag |= PermissionFlag.Delete; userPermissions[user] = permissionFlag; } } permission.SyncPermissions(userPermissions); } string strGroupPermissions = request.QueryOrForm("groupPermissions"); if (strGroupPermissions is not null) { string[] parts = strGroupPermissions.Split('|'); Dictionary groupPermissions = new Dictionary(); for (int i = 0; i < parts.Length; i += 4) { if (parts[i].Length == 0) continue; Group group = _dnsWebService._authManager.GetGroup(parts[i]); bool canView = bool.Parse(parts[i + 1]); bool canModify = bool.Parse(parts[i + 2]); bool canDelete = bool.Parse(parts[i + 3]); if (group is not null) { PermissionFlag permissionFlag = PermissionFlag.None; if (canView) permissionFlag |= PermissionFlag.View; if (canModify) permissionFlag |= PermissionFlag.Modify; if (canDelete) permissionFlag |= PermissionFlag.Delete; groupPermissions[group] = permissionFlag; } } //ensure administrators group always has all permissions Group admins = _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS); groupPermissions[admins] = PermissionFlag.ViewModifyDelete; switch (section) { case PermissionSection.Zones: //ensure DNS administrators group always has all permissions Group dnsAdmins = _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS); groupPermissions[dnsAdmins] = PermissionFlag.ViewModifyDelete; break; case PermissionSection.DhcpServer: //ensure DHCP administrators group always has all permissions Group dhcpAdmins = _dnsWebService._authManager.GetGroup(Group.DHCP_ADMINISTRATORS); groupPermissions[dhcpAdmins] = PermissionFlag.ViewModifyDelete; break; } permission.SyncPermissions(groupPermissions); } _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Permissions were updated successfully for section: " + section.ToString() + (string.IsNullOrEmpty(strSubItem) ? "" : "/" + strSubItem)); _dnsWebService._authManager.SaveConfigFile(); Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter(); WritePermissionDetails(jsonWriter, permission, strSubItem, false); } #endregion } }