AuthManager.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  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 System;
  16. using System.Collections.Concurrent;
  17. using System.Collections.Generic;
  18. using System.IO;
  19. using System.Net;
  20. using System.Net.Sockets;
  21. using System.Text;
  22. using System.Threading;
  23. using System.Threading.Tasks;
  24. using TechnitiumLibrary.Net;
  25. namespace DnsServerCore.Auth
  26. {
  27. sealed class AuthManager : IDisposable
  28. {
  29. #region variables
  30. readonly ConcurrentDictionary<string, Group> _groups = new ConcurrentDictionary<string, Group>(1, 4);
  31. readonly ConcurrentDictionary<string, User> _users = new ConcurrentDictionary<string, User>(1, 4);
  32. readonly ConcurrentDictionary<PermissionSection, Permission> _permissions = new ConcurrentDictionary<PermissionSection, Permission>(1, 11);
  33. readonly ConcurrentDictionary<string, UserSession> _sessions = new ConcurrentDictionary<string, UserSession>(1, 10);
  34. readonly ConcurrentDictionary<IPAddress, int> _failedLoginAttemptNetworks = new ConcurrentDictionary<IPAddress, int>(1, 10);
  35. const int MAX_LOGIN_ATTEMPTS = 5;
  36. readonly ConcurrentDictionary<IPAddress, DateTime> _blockedNetworks = new ConcurrentDictionary<IPAddress, DateTime>(1, 10);
  37. const int BLOCK_NETWORK_INTERVAL = 5 * 60 * 1000;
  38. readonly string _configFolder;
  39. readonly LogManager _log;
  40. readonly object _saveLock = new object();
  41. bool _pendingSave;
  42. readonly Timer _saveTimer;
  43. const int SAVE_TIMER_INITIAL_INTERVAL = 10000;
  44. #endregion
  45. #region constructor
  46. public AuthManager(string configFolder, LogManager log)
  47. {
  48. _configFolder = configFolder;
  49. _log = log;
  50. _saveTimer = new Timer(delegate (object state)
  51. {
  52. lock (_saveLock)
  53. {
  54. if (_pendingSave)
  55. {
  56. try
  57. {
  58. SaveConfigFileInternal();
  59. _pendingSave = false;
  60. }
  61. catch (Exception ex)
  62. {
  63. _log.Write(ex);
  64. //set timer to retry again
  65. _saveTimer.Change(SAVE_TIMER_INITIAL_INTERVAL, Timeout.Infinite);
  66. }
  67. }
  68. }
  69. });
  70. }
  71. #endregion
  72. #region IDisposable
  73. bool _disposed;
  74. public void Dispose()
  75. {
  76. if (_disposed)
  77. return;
  78. lock (_saveLock)
  79. {
  80. _saveTimer?.Dispose();
  81. //always save config here
  82. try
  83. {
  84. SaveConfigFileInternal();
  85. }
  86. catch (Exception ex)
  87. {
  88. _log.Write(ex);
  89. }
  90. finally
  91. {
  92. _pendingSave = false;
  93. }
  94. }
  95. _disposed = true;
  96. }
  97. #endregion
  98. #region private
  99. private void CreateDefaultConfig()
  100. {
  101. Group adminGroup = CreateGroup(Group.ADMINISTRATORS, "Super administrators");
  102. Group dnsAdminGroup = CreateGroup(Group.DNS_ADMINISTRATORS, "DNS service administrators");
  103. Group dhcpAdminGroup = CreateGroup(Group.DHCP_ADMINISTRATORS, "DHCP service administrators");
  104. Group everyoneGroup = CreateGroup(Group.EVERYONE, "All users");
  105. SetPermission(PermissionSection.Dashboard, adminGroup, PermissionFlag.ViewModifyDelete);
  106. SetPermission(PermissionSection.Zones, adminGroup, PermissionFlag.ViewModifyDelete);
  107. SetPermission(PermissionSection.Cache, adminGroup, PermissionFlag.ViewModifyDelete);
  108. SetPermission(PermissionSection.Allowed, adminGroup, PermissionFlag.ViewModifyDelete);
  109. SetPermission(PermissionSection.Blocked, adminGroup, PermissionFlag.ViewModifyDelete);
  110. SetPermission(PermissionSection.Apps, adminGroup, PermissionFlag.ViewModifyDelete);
  111. SetPermission(PermissionSection.DnsClient, adminGroup, PermissionFlag.ViewModifyDelete);
  112. SetPermission(PermissionSection.Settings, adminGroup, PermissionFlag.ViewModifyDelete);
  113. SetPermission(PermissionSection.DhcpServer, adminGroup, PermissionFlag.ViewModifyDelete);
  114. SetPermission(PermissionSection.Administration, adminGroup, PermissionFlag.ViewModifyDelete);
  115. SetPermission(PermissionSection.Logs, adminGroup, PermissionFlag.ViewModifyDelete);
  116. SetPermission(PermissionSection.Zones, dnsAdminGroup, PermissionFlag.ViewModifyDelete);
  117. SetPermission(PermissionSection.Cache, dnsAdminGroup, PermissionFlag.ViewModifyDelete);
  118. SetPermission(PermissionSection.Allowed, dnsAdminGroup, PermissionFlag.ViewModifyDelete);
  119. SetPermission(PermissionSection.Blocked, dnsAdminGroup, PermissionFlag.ViewModifyDelete);
  120. SetPermission(PermissionSection.Apps, dnsAdminGroup, PermissionFlag.ViewModifyDelete);
  121. SetPermission(PermissionSection.DnsClient, dnsAdminGroup, PermissionFlag.ViewModifyDelete);
  122. SetPermission(PermissionSection.Settings, dnsAdminGroup, PermissionFlag.ViewModifyDelete);
  123. SetPermission(PermissionSection.DhcpServer, dhcpAdminGroup, PermissionFlag.ViewModifyDelete);
  124. SetPermission(PermissionSection.Dashboard, everyoneGroup, PermissionFlag.View);
  125. SetPermission(PermissionSection.Zones, everyoneGroup, PermissionFlag.View);
  126. SetPermission(PermissionSection.Cache, everyoneGroup, PermissionFlag.View);
  127. SetPermission(PermissionSection.Allowed, everyoneGroup, PermissionFlag.View);
  128. SetPermission(PermissionSection.Blocked, everyoneGroup, PermissionFlag.View);
  129. SetPermission(PermissionSection.Apps, everyoneGroup, PermissionFlag.View);
  130. SetPermission(PermissionSection.DnsClient, everyoneGroup, PermissionFlag.View);
  131. SetPermission(PermissionSection.DhcpServer, everyoneGroup, PermissionFlag.View);
  132. SetPermission(PermissionSection.Logs, everyoneGroup, PermissionFlag.View);
  133. string adminPassword = Environment.GetEnvironmentVariable("DNS_SERVER_ADMIN_PASSWORD");
  134. string adminPasswordFile = Environment.GetEnvironmentVariable("DNS_SERVER_ADMIN_PASSWORD_FILE");
  135. User adminUser;
  136. if (!string.IsNullOrEmpty(adminPassword))
  137. {
  138. adminUser = CreateUser("Administrator", "admin", adminPassword);
  139. }
  140. else if (!string.IsNullOrEmpty(adminPasswordFile))
  141. {
  142. try
  143. {
  144. using (StreamReader sR = new StreamReader(adminPasswordFile, true))
  145. {
  146. string password = sR.ReadLine();
  147. adminUser = CreateUser("Administrator", "admin", password);
  148. }
  149. }
  150. catch (Exception ex)
  151. {
  152. _log.Write(ex);
  153. adminUser = CreateUser("Administrator", "admin", "admin");
  154. }
  155. }
  156. else
  157. {
  158. adminUser = CreateUser("Administrator", "admin", "admin");
  159. }
  160. adminUser.AddToGroup(adminGroup);
  161. }
  162. private void LoadConfigFileInternal(UserSession implantSession)
  163. {
  164. string configFile = Path.Combine(_configFolder, "auth.config");
  165. try
  166. {
  167. bool passwordResetOption = false;
  168. if (!File.Exists(configFile))
  169. {
  170. string passwordResetConfigFile = Path.Combine(_configFolder, "resetadmin.config");
  171. if (File.Exists(passwordResetConfigFile))
  172. {
  173. passwordResetOption = true;
  174. configFile = passwordResetConfigFile;
  175. }
  176. }
  177. using (FileStream fS = new FileStream(configFile, FileMode.Open, FileAccess.Read))
  178. {
  179. ReadConfigFrom(new BinaryReader(fS));
  180. }
  181. if (implantSession is not null)
  182. {
  183. using (MemoryStream mS = new MemoryStream())
  184. {
  185. //implant current user
  186. implantSession.User.WriteTo(new BinaryWriter(mS));
  187. mS.Position = 0;
  188. User newUser = new User(new BinaryReader(mS), this);
  189. newUser.AddToGroup(GetGroup(Group.ADMINISTRATORS));
  190. _users[newUser.Username] = newUser;
  191. //implant current session
  192. mS.SetLength(0);
  193. implantSession.WriteTo(new BinaryWriter(mS));
  194. mS.Position = 0;
  195. UserSession newSession = new UserSession(new BinaryReader(mS), this);
  196. _sessions.TryAdd(newSession.Token, newSession);
  197. //save config
  198. SaveConfigFileInternal();
  199. }
  200. }
  201. _log.Write("DNS Server auth config file was loaded: " + configFile);
  202. if (passwordResetOption)
  203. {
  204. User adminUser = GetUser("admin");
  205. if (adminUser is null)
  206. {
  207. adminUser = CreateUser("Administrator", "admin", "admin");
  208. }
  209. else
  210. {
  211. adminUser.ChangePassword("admin");
  212. adminUser.Disabled = false;
  213. }
  214. adminUser.AddToGroup(GetGroup(Group.ADMINISTRATORS));
  215. _log.Write("DNS Server reset password for user: admin");
  216. SaveConfigFileInternal();
  217. try
  218. {
  219. File.Delete(configFile);
  220. }
  221. catch
  222. { }
  223. }
  224. }
  225. catch (FileNotFoundException)
  226. {
  227. _log.Write("DNS Server auth config file was not found: " + configFile);
  228. _log.Write("DNS Server is restoring default auth config file.");
  229. CreateDefaultConfig();
  230. SaveConfigFileInternal();
  231. }
  232. catch (Exception ex)
  233. {
  234. _log.Write("DNS Server encountered an error while loading auth config file: " + configFile + "\r\n" + ex.ToString());
  235. _log.Write("Note: You may try deleting the auth config file to fix this issue. However, you will lose auth settings but, rest of the DNS settings and zone data wont be affected.");
  236. throw;
  237. }
  238. }
  239. private void SaveConfigFileInternal()
  240. {
  241. string configFile = Path.Combine(_configFolder, "auth.config");
  242. using (MemoryStream mS = new MemoryStream())
  243. {
  244. //serialize config
  245. WriteConfigTo(new BinaryWriter(mS));
  246. //write config
  247. mS.Position = 0;
  248. using (FileStream fS = new FileStream(configFile, FileMode.Create, FileAccess.Write))
  249. {
  250. mS.CopyTo(fS);
  251. }
  252. }
  253. _log.Write("DNS Server auth config file was saved: " + configFile);
  254. }
  255. private void ReadConfigFrom(BinaryReader bR)
  256. {
  257. if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "AS") //format
  258. throw new InvalidDataException("DNS Server auth config file format is invalid.");
  259. int version = bR.ReadByte();
  260. switch (version)
  261. {
  262. case 1:
  263. {
  264. int count = bR.ReadByte();
  265. for (int i = 0; i < count; i++)
  266. {
  267. Group group = new Group(bR);
  268. _groups.TryAdd(group.Name.ToLowerInvariant(), group);
  269. }
  270. }
  271. {
  272. int count = bR.ReadByte();
  273. for (int i = 0; i < count; i++)
  274. {
  275. User user = new User(bR, this);
  276. _users.TryAdd(user.Username, user);
  277. }
  278. }
  279. {
  280. int count = bR.ReadInt32();
  281. for (int i = 0; i < count; i++)
  282. {
  283. Permission permission = new Permission(bR, this);
  284. _permissions.TryAdd(permission.Section, permission);
  285. }
  286. }
  287. {
  288. int count = bR.ReadInt32();
  289. for (int i = 0; i < count; i++)
  290. {
  291. UserSession session = new UserSession(bR, this);
  292. if (!session.HasExpired())
  293. _sessions.TryAdd(session.Token, session);
  294. }
  295. }
  296. break;
  297. default:
  298. throw new InvalidDataException("DNS Server auth config version not supported.");
  299. }
  300. }
  301. private void WriteConfigTo(BinaryWriter bW)
  302. {
  303. bW.Write(Encoding.ASCII.GetBytes("AS")); //format
  304. bW.Write((byte)1); //version
  305. bW.Write(Convert.ToByte(_groups.Count));
  306. foreach (KeyValuePair<string, Group> group in _groups)
  307. group.Value.WriteTo(bW);
  308. bW.Write(Convert.ToByte(_users.Count));
  309. foreach (KeyValuePair<string, User> user in _users)
  310. user.Value.WriteTo(bW);
  311. bW.Write(_permissions.Count);
  312. foreach (KeyValuePair<PermissionSection, Permission> permission in _permissions)
  313. permission.Value.WriteTo(bW);
  314. List<UserSession> activeSessions = new List<UserSession>(_sessions.Count);
  315. foreach (KeyValuePair<string, UserSession> session in _sessions)
  316. {
  317. if (session.Value.HasExpired())
  318. _sessions.TryRemove(session.Key, out _);
  319. else
  320. activeSessions.Add(session.Value);
  321. }
  322. bW.Write(activeSessions.Count);
  323. foreach (UserSession session in activeSessions)
  324. session.WriteTo(bW);
  325. }
  326. private static IPAddress GetClientNetwork(IPAddress address)
  327. {
  328. switch (address.AddressFamily)
  329. {
  330. case AddressFamily.InterNetwork:
  331. return address.GetNetworkAddress(32);
  332. case AddressFamily.InterNetworkV6:
  333. return address.GetNetworkAddress(64);
  334. default:
  335. throw new InvalidOperationException();
  336. }
  337. }
  338. private void MarkFailedLoginAttempt(IPAddress network)
  339. {
  340. _failedLoginAttemptNetworks.AddOrUpdate(network, 1, delegate (IPAddress key, int attempts)
  341. {
  342. return attempts + 1;
  343. });
  344. }
  345. private bool HasLoginAttemptExceedLimit(IPAddress network, int limit)
  346. {
  347. if (!_failedLoginAttemptNetworks.TryGetValue(network, out int attempts))
  348. return false;
  349. return attempts >= limit;
  350. }
  351. private void ResetFailedLoginAttempts(IPAddress network)
  352. {
  353. _failedLoginAttemptNetworks.TryRemove(network, out _);
  354. }
  355. private void BlockNetwork(IPAddress network, int interval)
  356. {
  357. _blockedNetworks.TryAdd(network, DateTime.UtcNow.AddMilliseconds(interval));
  358. }
  359. private bool IsNetworkBlocked(IPAddress network)
  360. {
  361. if (!_blockedNetworks.TryGetValue(network, out DateTime expiry))
  362. return false;
  363. if (expiry > DateTime.UtcNow)
  364. {
  365. return true;
  366. }
  367. else
  368. {
  369. UnblockNetwork(network);
  370. ResetFailedLoginAttempts(network);
  371. return false;
  372. }
  373. }
  374. private void UnblockNetwork(IPAddress network)
  375. {
  376. _blockedNetworks.TryRemove(network, out _);
  377. }
  378. #endregion
  379. #region public
  380. public User GetUser(string username)
  381. {
  382. if (_users.TryGetValue(username.ToLowerInvariant(), out User user))
  383. return user;
  384. return null;
  385. }
  386. public User CreateUser(string displayName, string username, string password, int iterations = User.DEFAULT_ITERATIONS)
  387. {
  388. if (_users.Count >= byte.MaxValue)
  389. throw new DnsWebServiceException("Cannot create more than 255 users.");
  390. username = username.ToLowerInvariant();
  391. User user = new User(displayName, username, password, iterations);
  392. if (_users.TryAdd(username, user))
  393. {
  394. user.AddToGroup(GetGroup(Group.EVERYONE));
  395. return user;
  396. }
  397. throw new DnsWebServiceException("User already exists: " + username);
  398. }
  399. public void ChangeUsername(User user, string newUsername)
  400. {
  401. if (user.Username.Equals(newUsername, StringComparison.OrdinalIgnoreCase))
  402. return;
  403. string oldUsername = user.Username;
  404. user.Username = newUsername;
  405. if (!_users.TryAdd(user.Username, user))
  406. {
  407. user.Username = oldUsername; //revert
  408. throw new DnsWebServiceException("User already exists: " + newUsername);
  409. }
  410. _users.TryRemove(oldUsername, out _);
  411. }
  412. public bool DeleteUser(string username)
  413. {
  414. if (_users.TryRemove(username.ToLowerInvariant(), out User deletedUser))
  415. {
  416. //delete all sessions
  417. foreach (UserSession session in GetSessions(deletedUser))
  418. DeleteSession(session.Token);
  419. //delete all permissions
  420. foreach (KeyValuePair<PermissionSection, Permission> permission in _permissions)
  421. {
  422. permission.Value.RemovePermission(deletedUser);
  423. permission.Value.RemoveAllSubItemPermissions(deletedUser);
  424. }
  425. return true;
  426. }
  427. return false;
  428. }
  429. public Group GetGroup(string name)
  430. {
  431. if (_groups.TryGetValue(name.ToLowerInvariant(), out Group group))
  432. return group;
  433. return null;
  434. }
  435. public List<User> GetGroupMembers(Group group)
  436. {
  437. List<User> members = new List<User>();
  438. foreach (KeyValuePair<string, User> user in _users)
  439. {
  440. if (user.Value.IsMemberOfGroup(group))
  441. members.Add(user.Value);
  442. }
  443. return members;
  444. }
  445. public void SyncGroupMembers(Group group, IReadOnlyDictionary<string, User> users)
  446. {
  447. //remove
  448. foreach (KeyValuePair<string, User> user in _users)
  449. {
  450. if (!users.ContainsKey(user.Key))
  451. user.Value.RemoveFromGroup(group);
  452. }
  453. //set
  454. foreach (KeyValuePair<string, User> user in users)
  455. user.Value.AddToGroup(group);
  456. }
  457. public Group CreateGroup(string name, string description)
  458. {
  459. if (_groups.Count >= byte.MaxValue)
  460. throw new DnsWebServiceException("Cannot create more than 255 groups.");
  461. Group group = new Group(name, description);
  462. if (_groups.TryAdd(name.ToLowerInvariant(), group))
  463. return group;
  464. throw new DnsWebServiceException("Group already exists: " + name);
  465. }
  466. public void RenameGroup(Group group, string newGroupName)
  467. {
  468. if (group.Name.Equals(newGroupName, StringComparison.OrdinalIgnoreCase))
  469. {
  470. group.Name = newGroupName;
  471. return;
  472. }
  473. string oldGroupName = group.Name;
  474. group.Name = newGroupName;
  475. if (!_groups.TryAdd(group.Name.ToLowerInvariant(), group))
  476. {
  477. group.Name = oldGroupName; //revert
  478. throw new DnsWebServiceException("Group already exists: " + newGroupName);
  479. }
  480. _groups.TryRemove(oldGroupName.ToLowerInvariant(), out _);
  481. //update users
  482. foreach (KeyValuePair<string, User> user in _users)
  483. user.Value.RenameGroup(oldGroupName);
  484. }
  485. public bool DeleteGroup(string name)
  486. {
  487. name = name.ToLowerInvariant();
  488. switch (name)
  489. {
  490. case "everyone":
  491. case "administrators":
  492. case "dns administrators":
  493. case "dhcp administrators":
  494. throw new InvalidOperationException("Access was denied.");
  495. default:
  496. if (_groups.TryRemove(name, out Group deletedGroup))
  497. {
  498. //remove all users from deleted group
  499. foreach (KeyValuePair<string, User> user in _users)
  500. user.Value.RemoveFromGroup(deletedGroup);
  501. //delete all permissions
  502. foreach (KeyValuePair<PermissionSection, Permission> permission in _permissions)
  503. {
  504. permission.Value.RemovePermission(deletedGroup);
  505. permission.Value.RemoveAllSubItemPermissions(deletedGroup);
  506. }
  507. return true;
  508. }
  509. return false;
  510. }
  511. }
  512. public UserSession GetSession(string token)
  513. {
  514. if (_sessions.TryGetValue(token, out UserSession session))
  515. return session;
  516. return null;
  517. }
  518. public List<UserSession> GetSessions(User user)
  519. {
  520. List<UserSession> userSessions = new List<UserSession>();
  521. foreach (KeyValuePair<string, UserSession> session in _sessions)
  522. {
  523. if (session.Value.User.Equals(user) && !session.Value.HasExpired())
  524. userSessions.Add(session.Value);
  525. }
  526. return userSessions;
  527. }
  528. public async Task<UserSession> CreateSessionAsync(UserSessionType type, string tokenName, string username, string password, IPAddress remoteAddress, string userAgent)
  529. {
  530. IPAddress network = GetClientNetwork(remoteAddress);
  531. if (IsNetworkBlocked(network))
  532. throw new DnsWebServiceException("Max limit of " + MAX_LOGIN_ATTEMPTS + " attempts exceeded. Access blocked for " + (BLOCK_NETWORK_INTERVAL / 1000) + " seconds.");
  533. User user = GetUser(username);
  534. if ((user is null) || !user.PasswordHash.Equals(user.GetPasswordHashFor(password), StringComparison.Ordinal))
  535. {
  536. if (password != "admin")
  537. {
  538. MarkFailedLoginAttempt(network);
  539. if (HasLoginAttemptExceedLimit(network, MAX_LOGIN_ATTEMPTS))
  540. BlockNetwork(network, BLOCK_NETWORK_INTERVAL);
  541. await Task.Delay(1000);
  542. }
  543. throw new DnsWebServiceException("Invalid username or password for user: " + username);
  544. }
  545. ResetFailedLoginAttempts(network);
  546. if (user.Disabled)
  547. throw new DnsWebServiceException("User account is disabled. Please contact your administrator.");
  548. UserSession session = new UserSession(type, tokenName, user, remoteAddress, userAgent);
  549. if (!_sessions.TryAdd(session.Token, session))
  550. throw new DnsWebServiceException("Error while creating session. Please try again.");
  551. user.LoggedInFrom(remoteAddress);
  552. return session;
  553. }
  554. public UserSession CreateApiToken(string tokenName, string username, IPAddress remoteAddress, string userAgent)
  555. {
  556. User user = GetUser(username);
  557. if (user is null)
  558. throw new DnsWebServiceException("No such user exists: " + username);
  559. if (user.Disabled)
  560. throw new DnsWebServiceException("Account is suspended.");
  561. UserSession session = new UserSession(UserSessionType.ApiToken, tokenName, user, remoteAddress, userAgent);
  562. if (!_sessions.TryAdd(session.Token, session))
  563. throw new DnsWebServiceException("Error while creating session. Please try again.");
  564. user.LoggedInFrom(remoteAddress);
  565. return session;
  566. }
  567. public UserSession DeleteSession(string token)
  568. {
  569. if (_sessions.TryRemove(token, out UserSession session))
  570. return session;
  571. return null;
  572. }
  573. public Permission GetPermission(PermissionSection section)
  574. {
  575. if (_permissions.TryGetValue(section, out Permission permission))
  576. return permission;
  577. return null;
  578. }
  579. public Permission GetPermission(PermissionSection section, string subItemName)
  580. {
  581. if (_permissions.TryGetValue(section, out Permission permission))
  582. return permission.GetSubItemPermission(subItemName);
  583. return null;
  584. }
  585. public void SetPermission(PermissionSection section, User user, PermissionFlag flags)
  586. {
  587. Permission permission = _permissions.GetOrAdd(section, delegate (PermissionSection key)
  588. {
  589. return new Permission(key);
  590. });
  591. permission.SetPermission(user, flags);
  592. }
  593. public void SetPermission(PermissionSection section, string subItemName, User user, PermissionFlag flags)
  594. {
  595. Permission permission = _permissions.GetOrAdd(section, delegate (PermissionSection key)
  596. {
  597. return new Permission(key);
  598. });
  599. permission.SetSubItemPermission(subItemName, user, flags);
  600. }
  601. public void SetPermission(PermissionSection section, Group group, PermissionFlag flags)
  602. {
  603. Permission permission = _permissions.GetOrAdd(section, delegate (PermissionSection key)
  604. {
  605. return new Permission(key);
  606. });
  607. permission.SetPermission(group, flags);
  608. }
  609. public void SetPermission(PermissionSection section, string subItemName, Group group, PermissionFlag flags)
  610. {
  611. Permission permission = _permissions.GetOrAdd(section, delegate (PermissionSection key)
  612. {
  613. return new Permission(key);
  614. });
  615. permission.SetSubItemPermission(subItemName, group, flags);
  616. }
  617. public bool RemovePermission(PermissionSection section, User user)
  618. {
  619. return _permissions.TryGetValue(section, out Permission permission) && permission.RemovePermission(user);
  620. }
  621. public bool RemovePermission(PermissionSection section, string subItemName, User user)
  622. {
  623. return _permissions.TryGetValue(section, out Permission permission) && permission.RemoveSubItemPermission(subItemName, user);
  624. }
  625. public bool RemovePermission(PermissionSection section, Group group)
  626. {
  627. return _permissions.TryGetValue(section, out Permission permission) && permission.RemovePermission(group);
  628. }
  629. public bool RemovePermission(PermissionSection section, string subItemName, Group group)
  630. {
  631. return _permissions.TryGetValue(section, out Permission permission) && permission.RemoveSubItemPermission(subItemName, group);
  632. }
  633. public bool RemoveAllPermissions(PermissionSection section, string subItemName)
  634. {
  635. return _permissions.TryGetValue(section, out Permission permission) && permission.RemoveAllSubItemPermissions(subItemName);
  636. }
  637. public bool IsPermitted(PermissionSection section, User user, PermissionFlag flag)
  638. {
  639. return _permissions.TryGetValue(section, out Permission permission) && permission.IsPermitted(user, flag);
  640. }
  641. public bool IsPermitted(PermissionSection section, string subItemName, User user, PermissionFlag flag)
  642. {
  643. return _permissions.TryGetValue(section, out Permission permission) && permission.IsSubItemPermitted(subItemName, user, flag);
  644. }
  645. public void LoadOldConfig(string password, bool isPasswordHash)
  646. {
  647. User user = GetUser("admin");
  648. if (user is null)
  649. user = CreateUser("Administrator", "admin", "admin");
  650. user.AddToGroup(GetGroup(Group.ADMINISTRATORS));
  651. if (isPasswordHash)
  652. user.LoadOldSchemeCredentials(password);
  653. else
  654. user.ChangePassword(password);
  655. lock (_saveLock)
  656. {
  657. SaveConfigFileInternal();
  658. }
  659. }
  660. public void LoadConfigFile(UserSession implantSession = null)
  661. {
  662. lock (_saveLock)
  663. {
  664. _groups.Clear();
  665. _users.Clear();
  666. _permissions.Clear();
  667. _sessions.Clear();
  668. LoadConfigFileInternal(implantSession);
  669. }
  670. }
  671. public void SaveConfigFile()
  672. {
  673. lock (_saveLock)
  674. {
  675. if (_pendingSave)
  676. return;
  677. _pendingSave = true;
  678. _saveTimer.Change(SAVE_TIMER_INITIAL_INTERVAL, Timeout.Infinite);
  679. }
  680. }
  681. #endregion
  682. #region properties
  683. public ICollection<Group> Groups
  684. { get { return _groups.Values; } }
  685. public ICollection<User> Users
  686. { get { return _users.Values; } }
  687. public ICollection<Permission> Permissions
  688. { get { return _permissions.Values; } }
  689. public ICollection<UserSession> Sessions
  690. { get { return _sessions.Values; } }
  691. #endregion
  692. }
  693. }