/* Technitium DNS Server Copyright (C) 2022 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 Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; 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(JsonTextWriter jsonWriter, UserSession currentSession, bool includeInfo) { if (currentSession.Type == UserSessionType.ApiToken) { jsonWriter.WritePropertyName("username"); jsonWriter.WriteValue(currentSession.User.Username); jsonWriter.WritePropertyName("tokenName"); jsonWriter.WriteValue(currentSession.TokenName); jsonWriter.WritePropertyName("token"); jsonWriter.WriteValue(currentSession.Token); } else { jsonWriter.WritePropertyName("displayName"); jsonWriter.WriteValue(currentSession.User.DisplayName); jsonWriter.WritePropertyName("username"); jsonWriter.WriteValue(currentSession.User.Username); jsonWriter.WritePropertyName("token"); jsonWriter.WriteValue(currentSession.Token); } if (includeInfo) { jsonWriter.WritePropertyName("info"); jsonWriter.WriteStartObject(); jsonWriter.WritePropertyName("version"); jsonWriter.WriteValue(_dnsWebService.GetServerVersion()); jsonWriter.WritePropertyName("dnsServerDomain"); jsonWriter.WriteValue(_dnsWebService.DnsServer.ServerDomain); jsonWriter.WritePropertyName("defaultRecordTtl"); jsonWriter.WriteValue(_dnsWebService.ZonesApi.DefaultRecordTtl); jsonWriter.WritePropertyName("permissions"); jsonWriter.WriteStartObject(); for (int i = 1; i <= 11; i++) { PermissionSection section = (PermissionSection)i; jsonWriter.WritePropertyName(section.ToString()); jsonWriter.WriteStartObject(); jsonWriter.WritePropertyName("canView"); jsonWriter.WriteValue(_dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.View)); jsonWriter.WritePropertyName("canModify"); jsonWriter.WriteValue(_dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.Modify)); jsonWriter.WritePropertyName("canDelete"); jsonWriter.WriteValue(_dnsWebService.AuthManager.IsPermitted(section, currentSession.User, PermissionFlag.Delete)); jsonWriter.WriteEndObject(); } jsonWriter.WriteEndObject(); jsonWriter.WriteEndObject(); } } private void WriteUserDetails(JsonTextWriter jsonWriter, User user, UserSession currentSession, bool includeMoreDetails, bool includeGroups) { jsonWriter.WritePropertyName("displayName"); jsonWriter.WriteValue(user.DisplayName); jsonWriter.WritePropertyName("username"); jsonWriter.WriteValue(user.Username); jsonWriter.WritePropertyName("disabled"); jsonWriter.WriteValue(user.Disabled); jsonWriter.WritePropertyName("previousSessionLoggedOn"); jsonWriter.WriteValue(user.PreviousSessionLoggedOn); jsonWriter.WritePropertyName("previousSessionRemoteAddress"); jsonWriter.WriteValue(user.PreviousSessionRemoteAddress.ToString()); jsonWriter.WritePropertyName("recentSessionLoggedOn"); jsonWriter.WriteValue(user.RecentSessionLoggedOn); jsonWriter.WritePropertyName("recentSessionRemoteAddress"); jsonWriter.WriteValue(user.RecentSessionRemoteAddress.ToString()); if (includeMoreDetails) { jsonWriter.WritePropertyName("sessionTimeoutSeconds"); jsonWriter.WriteValue(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.WriteValue(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.WriteValue(group.Name); } jsonWriter.WriteEndArray(); } } private static void WriteUserSessionDetails(JsonTextWriter jsonWriter, UserSession session, UserSession currentSession) { jsonWriter.WriteStartObject(); jsonWriter.WritePropertyName("username"); jsonWriter.WriteValue(session.User.Username); jsonWriter.WritePropertyName("isCurrentSession"); jsonWriter.WriteValue(session.Equals(currentSession)); jsonWriter.WritePropertyName("partialToken"); jsonWriter.WriteValue(session.Token.Substring(0, 16)); jsonWriter.WritePropertyName("type"); jsonWriter.WriteValue(session.Type.ToString()); jsonWriter.WritePropertyName("tokenName"); jsonWriter.WriteValue(session.TokenName); jsonWriter.WritePropertyName("lastSeen"); jsonWriter.WriteValue(session.LastSeen); jsonWriter.WritePropertyName("lastSeenRemoteAddress"); jsonWriter.WriteValue(session.LastSeenRemoteAddress.ToString()); jsonWriter.WritePropertyName("lastSeenUserAgent"); jsonWriter.WriteValue(session.LastSeenUserAgent); jsonWriter.WriteEndObject(); } private void WriteGroupDetails(JsonTextWriter jsonWriter, Group group, bool includeMembers, bool includeUsers) { jsonWriter.WritePropertyName("name"); jsonWriter.WriteValue(group.Name); jsonWriter.WritePropertyName("description"); jsonWriter.WriteValue(group.Description); if (includeMembers) { jsonWriter.WritePropertyName("members"); jsonWriter.WriteStartArray(); List members = _dnsWebService.AuthManager.GetGroupMembers(group); members.Sort(); foreach (User user in members) jsonWriter.WriteValue(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.WriteValue(user.Username); jsonWriter.WriteEndArray(); } } private void WritePermissionDetails(JsonTextWriter jsonWriter, Permission permission, string subItem, bool includeUsersAndGroups) { jsonWriter.WritePropertyName("section"); jsonWriter.WriteValue(permission.Section.ToString()); if (subItem is not null) { jsonWriter.WritePropertyName("subItem"); jsonWriter.WriteValue(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.WritePropertyName("username"); jsonWriter.WriteValue(userPermission.Key.Username); jsonWriter.WritePropertyName("canView"); jsonWriter.WriteValue(userPermission.Value.HasFlag(PermissionFlag.View)); jsonWriter.WritePropertyName("canModify"); jsonWriter.WriteValue(userPermission.Value.HasFlag(PermissionFlag.Modify)); jsonWriter.WritePropertyName("canDelete"); jsonWriter.WriteValue(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.WritePropertyName("name"); jsonWriter.WriteValue(groupPermission.Key.Name); jsonWriter.WritePropertyName("canView"); jsonWriter.WriteValue(groupPermission.Value.HasFlag(PermissionFlag.View)); jsonWriter.WritePropertyName("canModify"); jsonWriter.WriteValue(groupPermission.Value.HasFlag(PermissionFlag.Modify)); jsonWriter.WritePropertyName("canDelete"); jsonWriter.WriteValue(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.WriteValue(user.Username); jsonWriter.WriteEndArray(); jsonWriter.WritePropertyName("groups"); jsonWriter.WriteStartArray(); foreach (Group group in groups) jsonWriter.WriteValue(group.Name); jsonWriter.WriteEndArray(); } } #endregion #region public public async Task LoginAsync(HttpListenerRequest request, JsonTextWriter jsonWriter, UserSessionType sessionType) { string strUsername = request.QueryString["user"]; if (string.IsNullOrEmpty(strUsername)) throw new DnsWebServiceException("Parameter 'user' missing."); string strPassword = request.QueryString["pass"]; if (string.IsNullOrEmpty(strPassword)) throw new DnsWebServiceException("Parameter 'pass' missing."); string strTokenName = null; if (sessionType == UserSessionType.ApiToken) { strTokenName = request.QueryString["tokenName"]; if (string.IsNullOrEmpty(strTokenName)) throw new DnsWebServiceException("Parameter 'tokenName' missing."); } bool includeInfo; string strIncludeInfo = request.QueryString["includeInfo"]; if (string.IsNullOrEmpty(strIncludeInfo)) includeInfo = false; else includeInfo = bool.Parse(strIncludeInfo); IPEndPoint remoteEP = DnsWebService.GetRequestRemoteEndPoint(request); UserSession session = await _dnsWebService.AuthManager.CreateSessionAsync(sessionType, strTokenName, strUsername, strPassword, remoteEP.Address, request.UserAgent); _dnsWebService.Log.Write(remoteEP, "[" + session.User.Username + "] User logged in."); _dnsWebService.AuthManager.SaveConfigFile(); WriteCurrentSessionDetails(jsonWriter, session, includeInfo); } public void Logout(HttpListenerRequest request) { string strToken = request.QueryString["token"]; if (string.IsNullOrEmpty(strToken)) throw new DnsWebServiceException("Parameter 'token' missing."); UserSession session = _dnsWebService.AuthManager.DeleteSession(strToken); if (session is not null) { _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User logged out."); _dnsWebService.AuthManager.SaveConfigFile(); } } public void GetCurrentSessionDetails(HttpListenerRequest request, JsonTextWriter jsonWriter) { if (!_dnsWebService.TryGetSession(request, out UserSession session)) throw new InvalidTokenWebServiceException("Invalid token or session expired."); WriteCurrentSessionDetails(jsonWriter, session, true); } public void ChangePassword(HttpListenerRequest request) { UserSession session = _dnsWebService.GetSession(request); if (session.Type != UserSessionType.Standard) throw new DnsWebServiceException("Access was denied."); string strPassword = request.QueryString["pass"]; if (string.IsNullOrEmpty(strPassword)) throw new DnsWebServiceException("Parameter 'pass' missing."); session.User.ChangePassword(strPassword); _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Password was changed successfully."); _dnsWebService.AuthManager.SaveConfigFile(); } public void GetProfile(HttpListenerRequest request, JsonTextWriter jsonWriter) { UserSession session = _dnsWebService.GetSession(request); WriteUserDetails(jsonWriter, session.User, session, true, false); } public void SetProfile(HttpListenerRequest request, JsonTextWriter jsonWriter) { UserSession session = _dnsWebService.GetSession(request); if (session.Type != UserSessionType.Standard) throw new DnsWebServiceException("Access was denied."); string strDisplayName = request.QueryString["displayName"]; if (!string.IsNullOrEmpty(strDisplayName)) session.User.DisplayName = strDisplayName; string strSessionTimeoutSeconds = request.QueryString["sessionTimeoutSeconds"]; if (!string.IsNullOrEmpty(strSessionTimeoutSeconds)) session.User.SessionTimeoutSeconds = int.Parse(strSessionTimeoutSeconds); _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User profile was updated successfully."); _dnsWebService.AuthManager.SaveConfigFile(); WriteUserDetails(jsonWriter, session.User, session, true, false); } public void ListSessions(HttpListenerRequest request, JsonTextWriter jsonWriter) { UserSession session = _dnsWebService.GetSession(request); 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(HttpListenerRequest request, JsonTextWriter jsonWriter) { string strUsername = request.QueryString["user"]; if (string.IsNullOrEmpty(strUsername)) throw new DnsWebServiceException("Parameter 'user' missing."); string strTokenName = request.QueryString["tokenName"]; if (string.IsNullOrEmpty(strTokenName)) throw new DnsWebServiceException("Parameter 'tokenName' missing."); IPEndPoint remoteEP = DnsWebService.GetRequestRemoteEndPoint(request); UserSession session = _dnsWebService.AuthManager.CreateApiToken(strTokenName, strUsername, remoteEP.Address, request.UserAgent); _dnsWebService.Log.Write(remoteEP, "[" + session.User.Username + "] API token [" + strTokenName + "] was created successfully for user: " + strUsername); _dnsWebService.AuthManager.SaveConfigFile(); jsonWriter.WritePropertyName("username"); jsonWriter.WriteValue(session.User.Username); jsonWriter.WritePropertyName("tokenName"); jsonWriter.WriteValue(session.TokenName); jsonWriter.WritePropertyName("token"); jsonWriter.WriteValue(session.Token); } public void DeleteSession(HttpListenerRequest request, bool isAdminContext) { string strPartialToken = request.QueryString["partialToken"]; if (string.IsNullOrEmpty(strPartialToken)) throw new DnsWebServiceException("Parameter 'partialToken' missing."); UserSession session = _dnsWebService.GetSession(request); 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(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User session [" + strPartialToken + "] was deleted successfully for user: " + deletedSession.User.Username); _dnsWebService.AuthManager.SaveConfigFile(); } public void ListUsers(JsonTextWriter jsonWriter) { List users = new List(_dnsWebService.AuthManager.Users); users.Sort(); 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(HttpListenerRequest request, JsonTextWriter jsonWriter) { string strDisplayName = request.QueryString["displayName"]; string strUsername = request.QueryString["user"]; if (string.IsNullOrEmpty(strUsername)) throw new DnsWebServiceException("Parameter 'user' missing."); string strPassword = request.QueryString["pass"]; if (string.IsNullOrEmpty(strPassword)) throw new DnsWebServiceException("Parameter 'pass' missing."); User user = _dnsWebService.AuthManager.CreateUser(strDisplayName, strUsername, strPassword); UserSession session = _dnsWebService.GetSession(request); _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account was created successfully with username: " + user.Username); _dnsWebService.AuthManager.SaveConfigFile(); WriteUserDetails(jsonWriter, user, null, false, false); } public void GetUserDetails(HttpListenerRequest request, JsonTextWriter jsonWriter) { string strUsername = request.QueryString["user"]; if (string.IsNullOrEmpty(strUsername)) throw new DnsWebServiceException("Parameter 'user' missing."); bool includeGroups; string strIncludeGroups = request.QueryString["includeGroups"]; if (string.IsNullOrEmpty(strIncludeGroups)) includeGroups = false; else includeGroups = bool.Parse(strIncludeGroups); User user = _dnsWebService.AuthManager.GetUser(strUsername); if (user is null) throw new DnsWebServiceException("No such user exists: " + strUsername); WriteUserDetails(jsonWriter, user, null, true, includeGroups); } public void SetUserDetails(HttpListenerRequest request, JsonTextWriter jsonWriter) { string strUsername = request.QueryString["user"]; if (string.IsNullOrEmpty(strUsername)) throw new DnsWebServiceException("Parameter 'user' missing."); User user = _dnsWebService.AuthManager.GetUser(strUsername); if (user is null) throw new DnsWebServiceException("No such user exists: " + strUsername); string strDisplayName = request.QueryString["displayName"]; if (!string.IsNullOrEmpty(strDisplayName)) user.DisplayName = strDisplayName; string strNewUsername = request.QueryString["newUser"]; if (!string.IsNullOrEmpty(strNewUsername)) _dnsWebService.AuthManager.ChangeUsername(user, strNewUsername); UserSession session = _dnsWebService.GetSession(request); string strDisabled = request.QueryString["disabled"]; if (!string.IsNullOrEmpty(strDisabled) && (session.User != user)) //to avoid self lockout { user.Disabled = bool.Parse(strDisabled); 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); } } } string strSessionTimeoutSeconds = request.QueryString["sessionTimeoutSeconds"]; if (!string.IsNullOrEmpty(strSessionTimeoutSeconds)) user.SessionTimeoutSeconds = int.Parse(strSessionTimeoutSeconds); string strNewPassword = request.QueryString["newPass"]; if (!string.IsNullOrWhiteSpace(strNewPassword)) { int iterations; string strIterations = request.QueryString["iterations"]; if (string.IsNullOrEmpty(strIterations)) iterations = User.DEFAULT_ITERATIONS; else iterations = int.Parse(strIterations); user.ChangePassword(strNewPassword, iterations); } string strMemberOfGroups = request.QueryString["memberOfGroups"]; if (strMemberOfGroups is not null) { string[] parts = strMemberOfGroups.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.ToLower(), group); } //ensure user is member of everyone group Group everyone = _dnsWebService.AuthManager.GetGroup(Group.EVERYONE); groups[everyone.Name.ToLower()] = 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.ToLower()] = admins; } user.SyncGroups(groups); } _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account details were updated successfully for user: " + strUsername); _dnsWebService.AuthManager.SaveConfigFile(); WriteUserDetails(jsonWriter, user, null, true, false); } public void DeleteUser(HttpListenerRequest request) { string strUsername = request.QueryString["user"]; if (string.IsNullOrEmpty(strUsername)) throw new DnsWebServiceException("Parameter 'user' missing."); UserSession session = _dnsWebService.GetSession(request); if (session.User.Username.Equals(strUsername, StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException("Invalid operation: cannot delete current user."); if (!_dnsWebService.AuthManager.DeleteUser(strUsername)) throw new DnsWebServiceException("Failed to delete user: " + strUsername); _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] User account was deleted successfully with username: " + strUsername); _dnsWebService.AuthManager.SaveConfigFile(); } public void ListGroups(JsonTextWriter jsonWriter) { 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.WriteStartObject(); WriteGroupDetails(jsonWriter, group, false, false); jsonWriter.WriteEndObject(); } jsonWriter.WriteEndArray(); } public void CreateGroup(HttpListenerRequest request, JsonTextWriter jsonWriter) { string strGroup = request.QueryString["group"]; if (string.IsNullOrEmpty(strGroup)) throw new DnsWebServiceException("Parameter 'group' missing."); string strDescription = request.QueryString["description"]; if (string.IsNullOrEmpty(strDescription)) strDescription = ""; Group group = _dnsWebService.AuthManager.CreateGroup(strGroup, strDescription); UserSession session = _dnsWebService.GetSession(request); _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group was created successfully with name: " + group.Name); _dnsWebService.AuthManager.SaveConfigFile(); WriteGroupDetails(jsonWriter, group, false, false); } public void GetGroupDetails(HttpListenerRequest request, JsonTextWriter jsonWriter) { string strGroup = request.QueryString["group"]; if (string.IsNullOrEmpty(strGroup)) throw new DnsWebServiceException("Parameter 'group' missing."); bool includeUsers; string strIncludeGroups = request.QueryString["includeUsers"]; if (string.IsNullOrEmpty(strIncludeGroups)) includeUsers = false; else includeUsers = bool.Parse(strIncludeGroups); Group group = _dnsWebService.AuthManager.GetGroup(strGroup); if (group is null) throw new DnsWebServiceException("No such group exists: " + strGroup); WriteGroupDetails(jsonWriter, group, true, includeUsers); } public void SetGroupDetails(HttpListenerRequest request, JsonTextWriter jsonWriter) { string strGroup = request.QueryString["group"]; if (string.IsNullOrEmpty(strGroup)) throw new DnsWebServiceException("Parameter 'group' missing."); Group group = _dnsWebService.AuthManager.GetGroup(strGroup); if (group is null) throw new DnsWebServiceException("No such group exists: " + strGroup); string strNewGroup = request.QueryString["newGroup"]; if (!string.IsNullOrEmpty(strNewGroup)) _dnsWebService.AuthManager.RenameGroup(group, strNewGroup); string strDescription = request.QueryString["description"]; if (!string.IsNullOrEmpty(strDescription)) group.Description = strDescription; UserSession session = _dnsWebService.GetSession(request); string strMembers = request.QueryString["members"]; if (strMembers is not null) { string[] parts = strMembers.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(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group details were updated successfully for group: " + strGroup); _dnsWebService.AuthManager.SaveConfigFile(); WriteGroupDetails(jsonWriter, group, true, false); } public void DeleteGroup(HttpListenerRequest request) { string strGroup = request.QueryString["group"]; if (string.IsNullOrEmpty(strGroup)) throw new DnsWebServiceException("Parameter 'group' missing."); if (!_dnsWebService.AuthManager.DeleteGroup(strGroup)) throw new DnsWebServiceException("Failed to delete group: " + strGroup); UserSession session = _dnsWebService.GetSession(request); _dnsWebService.Log.Write(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Group was deleted successfully with name: " + strGroup); _dnsWebService.AuthManager.SaveConfigFile(); } public void ListPermissions(JsonTextWriter jsonWriter) { List permissions = new List(_dnsWebService.AuthManager.Permissions); permissions.Sort(); jsonWriter.WritePropertyName("permissions"); jsonWriter.WriteStartArray(); foreach (Permission permission in permissions) { jsonWriter.WriteStartObject(); WritePermissionDetails(jsonWriter, permission, null, false); jsonWriter.WriteEndObject(); } jsonWriter.WriteEndArray(); } public void GetPermissionDetails(HttpListenerRequest request, JsonTextWriter jsonWriter, PermissionSection section) { if (section == PermissionSection.Unknown) { string strSection = request.QueryString["section"]; if (string.IsNullOrEmpty(strSection)) throw new DnsWebServiceException("Parameter 'section' missing."); if (!Enum.TryParse(strSection, true, out section)) throw new DnsWebServiceException("No such permission section exists: " + strSection); } string strSubItem; switch (section) { case PermissionSection.Zones: strSubItem = request.QueryString["zone"]; if (strSubItem is not null) strSubItem = strSubItem.TrimEnd('.'); break; default: strSubItem = null; break; } bool includeUsersAndGroups; string strIncludeUsersAndGroups = request.QueryString["includeUsersAndGroups"]; if (string.IsNullOrEmpty(strIncludeUsersAndGroups)) includeUsersAndGroups = false; else includeUsersAndGroups = bool.Parse(strIncludeUsersAndGroups); if (strSubItem is not null) { UserSession session = _dnsWebService.GetSession(request); 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)); WritePermissionDetails(jsonWriter, permission, strSubItem, includeUsersAndGroups); } public void SetPermissionsDetails(HttpListenerRequest request, JsonTextWriter jsonWriter, PermissionSection section) { if (section == PermissionSection.Unknown) { string strSection = request.QueryString["section"]; if (string.IsNullOrEmpty(strSection)) throw new DnsWebServiceException("Parameter 'section' missing."); if (!Enum.TryParse(strSection, true, out section)) throw new DnsWebServiceException("No such permission section exists: " + strSection); } string strSubItem; switch (section) { case PermissionSection.Zones: strSubItem = request.QueryString["zone"]; if (strSubItem is not null) strSubItem = strSubItem.TrimEnd('.'); break; default: strSubItem = null; break; } UserSession session = _dnsWebService.GetSession(request); 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.QueryString["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.QueryString["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(DnsWebService.GetRequestRemoteEndPoint(request), "[" + session.User.Username + "] Permissions were updated successfully for section: " + section.ToString() + (string.IsNullOrEmpty(strSubItem) ? "" : "/" + strSubItem)); _dnsWebService.AuthManager.SaveConfigFile(); WritePermissionDetails(jsonWriter, permission, strSubItem, false); } #endregion } }