WebServiceAuthApi.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  1. /*
  2. Technitium DNS Server
  3. Copyright (C) 2024 Shreyas Zare (shreyas@technitium.com)
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. using DnsServerCore.Auth;
  16. using Microsoft.AspNetCore.Http;
  17. using System;
  18. using System.Collections.Generic;
  19. using System.Net;
  20. using System.Text.Json;
  21. using System.Threading.Tasks;
  22. namespace DnsServerCore
  23. {
  24. sealed class WebServiceAuthApi
  25. {
  26. #region variables
  27. readonly DnsWebService _dnsWebService;
  28. #endregion
  29. #region constructor
  30. public WebServiceAuthApi(DnsWebService dnsWebService)
  31. {
  32. _dnsWebService = dnsWebService;
  33. }
  34. #endregion
  35. #region private
  36. private void WriteCurrentSessionDetails(Utf8JsonWriter jsonWriter, UserSession currentSession, bool includeInfo)
  37. {
  38. if (currentSession.Type == UserSessionType.ApiToken)
  39. {
  40. jsonWriter.WriteString("username", currentSession.User.Username);
  41. jsonWriter.WriteString("tokenName", currentSession.TokenName);
  42. jsonWriter.WriteString("token", currentSession.Token);
  43. }
  44. else
  45. {
  46. jsonWriter.WriteString("displayName", currentSession.User.DisplayName);
  47. jsonWriter.WriteString("username", currentSession.User.Username);
  48. jsonWriter.WriteString("token", currentSession.Token);
  49. }
  50. if (includeInfo)
  51. {
  52. jsonWriter.WritePropertyName("info");
  53. jsonWriter.WriteStartObject();
  54. jsonWriter.WriteString("version", _dnsWebService.GetServerVersion());
  55. jsonWriter.WriteString("uptimestamp", _dnsWebService._uptimestamp);
  56. jsonWriter.WriteString("dnsServerDomain", _dnsWebService.DnsServer.ServerDomain);
  57. jsonWriter.WriteNumber("defaultRecordTtl", _dnsWebService._zonesApi.DefaultRecordTtl);
  58. jsonWriter.WriteBoolean("useSoaSerialDateScheme", _dnsWebService.DnsServer.AuthZoneManager.UseSoaSerialDateScheme);
  59. jsonWriter.WriteBoolean("dnssecValidation", _dnsWebService.DnsServer.DnssecValidation);
  60. jsonWriter.WritePropertyName("permissions");
  61. jsonWriter.WriteStartObject();
  62. for (int i = 1; i <= 11; i++)
  63. {
  64. PermissionSection section = (PermissionSection)i;
  65. jsonWriter.WritePropertyName(section.ToString());
  66. jsonWriter.WriteStartObject();
  67. jsonWriter.WriteBoolean("canView", _dnsWebService._authManager.IsPermitted(section, currentSession.User, PermissionFlag.View));
  68. jsonWriter.WriteBoolean("canModify", _dnsWebService._authManager.IsPermitted(section, currentSession.User, PermissionFlag.Modify));
  69. jsonWriter.WriteBoolean("canDelete", _dnsWebService._authManager.IsPermitted(section, currentSession.User, PermissionFlag.Delete));
  70. jsonWriter.WriteEndObject();
  71. }
  72. jsonWriter.WriteEndObject();
  73. jsonWriter.WriteEndObject();
  74. }
  75. }
  76. private void WriteUserDetails(Utf8JsonWriter jsonWriter, User user, UserSession currentSession, bool includeMoreDetails, bool includeGroups)
  77. {
  78. jsonWriter.WriteString("displayName", user.DisplayName);
  79. jsonWriter.WriteString("username", user.Username);
  80. jsonWriter.WriteBoolean("disabled", user.Disabled);
  81. jsonWriter.WriteString("previousSessionLoggedOn", user.PreviousSessionLoggedOn);
  82. jsonWriter.WriteString("previousSessionRemoteAddress", user.PreviousSessionRemoteAddress.ToString());
  83. jsonWriter.WriteString("recentSessionLoggedOn", user.RecentSessionLoggedOn);
  84. jsonWriter.WriteString("recentSessionRemoteAddress", user.RecentSessionRemoteAddress.ToString());
  85. if (includeMoreDetails)
  86. {
  87. jsonWriter.WriteNumber("sessionTimeoutSeconds", user.SessionTimeoutSeconds);
  88. jsonWriter.WritePropertyName("memberOfGroups");
  89. jsonWriter.WriteStartArray();
  90. List<Group> memberOfGroups = new List<Group>(user.MemberOfGroups);
  91. memberOfGroups.Sort();
  92. foreach (Group group in memberOfGroups)
  93. {
  94. if (group.Name.Equals("Everyone", StringComparison.OrdinalIgnoreCase))
  95. continue;
  96. jsonWriter.WriteStringValue(group.Name);
  97. }
  98. jsonWriter.WriteEndArray();
  99. jsonWriter.WritePropertyName("sessions");
  100. jsonWriter.WriteStartArray();
  101. List<UserSession> sessions = _dnsWebService._authManager.GetSessions(user);
  102. sessions.Sort();
  103. foreach (UserSession session in sessions)
  104. WriteUserSessionDetails(jsonWriter, session, currentSession);
  105. jsonWriter.WriteEndArray();
  106. }
  107. if (includeGroups)
  108. {
  109. List<Group> groups = new List<Group>(_dnsWebService._authManager.Groups);
  110. groups.Sort();
  111. jsonWriter.WritePropertyName("groups");
  112. jsonWriter.WriteStartArray();
  113. foreach (Group group in groups)
  114. {
  115. if (group.Name.Equals("Everyone", StringComparison.OrdinalIgnoreCase))
  116. continue;
  117. jsonWriter.WriteStringValue(group.Name);
  118. }
  119. jsonWriter.WriteEndArray();
  120. }
  121. }
  122. private static void WriteUserSessionDetails(Utf8JsonWriter jsonWriter, UserSession session, UserSession currentSession)
  123. {
  124. jsonWriter.WriteStartObject();
  125. jsonWriter.WriteString("username", session.User.Username);
  126. jsonWriter.WriteBoolean("isCurrentSession", session.Equals(currentSession));
  127. jsonWriter.WriteString("partialToken", session.Token.AsSpan(0, 16));
  128. jsonWriter.WriteString("type", session.Type.ToString());
  129. jsonWriter.WriteString("tokenName", session.TokenName);
  130. jsonWriter.WriteString("lastSeen", session.LastSeen);
  131. jsonWriter.WriteString("lastSeenRemoteAddress", session.LastSeenRemoteAddress.ToString());
  132. jsonWriter.WriteString("lastSeenUserAgent", session.LastSeenUserAgent);
  133. jsonWriter.WriteEndObject();
  134. }
  135. private void WriteGroupDetails(Utf8JsonWriter jsonWriter, Group group, bool includeMembers, bool includeUsers)
  136. {
  137. jsonWriter.WriteString("name", group.Name);
  138. jsonWriter.WriteString("description", group.Description);
  139. if (includeMembers)
  140. {
  141. jsonWriter.WritePropertyName("members");
  142. jsonWriter.WriteStartArray();
  143. List<User> members = _dnsWebService._authManager.GetGroupMembers(group);
  144. members.Sort();
  145. foreach (User user in members)
  146. jsonWriter.WriteStringValue(user.Username);
  147. jsonWriter.WriteEndArray();
  148. }
  149. if (includeUsers)
  150. {
  151. List<User> users = new List<User>(_dnsWebService._authManager.Users);
  152. users.Sort();
  153. jsonWriter.WritePropertyName("users");
  154. jsonWriter.WriteStartArray();
  155. foreach (User user in users)
  156. jsonWriter.WriteStringValue(user.Username);
  157. jsonWriter.WriteEndArray();
  158. }
  159. }
  160. private void WritePermissionDetails(Utf8JsonWriter jsonWriter, Permission permission, string subItem, bool includeUsersAndGroups)
  161. {
  162. jsonWriter.WriteString("section", permission.Section.ToString());
  163. if (subItem is not null)
  164. jsonWriter.WriteString("subItem", subItem.Length == 0 ? "." : subItem);
  165. jsonWriter.WritePropertyName("userPermissions");
  166. jsonWriter.WriteStartArray();
  167. List<KeyValuePair<User, PermissionFlag>> userPermissions = new List<KeyValuePair<User, PermissionFlag>>(permission.UserPermissions);
  168. userPermissions.Sort(delegate (KeyValuePair<User, PermissionFlag> x, KeyValuePair<User, PermissionFlag> y)
  169. {
  170. return x.Key.Username.CompareTo(y.Key.Username);
  171. });
  172. foreach (KeyValuePair<User, PermissionFlag> userPermission in userPermissions)
  173. {
  174. jsonWriter.WriteStartObject();
  175. jsonWriter.WriteString("username", userPermission.Key.Username);
  176. jsonWriter.WriteBoolean("canView", userPermission.Value.HasFlag(PermissionFlag.View));
  177. jsonWriter.WriteBoolean("canModify", userPermission.Value.HasFlag(PermissionFlag.Modify));
  178. jsonWriter.WriteBoolean("canDelete", userPermission.Value.HasFlag(PermissionFlag.Delete));
  179. jsonWriter.WriteEndObject();
  180. }
  181. jsonWriter.WriteEndArray();
  182. jsonWriter.WritePropertyName("groupPermissions");
  183. jsonWriter.WriteStartArray();
  184. List<KeyValuePair<Group, PermissionFlag>> groupPermissions = new List<KeyValuePair<Group, PermissionFlag>>(permission.GroupPermissions);
  185. groupPermissions.Sort(delegate (KeyValuePair<Group, PermissionFlag> x, KeyValuePair<Group, PermissionFlag> y)
  186. {
  187. return x.Key.Name.CompareTo(y.Key.Name);
  188. });
  189. foreach (KeyValuePair<Group, PermissionFlag> groupPermission in groupPermissions)
  190. {
  191. jsonWriter.WriteStartObject();
  192. jsonWriter.WriteString("name", groupPermission.Key.Name);
  193. jsonWriter.WriteBoolean("canView", groupPermission.Value.HasFlag(PermissionFlag.View));
  194. jsonWriter.WriteBoolean("canModify", groupPermission.Value.HasFlag(PermissionFlag.Modify));
  195. jsonWriter.WriteBoolean("canDelete", groupPermission.Value.HasFlag(PermissionFlag.Delete));
  196. jsonWriter.WriteEndObject();
  197. }
  198. jsonWriter.WriteEndArray();
  199. if (includeUsersAndGroups)
  200. {
  201. List<User> users = new List<User>(_dnsWebService._authManager.Users);
  202. users.Sort();
  203. List<Group> groups = new List<Group>(_dnsWebService._authManager.Groups);
  204. groups.Sort();
  205. jsonWriter.WritePropertyName("users");
  206. jsonWriter.WriteStartArray();
  207. foreach (User user in users)
  208. jsonWriter.WriteStringValue(user.Username);
  209. jsonWriter.WriteEndArray();
  210. jsonWriter.WritePropertyName("groups");
  211. jsonWriter.WriteStartArray();
  212. foreach (Group group in groups)
  213. jsonWriter.WriteStringValue(group.Name);
  214. jsonWriter.WriteEndArray();
  215. }
  216. }
  217. #endregion
  218. #region public
  219. public async Task LoginAsync(HttpContext context, UserSessionType sessionType)
  220. {
  221. HttpRequest request = context.Request;
  222. string username = request.GetQueryOrForm("user");
  223. string password = request.GetQueryOrForm("pass");
  224. string tokenName = (sessionType == UserSessionType.ApiToken) ? request.GetQueryOrForm("tokenName") : null;
  225. bool includeInfo = request.GetQueryOrForm("includeInfo", bool.Parse, false);
  226. IPEndPoint remoteEP = context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader);
  227. UserSession session = await _dnsWebService._authManager.CreateSessionAsync(sessionType, tokenName, username, password, remoteEP.Address, request.Headers.UserAgent);
  228. _dnsWebService._log.Write(remoteEP, "[" + session.User.Username + "] User logged in.");
  229. _dnsWebService._authManager.SaveConfigFile();
  230. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  231. WriteCurrentSessionDetails(jsonWriter, session, includeInfo);
  232. }
  233. public void Logout(HttpContext context)
  234. {
  235. string token = context.Request.GetQueryOrForm("token");
  236. UserSession session = _dnsWebService._authManager.DeleteSession(token);
  237. if (session is not null)
  238. {
  239. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User logged out.");
  240. _dnsWebService._authManager.SaveConfigFile();
  241. }
  242. }
  243. public void GetCurrentSessionDetails(HttpContext context)
  244. {
  245. UserSession session = context.GetCurrentSession();
  246. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  247. WriteCurrentSessionDetails(jsonWriter, session, true);
  248. }
  249. public void ChangePassword(HttpContext context)
  250. {
  251. UserSession session = context.GetCurrentSession();
  252. if (session.Type != UserSessionType.Standard)
  253. throw new DnsWebServiceException("Access was denied.");
  254. string password = context.Request.GetQueryOrForm("pass");
  255. session.User.ChangePassword(password);
  256. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Password was changed successfully.");
  257. _dnsWebService._authManager.SaveConfigFile();
  258. }
  259. public void GetProfile(HttpContext context)
  260. {
  261. UserSession session = context.GetCurrentSession();
  262. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  263. WriteUserDetails(jsonWriter, session.User, session, true, false);
  264. }
  265. public void SetProfile(HttpContext context)
  266. {
  267. UserSession session = context.GetCurrentSession();
  268. if (session.Type != UserSessionType.Standard)
  269. throw new DnsWebServiceException("Access was denied.");
  270. HttpRequest request = context.Request;
  271. if (request.TryGetQueryOrForm("displayName", out string displayName))
  272. session.User.DisplayName = displayName;
  273. if (request.TryGetQueryOrForm("sessionTimeoutSeconds", int.Parse, out int sessionTimeoutSeconds))
  274. session.User.SessionTimeoutSeconds = sessionTimeoutSeconds;
  275. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User profile was updated successfully.");
  276. _dnsWebService._authManager.SaveConfigFile();
  277. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  278. WriteUserDetails(jsonWriter, session.User, session, true, false);
  279. }
  280. public void ListSessions(HttpContext context)
  281. {
  282. UserSession session = context.GetCurrentSession();
  283. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View))
  284. throw new DnsWebServiceException("Access was denied.");
  285. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  286. jsonWriter.WritePropertyName("sessions");
  287. jsonWriter.WriteStartArray();
  288. List<UserSession> sessions = new List<UserSession>(_dnsWebService._authManager.Sessions);
  289. sessions.Sort();
  290. foreach (UserSession activeSession in sessions)
  291. {
  292. if (!activeSession.HasExpired())
  293. WriteUserSessionDetails(jsonWriter, activeSession, session);
  294. }
  295. jsonWriter.WriteEndArray();
  296. }
  297. public void CreateApiToken(HttpContext context)
  298. {
  299. UserSession session = context.GetCurrentSession();
  300. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify))
  301. throw new DnsWebServiceException("Access was denied.");
  302. HttpRequest request = context.Request;
  303. string username = request.GetQueryOrForm("user");
  304. string tokenName = request.GetQueryOrForm("tokenName");
  305. IPEndPoint remoteEP = context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader);
  306. UserSession createdSession = _dnsWebService._authManager.CreateApiToken(tokenName, username, remoteEP.Address, request.Headers.UserAgent);
  307. _dnsWebService._log.Write(remoteEP, "[" + session.User.Username + "] API token [" + tokenName + "] was created successfully for user: " + username);
  308. _dnsWebService._authManager.SaveConfigFile();
  309. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  310. jsonWriter.WriteString("username", createdSession.User.Username);
  311. jsonWriter.WriteString("tokenName", createdSession.TokenName);
  312. jsonWriter.WriteString("token", createdSession.Token);
  313. }
  314. public void DeleteSession(HttpContext context, bool isAdminContext)
  315. {
  316. UserSession session = context.GetCurrentSession();
  317. if (isAdminContext)
  318. {
  319. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete))
  320. throw new DnsWebServiceException("Access was denied.");
  321. }
  322. string strPartialToken = context.Request.GetQueryOrForm("partialToken");
  323. if (session.Token.StartsWith(strPartialToken))
  324. throw new InvalidOperationException("Invalid operation: cannot delete current session.");
  325. string token = null;
  326. foreach (UserSession activeSession in _dnsWebService._authManager.Sessions)
  327. {
  328. if (activeSession.Token.StartsWith(strPartialToken))
  329. {
  330. token = activeSession.Token;
  331. break;
  332. }
  333. }
  334. if (token is null)
  335. throw new DnsWebServiceException("No such active session was found for partial token: " + strPartialToken);
  336. if (!isAdminContext)
  337. {
  338. UserSession sessionToDelete = _dnsWebService._authManager.GetSession(token);
  339. if (sessionToDelete.User != session.User)
  340. throw new DnsWebServiceException("Access was denied.");
  341. }
  342. UserSession deletedSession = _dnsWebService._authManager.DeleteSession(token);
  343. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User session [" + strPartialToken + "] was deleted successfully for user: " + deletedSession.User.Username);
  344. _dnsWebService._authManager.SaveConfigFile();
  345. }
  346. public void ListUsers(HttpContext context)
  347. {
  348. UserSession session = context.GetCurrentSession();
  349. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View))
  350. throw new DnsWebServiceException("Access was denied.");
  351. List<User> users = new List<User>(_dnsWebService._authManager.Users);
  352. users.Sort();
  353. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  354. jsonWriter.WritePropertyName("users");
  355. jsonWriter.WriteStartArray();
  356. foreach (User user in users)
  357. {
  358. jsonWriter.WriteStartObject();
  359. WriteUserDetails(jsonWriter, user, null, false, false);
  360. jsonWriter.WriteEndObject();
  361. }
  362. jsonWriter.WriteEndArray();
  363. }
  364. public void CreateUser(HttpContext context)
  365. {
  366. UserSession session = context.GetCurrentSession();
  367. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify))
  368. throw new DnsWebServiceException("Access was denied.");
  369. HttpRequest request = context.Request;
  370. string displayName = request.QueryOrForm("displayName");
  371. string username = request.GetQueryOrForm("user");
  372. string password = request.GetQueryOrForm("pass");
  373. User user = _dnsWebService._authManager.CreateUser(displayName, username, password);
  374. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User account was created successfully with username: " + user.Username);
  375. _dnsWebService._authManager.SaveConfigFile();
  376. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  377. WriteUserDetails(jsonWriter, user, null, false, false);
  378. }
  379. public void GetUserDetails(HttpContext context)
  380. {
  381. UserSession session = context.GetCurrentSession();
  382. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View))
  383. throw new DnsWebServiceException("Access was denied.");
  384. HttpRequest request = context.Request;
  385. string username = request.GetQueryOrForm("user");
  386. bool includeGroups = request.GetQueryOrForm("includeGroups", bool.Parse, false);
  387. User user = _dnsWebService._authManager.GetUser(username);
  388. if (user is null)
  389. throw new DnsWebServiceException("No such user exists: " + username);
  390. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  391. WriteUserDetails(jsonWriter, user, null, true, includeGroups);
  392. }
  393. public void SetUserDetails(HttpContext context)
  394. {
  395. UserSession session = context.GetCurrentSession();
  396. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify))
  397. throw new DnsWebServiceException("Access was denied.");
  398. HttpRequest request = context.Request;
  399. string username = request.GetQueryOrForm("user");
  400. User user = _dnsWebService._authManager.GetUser(username);
  401. if (user is null)
  402. throw new DnsWebServiceException("No such user exists: " + username);
  403. if (request.TryGetQueryOrForm("displayName", out string displayName))
  404. user.DisplayName = displayName;
  405. if (request.TryGetQueryOrForm("newUser", out string newUsername))
  406. _dnsWebService._authManager.ChangeUsername(user, newUsername);
  407. if (request.TryGetQueryOrForm("disabled", bool.Parse, out bool disabled) && (session.User != user)) //to avoid self lockout
  408. {
  409. user.Disabled = disabled;
  410. if (user.Disabled)
  411. {
  412. foreach (UserSession userSession in _dnsWebService._authManager.Sessions)
  413. {
  414. if (userSession.Type == UserSessionType.ApiToken)
  415. continue;
  416. if (userSession.User == user)
  417. _dnsWebService._authManager.DeleteSession(userSession.Token);
  418. }
  419. }
  420. }
  421. if (request.TryGetQueryOrForm("sessionTimeoutSeconds", int.Parse, out int sessionTimeoutSeconds))
  422. user.SessionTimeoutSeconds = sessionTimeoutSeconds;
  423. string newPassword = request.QueryOrForm("newPass");
  424. if (!string.IsNullOrWhiteSpace(newPassword))
  425. {
  426. int iterations = request.GetQueryOrForm("iterations", int.Parse, User.DEFAULT_ITERATIONS);
  427. user.ChangePassword(newPassword, iterations);
  428. }
  429. string memberOfGroups = request.QueryOrForm("memberOfGroups");
  430. if (memberOfGroups is not null)
  431. {
  432. string[] parts = memberOfGroups.Split(',');
  433. Dictionary<string, Group> groups = new Dictionary<string, Group>(parts.Length);
  434. foreach (string part in parts)
  435. {
  436. if (part.Length == 0)
  437. continue;
  438. Group group = _dnsWebService._authManager.GetGroup(part);
  439. if (group is null)
  440. throw new DnsWebServiceException("No such group exists: " + part);
  441. groups.Add(group.Name.ToLowerInvariant(), group);
  442. }
  443. //ensure user is member of everyone group
  444. Group everyone = _dnsWebService._authManager.GetGroup(Group.EVERYONE);
  445. groups[everyone.Name.ToLowerInvariant()] = everyone;
  446. if (session.User == user)
  447. {
  448. //ensure current admin user is member of administrators group to avoid self lockout
  449. Group admins = _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS);
  450. groups[admins.Name.ToLowerInvariant()] = admins;
  451. }
  452. user.SyncGroups(groups);
  453. }
  454. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User account details were updated successfully for user: " + username);
  455. _dnsWebService._authManager.SaveConfigFile();
  456. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  457. WriteUserDetails(jsonWriter, user, null, true, false);
  458. }
  459. public void DeleteUser(HttpContext context)
  460. {
  461. UserSession session = context.GetCurrentSession();
  462. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete))
  463. throw new DnsWebServiceException("Access was denied.");
  464. string username = context.Request.GetQueryOrForm("user");
  465. if (session.User.Username.Equals(username, StringComparison.OrdinalIgnoreCase))
  466. throw new InvalidOperationException("Invalid operation: cannot delete current user.");
  467. if (!_dnsWebService._authManager.DeleteUser(username))
  468. throw new DnsWebServiceException("Failed to delete user: " + username);
  469. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] User account was deleted successfully with username: " + username);
  470. _dnsWebService._authManager.SaveConfigFile();
  471. }
  472. public void ListGroups(HttpContext context)
  473. {
  474. UserSession session = context.GetCurrentSession();
  475. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View))
  476. throw new DnsWebServiceException("Access was denied.");
  477. List<Group> groups = new List<Group>(_dnsWebService._authManager.Groups);
  478. groups.Sort();
  479. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  480. jsonWriter.WritePropertyName("groups");
  481. jsonWriter.WriteStartArray();
  482. foreach (Group group in groups)
  483. {
  484. if (group.Name.Equals("Everyone", StringComparison.OrdinalIgnoreCase))
  485. continue;
  486. jsonWriter.WriteStartObject();
  487. WriteGroupDetails(jsonWriter, group, false, false);
  488. jsonWriter.WriteEndObject();
  489. }
  490. jsonWriter.WriteEndArray();
  491. }
  492. public void CreateGroup(HttpContext context)
  493. {
  494. UserSession session = context.GetCurrentSession();
  495. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify))
  496. throw new DnsWebServiceException("Access was denied.");
  497. HttpRequest request = context.Request;
  498. string groupName = request.GetQueryOrForm("group");
  499. string description = request.GetQueryOrForm("description", "");
  500. Group group = _dnsWebService._authManager.CreateGroup(groupName, description);
  501. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Group was created successfully with name: " + group.Name);
  502. _dnsWebService._authManager.SaveConfigFile();
  503. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  504. WriteGroupDetails(jsonWriter, group, false, false);
  505. }
  506. public void GetGroupDetails(HttpContext context)
  507. {
  508. UserSession session = context.GetCurrentSession();
  509. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View))
  510. throw new DnsWebServiceException("Access was denied.");
  511. HttpRequest request = context.Request;
  512. string groupName = request.GetQueryOrForm("group");
  513. bool includeUsers = request.GetQueryOrForm("includeUsers", bool.Parse, false);
  514. Group group = _dnsWebService._authManager.GetGroup(groupName);
  515. if (group is null)
  516. throw new DnsWebServiceException("No such group exists: " + groupName);
  517. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  518. WriteGroupDetails(jsonWriter, group, true, includeUsers);
  519. }
  520. public void SetGroupDetails(HttpContext context)
  521. {
  522. UserSession session = context.GetCurrentSession();
  523. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Modify))
  524. throw new DnsWebServiceException("Access was denied.");
  525. HttpRequest request = context.Request;
  526. string groupName = request.GetQueryOrForm("group");
  527. Group group = _dnsWebService._authManager.GetGroup(groupName);
  528. if (group is null)
  529. throw new DnsWebServiceException("No such group exists: " + groupName);
  530. if (request.TryGetQueryOrForm("newGroup", out string newGroup))
  531. _dnsWebService._authManager.RenameGroup(group, newGroup);
  532. if (request.TryGetQueryOrForm("description", out string description))
  533. group.Description = description;
  534. string members = request.QueryOrForm("members");
  535. if (members is not null)
  536. {
  537. string[] parts = members.Split(',');
  538. Dictionary<string, User> users = new Dictionary<string, User>();
  539. foreach (string part in parts)
  540. {
  541. if (part.Length == 0)
  542. continue;
  543. User user = _dnsWebService._authManager.GetUser(part);
  544. if (user is null)
  545. throw new DnsWebServiceException("No such user exists: " + part);
  546. users.Add(user.Username, user);
  547. }
  548. if (group.Name.Equals("administrators", StringComparison.OrdinalIgnoreCase))
  549. users[session.User.Username] = session.User; //ensure current admin user is member of administrators group to avoid self lockout
  550. _dnsWebService._authManager.SyncGroupMembers(group, users);
  551. }
  552. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Group details were updated successfully for group: " + groupName);
  553. _dnsWebService._authManager.SaveConfigFile();
  554. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  555. WriteGroupDetails(jsonWriter, group, true, false);
  556. }
  557. public void DeleteGroup(HttpContext context)
  558. {
  559. UserSession session = context.GetCurrentSession();
  560. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete))
  561. throw new DnsWebServiceException("Access was denied.");
  562. string groupName = context.Request.GetQueryOrForm("group");
  563. if (!_dnsWebService._authManager.DeleteGroup(groupName))
  564. throw new DnsWebServiceException("Failed to delete group: " + groupName);
  565. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Group was deleted successfully with name: " + groupName);
  566. _dnsWebService._authManager.SaveConfigFile();
  567. }
  568. public void ListPermissions(HttpContext context)
  569. {
  570. UserSession session = context.GetCurrentSession();
  571. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View))
  572. throw new DnsWebServiceException("Access was denied.");
  573. List<Permission> permissions = new List<Permission>(_dnsWebService._authManager.Permissions);
  574. permissions.Sort();
  575. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  576. jsonWriter.WritePropertyName("permissions");
  577. jsonWriter.WriteStartArray();
  578. foreach (Permission permission in permissions)
  579. {
  580. jsonWriter.WriteStartObject();
  581. WritePermissionDetails(jsonWriter, permission, null, false);
  582. jsonWriter.WriteEndObject();
  583. }
  584. jsonWriter.WriteEndArray();
  585. }
  586. public void GetPermissionDetails(HttpContext context, PermissionSection section)
  587. {
  588. UserSession session = context.GetCurrentSession();
  589. HttpRequest request = context.Request;
  590. string strSubItem = null;
  591. switch (section)
  592. {
  593. case PermissionSection.Unknown:
  594. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.View))
  595. throw new DnsWebServiceException("Access was denied.");
  596. section = request.GetQueryOrFormEnum<PermissionSection>("section");
  597. break;
  598. case PermissionSection.Zones:
  599. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  600. throw new DnsWebServiceException("Access was denied.");
  601. strSubItem = request.GetQueryOrForm("zone").TrimEnd('.');
  602. break;
  603. default:
  604. throw new InvalidOperationException();
  605. }
  606. bool includeUsersAndGroups = request.GetQueryOrForm("includeUsersAndGroups", bool.Parse, false);
  607. if (strSubItem is not null)
  608. {
  609. if (!_dnsWebService._authManager.IsPermitted(section, strSubItem, session.User, PermissionFlag.View))
  610. throw new DnsWebServiceException("Access was denied.");
  611. }
  612. Permission permission;
  613. if (strSubItem is null)
  614. permission = _dnsWebService._authManager.GetPermission(section);
  615. else
  616. permission = _dnsWebService._authManager.GetPermission(section, strSubItem);
  617. if (permission is null)
  618. throw new DnsWebServiceException("No permissions exists for section: " + section.ToString() + (strSubItem is null ? "" : "/" + strSubItem));
  619. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  620. WritePermissionDetails(jsonWriter, permission, strSubItem, includeUsersAndGroups);
  621. }
  622. public void SetPermissionsDetails(HttpContext context, PermissionSection section)
  623. {
  624. UserSession session = context.GetCurrentSession();
  625. HttpRequest request = context.Request;
  626. string strSubItem = null;
  627. switch (section)
  628. {
  629. case PermissionSection.Unknown:
  630. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Administration, session.User, PermissionFlag.Delete))
  631. throw new DnsWebServiceException("Access was denied.");
  632. section = request.GetQueryOrFormEnum<PermissionSection>("section");
  633. break;
  634. case PermissionSection.Zones:
  635. if (!_dnsWebService._authManager.IsPermitted(PermissionSection.Zones, session.User, PermissionFlag.Modify))
  636. throw new DnsWebServiceException("Access was denied.");
  637. strSubItem = request.GetQueryOrForm("zone").TrimEnd('.');
  638. break;
  639. default:
  640. throw new InvalidOperationException();
  641. }
  642. if (strSubItem is not null)
  643. {
  644. if (!_dnsWebService._authManager.IsPermitted(section, strSubItem, session.User, PermissionFlag.Delete))
  645. throw new DnsWebServiceException("Access was denied.");
  646. }
  647. Permission permission;
  648. if (strSubItem is null)
  649. permission = _dnsWebService._authManager.GetPermission(section);
  650. else
  651. permission = _dnsWebService._authManager.GetPermission(section, strSubItem);
  652. if (permission is null)
  653. throw new DnsWebServiceException("No permissions exists for section: " + section.ToString() + (strSubItem is null ? "" : "/" + strSubItem));
  654. string strUserPermissions = request.QueryOrForm("userPermissions");
  655. if (strUserPermissions is not null)
  656. {
  657. string[] parts = strUserPermissions.Split('|');
  658. Dictionary<User, PermissionFlag> userPermissions = new Dictionary<User, PermissionFlag>();
  659. for (int i = 0; i < parts.Length; i += 4)
  660. {
  661. if (parts[i].Length == 0)
  662. continue;
  663. User user = _dnsWebService._authManager.GetUser(parts[i]);
  664. bool canView = bool.Parse(parts[i + 1]);
  665. bool canModify = bool.Parse(parts[i + 2]);
  666. bool canDelete = bool.Parse(parts[i + 3]);
  667. if (user is not null)
  668. {
  669. PermissionFlag permissionFlag = PermissionFlag.None;
  670. if (canView)
  671. permissionFlag |= PermissionFlag.View;
  672. if (canModify)
  673. permissionFlag |= PermissionFlag.Modify;
  674. if (canDelete)
  675. permissionFlag |= PermissionFlag.Delete;
  676. userPermissions[user] = permissionFlag;
  677. }
  678. }
  679. permission.SyncPermissions(userPermissions);
  680. }
  681. string strGroupPermissions = request.QueryOrForm("groupPermissions");
  682. if (strGroupPermissions is not null)
  683. {
  684. string[] parts = strGroupPermissions.Split('|');
  685. Dictionary<Group, PermissionFlag> groupPermissions = new Dictionary<Group, PermissionFlag>();
  686. for (int i = 0; i < parts.Length; i += 4)
  687. {
  688. if (parts[i].Length == 0)
  689. continue;
  690. Group group = _dnsWebService._authManager.GetGroup(parts[i]);
  691. bool canView = bool.Parse(parts[i + 1]);
  692. bool canModify = bool.Parse(parts[i + 2]);
  693. bool canDelete = bool.Parse(parts[i + 3]);
  694. if (group is not null)
  695. {
  696. PermissionFlag permissionFlag = PermissionFlag.None;
  697. if (canView)
  698. permissionFlag |= PermissionFlag.View;
  699. if (canModify)
  700. permissionFlag |= PermissionFlag.Modify;
  701. if (canDelete)
  702. permissionFlag |= PermissionFlag.Delete;
  703. groupPermissions[group] = permissionFlag;
  704. }
  705. }
  706. //ensure administrators group always has all permissions
  707. Group admins = _dnsWebService._authManager.GetGroup(Group.ADMINISTRATORS);
  708. groupPermissions[admins] = PermissionFlag.ViewModifyDelete;
  709. switch (section)
  710. {
  711. case PermissionSection.Zones:
  712. //ensure DNS administrators group always has all permissions
  713. Group dnsAdmins = _dnsWebService._authManager.GetGroup(Group.DNS_ADMINISTRATORS);
  714. groupPermissions[dnsAdmins] = PermissionFlag.ViewModifyDelete;
  715. break;
  716. case PermissionSection.DhcpServer:
  717. //ensure DHCP administrators group always has all permissions
  718. Group dhcpAdmins = _dnsWebService._authManager.GetGroup(Group.DHCP_ADMINISTRATORS);
  719. groupPermissions[dhcpAdmins] = PermissionFlag.ViewModifyDelete;
  720. break;
  721. }
  722. permission.SyncPermissions(groupPermissions);
  723. }
  724. _dnsWebService._log.Write(context.GetRemoteEndPoint(_dnsWebService._webServiceRealIpHeader), "[" + session.User.Username + "] Permissions were updated successfully for section: " + section.ToString() + (string.IsNullOrEmpty(strSubItem) ? "" : "/" + strSubItem));
  725. _dnsWebService._authManager.SaveConfigFile();
  726. Utf8JsonWriter jsonWriter = context.GetCurrentJsonWriter();
  727. WritePermissionDetails(jsonWriter, permission, strSubItem, false);
  728. }
  729. #endregion
  730. }
  731. }