AuthManager.cs 30 KB

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