The next generation of the Teknik Services. Written in ASP.NET. https://www.teknik.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ManageController.cs 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using IdentityServer4;
  7. using IdentityServer4.Configuration;
  8. using IdentityServer4.EntityFramework.DbContexts;
  9. using IdentityServer4.EntityFramework.Entities;
  10. using IdentityServer4.EntityFramework.Mappers;
  11. using IdentityServer4.Models;
  12. using IdentityServer4.Services;
  13. using IdentityServer4.Stores;
  14. using Microsoft.AspNetCore.Authorization;
  15. using Microsoft.AspNetCore.Identity;
  16. using Microsoft.AspNetCore.Mvc;
  17. using Microsoft.EntityFrameworkCore;
  18. using Microsoft.EntityFrameworkCore.Internal;
  19. using Microsoft.Extensions.Caching.Memory;
  20. using Microsoft.Extensions.Logging;
  21. using Newtonsoft.Json.Linq;
  22. using Teknik.Configuration;
  23. using Teknik.IdentityServer.Models;
  24. using Teknik.IdentityServer.Models.Manage;
  25. using Teknik.IdentityServer.Services;
  26. using Teknik.Logging;
  27. using Teknik.Utilities;
  28. namespace Teknik.IdentityServer.Controllers
  29. {
  30. [Authorize(Policy = "Internal", AuthenticationSchemes = "Bearer")]
  31. [Route("[controller]/[action]")]
  32. [ApiController]
  33. public class ManageController : DefaultController
  34. {
  35. private const string _KeySeparator = ":";
  36. private const string _UserInfoCacheKey = "UserInfo";
  37. private readonly UserManager<ApplicationUser> _userManager;
  38. private readonly SignInManager<ApplicationUser> _signInManager;
  39. private readonly IMemoryCache _cache;
  40. public ManageController(
  41. ILogger<Logger> logger,
  42. Config config,
  43. UserManager<ApplicationUser> userManager,
  44. SignInManager<ApplicationUser> signInManager,
  45. IMemoryCache cache) : base(logger, config)
  46. {
  47. _userManager = userManager;
  48. _signInManager = signInManager;
  49. _cache = cache;
  50. }
  51. [HttpPost]
  52. public async Task<IActionResult> CreateUser(NewUserModel model)
  53. {
  54. if (string.IsNullOrEmpty(model.Username))
  55. return new JsonResult(new { success = false, message = "Username is required" });
  56. if (string.IsNullOrEmpty(model.Password))
  57. return new JsonResult(new { success = false, message = "Password is required" });
  58. var identityUser = new ApplicationUser(model.Username)
  59. {
  60. Id = Guid.NewGuid().ToString(),
  61. UserName = model.Username,
  62. AccountStatus = model.AccountStatus,
  63. AccountType = model.AccountType,
  64. Email = model.RecoveryEmail,
  65. EmailConfirmed = model.RecoveryVerified,
  66. PGPPublicKey = model.PGPPublicKey
  67. };
  68. var result = await _userManager.CreateAsync(identityUser, model.Password);
  69. if (result.Succeeded)
  70. {
  71. return new JsonResult(new { success = true });
  72. }
  73. return new JsonResult(new { success = false, message = "Unable to create user.", identityErrors = result.Errors });
  74. }
  75. [HttpPost]
  76. public async Task<IActionResult> DeleteUser(DeleteUserModel model, [FromServices] ConfigurationDbContext configContext)
  77. {
  78. if (string.IsNullOrEmpty(model.Username))
  79. return new JsonResult(new { success = false, message = "Username is required" });
  80. var foundUser = await _userManager.FindByNameAsync(model.Username);
  81. if (foundUser != null)
  82. {
  83. // Find this user's clients
  84. var foundClients = configContext.Clients.Where(c =>
  85. c.Properties.Exists(p =>
  86. p.Key == "username" &&
  87. p.Value.ToLower() == model.Username.ToLower())
  88. ).ToList();
  89. if (foundClients != null)
  90. {
  91. configContext.Clients.RemoveRange(foundClients);
  92. configContext.SaveChanges();
  93. }
  94. var result = await _userManager.DeleteAsync(foundUser);
  95. if (result.Succeeded)
  96. {
  97. RemoveCachedUser(model.Username);
  98. return new JsonResult(new { success = true });
  99. }
  100. else
  101. return new JsonResult(new { success = false, message = "Unable to delete user.", identityErrors = result.Errors });
  102. }
  103. return new JsonResult(new { success = false, message = "User does not exist." });
  104. }
  105. [HttpGet]
  106. public async Task<IActionResult> UserExists(string username)
  107. {
  108. if (string.IsNullOrEmpty(username))
  109. return new JsonResult(new { success = false, message = "Username is required" });
  110. var foundUser = await _userManager.FindByNameAsync(username);
  111. return new JsonResult(new { success = true, data = foundUser != null });
  112. }
  113. [HttpGet]
  114. public async Task<IActionResult> GetUserInfo(string username)
  115. {
  116. if (string.IsNullOrEmpty(username))
  117. return new JsonResult(new { success = false, message = "Username is required" });
  118. var foundUser = await GetCachedUser(username);
  119. if (foundUser != null)
  120. {
  121. return new JsonResult(new { success = true, data = foundUser.ToJson() });
  122. }
  123. return new JsonResult(new { success = false, message = "User does not exist." });
  124. }
  125. [HttpPost]
  126. public async Task<IActionResult> CheckPassword(CheckPasswordModel model)
  127. {
  128. if (string.IsNullOrEmpty(model.Username))
  129. return new JsonResult(new { success = false, message = "Username is required" });
  130. if (string.IsNullOrEmpty(model.Password))
  131. return new JsonResult(new { success = false, message = "Password is required" });
  132. var foundUser = await _userManager.FindByNameAsync(model.Username);
  133. if (foundUser != null)
  134. {
  135. bool valid = await _userManager.CheckPasswordAsync(foundUser, model.Password);
  136. return new JsonResult(new { success = true, data = valid });
  137. }
  138. return new JsonResult(new { success = false, message = "User does not exist." });
  139. }
  140. [HttpPost]
  141. public async Task<IActionResult> GeneratePasswordResetToken(GeneratePasswordResetTokenModel model)
  142. {
  143. if (string.IsNullOrEmpty(model.Username))
  144. return new JsonResult(new { success = false, message = "Username is required" });
  145. var foundUser = await _userManager.FindByNameAsync(model.Username);
  146. if (foundUser != null)
  147. {
  148. string token = await _userManager.GeneratePasswordResetTokenAsync(foundUser);
  149. return new JsonResult(new { success = true, data = token });
  150. }
  151. return new JsonResult(new { success = false, message = "User does not exist." });
  152. }
  153. [HttpPost]
  154. public async Task<IActionResult> ResetPassword(ResetPasswordModel model)
  155. {
  156. if (string.IsNullOrEmpty(model.Username))
  157. return new JsonResult(new { success = false, message = "Username is required" });
  158. if (string.IsNullOrEmpty(model.Token))
  159. return new JsonResult(new { success = false, message = "Token is required" });
  160. if (string.IsNullOrEmpty(model.Password))
  161. return new JsonResult(new { success = false, message = "Password is required" });
  162. var foundUser = await _userManager.FindByNameAsync(model.Username);
  163. if (foundUser != null)
  164. {
  165. var result = await _userManager.ResetPasswordAsync(foundUser, model.Token, model.Password);
  166. if (result.Succeeded)
  167. return new JsonResult(new { success = true });
  168. else
  169. return new JsonResult(new { success = false, message = "Unable to reset password.", identityErrors = result.Errors });
  170. }
  171. return new JsonResult(new { success = false, message = "User does not exist." });
  172. }
  173. [HttpPost]
  174. public async Task<IActionResult> UpdatePassword(UpdatePasswordModel model)
  175. {
  176. if (string.IsNullOrEmpty(model.Username))
  177. return new JsonResult(new { success = false, message = "Username is required" });
  178. if (string.IsNullOrEmpty(model.CurrentPassword))
  179. return new JsonResult(new { success = false, message = "Current Password is required" });
  180. if (string.IsNullOrEmpty(model.NewPassword))
  181. return new JsonResult(new { success = false, message = "New Password is required" });
  182. var foundUser = await _userManager.FindByNameAsync(model.Username);
  183. if (foundUser != null)
  184. {
  185. var result = await _userManager.ChangePasswordAsync(foundUser, model.CurrentPassword, model.NewPassword);
  186. if (result.Succeeded)
  187. return new JsonResult(new { success = true });
  188. else
  189. return new JsonResult(new { success = false, message = "Unable to update password.", identityErrors = result.Errors });
  190. }
  191. return new JsonResult(new { success = false, message = "User does not exist." });
  192. }
  193. [HttpPost]
  194. public async Task<IActionResult> UpdateEmail(UpdateEmailModel model)
  195. {
  196. if (string.IsNullOrEmpty(model.Username))
  197. return new JsonResult(new { success = false, message = "Username is required" });
  198. var foundUser = await _userManager.FindByNameAsync(model.Username);
  199. if (foundUser != null)
  200. {
  201. var result = await _userManager.SetEmailAsync(foundUser, model.Email);
  202. if (result.Succeeded)
  203. {
  204. // Remove the UserInfo Cache
  205. RemoveCachedUser(model.Username);
  206. var token = await _userManager.GenerateEmailConfirmationTokenAsync(foundUser);
  207. return new JsonResult(new { success = true, data = token });
  208. }
  209. else
  210. return new JsonResult(new { success = false, message = "Unable to update email address.", identityErrors = result.Errors });
  211. }
  212. return new JsonResult(new { success = false, message = "User does not exist." });
  213. }
  214. [HttpPost]
  215. public async Task<IActionResult> VerifyEmail(VerifyEmailModel model)
  216. {
  217. if (string.IsNullOrEmpty(model.Username))
  218. return new JsonResult(new { success = false, message = "Username is required" });
  219. if (string.IsNullOrEmpty(model.Token))
  220. return new JsonResult(new { success = false, message = "Token is required" });
  221. var foundUser = await _userManager.FindByNameAsync(model.Username);
  222. if (foundUser != null)
  223. {
  224. // Remove the UserInfo Cache
  225. RemoveCachedUser(model.Username);
  226. var result = await _userManager.ConfirmEmailAsync(foundUser, model.Token);
  227. if (result.Succeeded)
  228. return new JsonResult(new { success = true });
  229. else
  230. return new JsonResult(new { success = false, message = "Unable to verify email address.", identityErrors = result.Errors });
  231. }
  232. return new JsonResult(new { success = false, message = "User does not exist." });
  233. }
  234. [HttpPost]
  235. public async Task<IActionResult> UpdateAccountStatus(UpdateAccountStatusModel model)
  236. {
  237. if (string.IsNullOrEmpty(model.Username))
  238. return new JsonResult(new { success = false, message = "Username is required" });
  239. var foundUser = await _userManager.FindByNameAsync(model.Username);
  240. if (foundUser != null)
  241. {
  242. foundUser.AccountStatus = model.AccountStatus;
  243. var result = await _userManager.UpdateAsync(foundUser);
  244. if (result.Succeeded)
  245. {
  246. // Remove the UserInfo Cache
  247. RemoveCachedUser(model.Username);
  248. return new JsonResult(new { success = true });
  249. }
  250. else
  251. return new JsonResult(new { success = false, message = "Unable to update account status.", identityErrors = result.Errors });
  252. }
  253. return new JsonResult(new { success = false, message = "User does not exist." });
  254. }
  255. [HttpPost]
  256. public async Task<IActionResult> UpdateAccountType(UpdateAccountTypeModel model)
  257. {
  258. if (string.IsNullOrEmpty(model.Username))
  259. return new JsonResult(new { success = false, message = "Username is required" });
  260. var foundUser = await _userManager.FindByNameAsync(model.Username);
  261. if (foundUser != null)
  262. {
  263. foundUser.AccountType = model.AccountType;
  264. var result = await _userManager.UpdateAsync(foundUser);
  265. if (result.Succeeded)
  266. {
  267. // Remove the UserInfo Cache
  268. RemoveCachedUser(model.Username);
  269. return new JsonResult(new { success = true });
  270. }
  271. else
  272. return new JsonResult(new { success = false, message = "Unable to update account type.", identityErrors = result.Errors });
  273. }
  274. return new JsonResult(new { success = false, message = "User does not exist." });
  275. }
  276. [HttpPost]
  277. public async Task<IActionResult> UpdatePGPPublicKey(UpdatePGPPublicKeyModel model)
  278. {
  279. if (string.IsNullOrEmpty(model.Username))
  280. return new JsonResult(new { success = false, message = "Username is required" });
  281. var foundUser = await _userManager.FindByNameAsync(model.Username);
  282. if (foundUser != null)
  283. {
  284. foundUser.PGPPublicKey = model.PGPPublicKey;
  285. var result = await _userManager.UpdateAsync(foundUser);
  286. if (result.Succeeded)
  287. {
  288. // Remove the UserInfo Cache
  289. RemoveCachedUser(model.Username);
  290. return new JsonResult(new { success = true });
  291. }
  292. else
  293. return new JsonResult(new { success = false, message = "Unable to update pgp public key.", identityErrors = result.Errors });
  294. }
  295. return new JsonResult(new { success = false, message = "User does not exist." });
  296. }
  297. [HttpGet]
  298. public async Task<IActionResult> Get2FAKey(string username)
  299. {
  300. if (string.IsNullOrEmpty(username))
  301. return new JsonResult(new { success = false, message = "Username is required" });
  302. var foundUser = await _userManager.FindByNameAsync(username);
  303. if (foundUser != null)
  304. {
  305. string unformattedKey = await _userManager.GetAuthenticatorKeyAsync(foundUser);
  306. return new JsonResult(new { success = true, data = FormatKey(unformattedKey) });
  307. }
  308. return new JsonResult(new { success = false, message = "User does not exist." });
  309. }
  310. [HttpPost]
  311. public async Task<IActionResult> Reset2FAKey(Reset2FAKeyModel model)
  312. {
  313. if (string.IsNullOrEmpty(model.Username))
  314. return new JsonResult(new { success = false, message = "Username is required" });
  315. var foundUser = await _userManager.FindByNameAsync(model.Username);
  316. if (foundUser != null)
  317. {
  318. // Remove the UserInfo Cache
  319. RemoveCachedUser(model.Username);
  320. await _userManager.ResetAuthenticatorKeyAsync(foundUser);
  321. string unformattedKey = await _userManager.GetAuthenticatorKeyAsync(foundUser);
  322. return new JsonResult(new { success = true, data = FormatKey(unformattedKey) });
  323. }
  324. return new JsonResult(new { success = false, message = "User does not exist." });
  325. }
  326. [HttpPost]
  327. public async Task<IActionResult> Enable2FA(Enable2FAModel model)
  328. {
  329. if (string.IsNullOrEmpty(model.Username))
  330. return new JsonResult(new { success = false, message = "Username is required" });
  331. if (string.IsNullOrEmpty(model.Code))
  332. return new JsonResult(new { success = false, message = "Code is required" });
  333. var foundUser = await _userManager.FindByNameAsync(model.Username);
  334. if (foundUser != null)
  335. {
  336. // Strip spaces and hypens
  337. var verificationCode = model.Code.Replace(" ", string.Empty).Replace("-", string.Empty);
  338. var is2faTokenValid = await _userManager.VerifyTwoFactorTokenAsync(
  339. foundUser, _userManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode);
  340. if (is2faTokenValid)
  341. {
  342. var result = await _userManager.SetTwoFactorEnabledAsync(foundUser, true);
  343. if (result.Succeeded)
  344. {
  345. // Remove the UserInfo Cache
  346. RemoveCachedUser(model.Username);
  347. var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(foundUser, 10);
  348. return new JsonResult(new { success = true, data = recoveryCodes.ToArray() });
  349. }
  350. else
  351. return new JsonResult(new { success = false, message = "Unable to set Two-Factor Authentication.", identityErrors = result.Errors });
  352. }
  353. return new JsonResult(new { success = false, message = "Verification code is invalid." });
  354. }
  355. return new JsonResult(new { success = false, message = "User does not exist." });
  356. }
  357. [HttpPost]
  358. public async Task<IActionResult> Disable2FA(Disable2FAModel model)
  359. {
  360. if (string.IsNullOrEmpty(model.Username))
  361. return new JsonResult(new { success = false, message = "Username is required" });
  362. var foundUser = await _userManager.FindByNameAsync(model.Username);
  363. if (foundUser != null)
  364. {
  365. var result = await _userManager.SetTwoFactorEnabledAsync(foundUser, false);
  366. if (result.Succeeded)
  367. {
  368. // Remove the UserInfo Cache
  369. RemoveCachedUser(model.Username);
  370. return new JsonResult(new { success = true });
  371. }
  372. else
  373. return new JsonResult(new { success = false, message = "Unable to disable Two-Factor Authentication.", identityErrors = result.Errors });
  374. }
  375. return new JsonResult(new { success = false, message = "User does not exist." });
  376. }
  377. [HttpPost]
  378. public async Task<IActionResult> GenerateRecoveryCodes(GenerateRecoveryCodesModel model)
  379. {
  380. if (string.IsNullOrEmpty(model.Username))
  381. return new JsonResult(new { success = false, message = "Username is required" });
  382. var foundUser = await _userManager.FindByNameAsync(model.Username);
  383. if (foundUser != null)
  384. {
  385. if (foundUser.TwoFactorEnabled)
  386. {
  387. // Remove the UserInfo Cache
  388. RemoveCachedUser(model.Username);
  389. var recoveryCodes = await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(foundUser, 10);
  390. return new JsonResult(new { success = true, data = recoveryCodes.ToArray() });
  391. }
  392. return new JsonResult(new { success = false, message = "Two-Factor Authentication is not enabled." });
  393. }
  394. return new JsonResult(new { success = false, message = "User does not exist." });
  395. }
  396. [HttpGet]
  397. public async Task<IActionResult> GetClient(string username, string clientId, [FromServices] IClientStore clientStore, [FromServices] ConfigurationDbContext configContext)
  398. {
  399. if (string.IsNullOrEmpty(username))
  400. return new JsonResult(new { success = false, message = "Username is required" });
  401. if (string.IsNullOrEmpty(clientId))
  402. return new JsonResult(new { success = false, message = "Client Id is required" });
  403. var client = configContext.Clients.FirstOrDefault(c =>
  404. c.ClientId == clientId &&
  405. c.Properties.Exists(p =>
  406. p.Key == "username" &&
  407. p.Value.ToLower() == username.ToLower())
  408. );
  409. if (client != null)
  410. {
  411. var foundClient = await clientStore.FindClientByIdAsync(client.ClientId);
  412. return new JsonResult(new { success = true, data = foundClient });
  413. }
  414. return new JsonResult(new { success = false, message = "Client does not exist." });
  415. }
  416. [HttpGet]
  417. public async Task<IActionResult> GetClients(string username, [FromServices] IClientStore clientStore, [FromServices] ConfigurationDbContext configContext)
  418. {
  419. if (string.IsNullOrEmpty(username))
  420. return new JsonResult(new { success = false, message = "Username is required" });
  421. var foundClientIds = configContext.Clients.Where(c =>
  422. c.Properties.Exists(p =>
  423. p.Key == "username" &&
  424. p.Value.ToLower() == username.ToLower())
  425. ).Select(c => c.ClientId);
  426. var clients = new List<IdentityServer4.Models.Client>();
  427. foreach (var clientId in foundClientIds)
  428. {
  429. var foundClient = await clientStore.FindClientByIdAsync(clientId);
  430. if (foundClient != null)
  431. clients.Add(foundClient);
  432. }
  433. return new JsonResult(new { success = true, data = clients });
  434. }
  435. [HttpPost]
  436. public IActionResult CreateClient(CreateClientModel model, [FromServices] ConfigurationDbContext configContext)
  437. {
  438. // Generate a unique client ID
  439. var clientId = StringHelper.RandomString(20, "abcdefghjkmnpqrstuvwxyz1234567890");
  440. while (configContext.Clients.Where(c => c.ClientId == clientId).FirstOrDefault() != null)
  441. {
  442. clientId = StringHelper.RandomString(20, "abcdefghjkmnpqrstuvwxyz1234567890");
  443. }
  444. var clientSecret = StringHelper.RandomString(40, "abcdefghjkmnpqrstuvwxyz1234567890");
  445. // Generate the origin for the callback
  446. Uri redirect = new Uri(model.CallbackUrl);
  447. string origin = redirect.Scheme + "://" + redirect.Host;
  448. var client = new IdentityServer4.Models.Client
  449. {
  450. Properties = new Dictionary<string, string>()
  451. {
  452. { "username", model.Username }
  453. },
  454. ClientId = clientId,
  455. ClientName = model.Name,
  456. ClientUri = model.HomepageUrl,
  457. LogoUri = model.LogoUrl,
  458. AllowedGrantTypes = new List<string>()
  459. {
  460. GrantType.AuthorizationCode,
  461. GrantType.ClientCredentials
  462. },
  463. ClientSecrets =
  464. {
  465. new IdentityServer4.Models.Secret(clientSecret.Sha256())
  466. },
  467. RequireConsent = true,
  468. RedirectUris =
  469. {
  470. model.CallbackUrl
  471. },
  472. AllowedCorsOrigins =
  473. {
  474. origin
  475. },
  476. AllowedScopes = model.AllowedScopes,
  477. AllowOfflineAccess = true
  478. };
  479. configContext.Clients.Add(client.ToEntity());
  480. configContext.SaveChanges();
  481. return new JsonResult(new { success = true, data = new { id = clientId, secret = clientSecret } });
  482. }
  483. [HttpPost]
  484. public IActionResult EditClient(EditClientModel model, [FromServices] ConfigurationDbContext configContext)
  485. {
  486. // Validate it's an actual client
  487. var foundClient = configContext.Clients.Where(c => c.ClientId == model.ClientId).FirstOrDefault();
  488. if (foundClient != null)
  489. {
  490. foundClient.ClientName = model.Name;
  491. foundClient.ClientUri = model.HomepageUrl;
  492. foundClient.LogoUri = model.LogoUrl;
  493. foundClient.Updated = DateTime.Now;
  494. configContext.Entry(foundClient).State = EntityState.Modified;
  495. // Update the redirect URL for this client
  496. var results = configContext.Set<ClientRedirectUri>().Where(c => c.ClientId == foundClient.Id).ToList();
  497. if (results != null)
  498. {
  499. configContext.RemoveRange(results);
  500. }
  501. var newUri = new ClientRedirectUri();
  502. newUri.Client = foundClient;
  503. newUri.ClientId = foundClient.Id;
  504. newUri.RedirectUri = model.CallbackUrl;
  505. configContext.Add(newUri);
  506. // Generate the origin for the callback
  507. Uri redirect = new Uri(model.CallbackUrl);
  508. string origin = redirect.Scheme + "://" + redirect.Host;
  509. // Update the allowed origin for this client
  510. var corsOrigins = configContext.Set<ClientCorsOrigin>().Where(c => c.ClientId == foundClient.Id).ToList();
  511. if (corsOrigins != null)
  512. {
  513. configContext.RemoveRange(corsOrigins);
  514. }
  515. var newOrigin = new ClientCorsOrigin();
  516. newOrigin.Client = foundClient;
  517. newOrigin.ClientId = foundClient.Id;
  518. newOrigin.Origin = origin;
  519. configContext.Add(newUri);
  520. // Save all the changed
  521. configContext.SaveChanges();
  522. // Clear the client cache
  523. RemoveCachedClient(model.ClientId);
  524. return new JsonResult(new { success = true });
  525. }
  526. return new JsonResult(new { success = false, message = "Client does not exist." });
  527. }
  528. [HttpPost]
  529. public IActionResult DeleteClient(DeleteClientModel model, [FromServices] ConfigurationDbContext configContext)
  530. {
  531. var foundClient = configContext.Clients.Where(c => c.ClientId == model.ClientId).FirstOrDefault();
  532. if (foundClient != null)
  533. {
  534. configContext.Clients.Remove(foundClient);
  535. configContext.SaveChanges();
  536. // Clear the client cache
  537. RemoveCachedClient(model.ClientId);
  538. return new JsonResult(new { success = true });
  539. }
  540. return new JsonResult(new { success = false, message = "Client does not exist." });
  541. }
  542. private string FormatKey(string unformattedKey)
  543. {
  544. var result = new StringBuilder();
  545. int currentPosition = 0;
  546. while (currentPosition + 4 < unformattedKey.Length)
  547. {
  548. result.Append(unformattedKey.Substring(currentPosition, 4)).Append(" ");
  549. currentPosition += 4;
  550. }
  551. if (currentPosition < unformattedKey.Length)
  552. {
  553. result.Append(unformattedKey.Substring(currentPosition));
  554. }
  555. return result.ToString().ToLowerInvariant();
  556. }
  557. private async Task<ApplicationUser> GetCachedUser(string username)
  558. {
  559. if (string.IsNullOrEmpty(username))
  560. throw new ArgumentNullException("username");
  561. // Check the cache
  562. string cacheKey = GetKey<ApplicationUser>(username);
  563. ApplicationUser foundUser;
  564. if (!_cache.TryGetValue(cacheKey, out foundUser))
  565. {
  566. foundUser = await _userManager.FindByNameAsync(username);
  567. if (foundUser != null)
  568. {
  569. _cache.AddToCache(cacheKey, foundUser, new TimeSpan(1, 0, 0));
  570. }
  571. }
  572. return foundUser;
  573. }
  574. private void RemoveCachedUser(string username)
  575. {
  576. if (string.IsNullOrEmpty(username))
  577. throw new ArgumentNullException("username");
  578. string cacheKey = GetKey<ApplicationUser>(username);
  579. _cache.Remove(cacheKey);
  580. }
  581. private void RemoveCachedClient(string clientId)
  582. {
  583. if (string.IsNullOrEmpty(clientId))
  584. throw new ArgumentNullException("clientId");
  585. string key = GetKey<IdentityServer4.Models.Client>(clientId);
  586. _cache.Remove(key);
  587. }
  588. private string GetKey<T>(string key)
  589. {
  590. if (string.IsNullOrEmpty(key))
  591. throw new ArgumentNullException("key");
  592. return typeof(T).FullName + _KeySeparator + key;
  593. }
  594. }
  595. }