public void Can_Encrypt_And_Decrypt_Forms_Authentication_Ticket() { // These would come from the asp.net 3.5 applications <machineKey decryption="AES" decryptionKey"" validation="SHA1" validationKey="" /> web.config. // I have made these up for the purposes of this test. string validationKey = "30101052676849B0B494466B7A99656346328E8964748448E422D7344467A45777D972414947271744423422851D6742C9A09A65212C276C7F839157501291C6"; string decryptionKey = "AC7387D7E54B156377D81930CF237888854B5B5B515CF2D6356541255E696144"; // Arrange var issueDate = DateTime.Now; var expiryDate = issueDate.AddHours(1); var formsAuthenticationTicket = new FormsAuthenticationTicket(2, "*****@*****.**", issueDate, expiryDate, false, "custom data", "/"); byte[] decryptionKeyBytes = HexUtils.HexToBinary(decryptionKey); byte[] validationKeyBytes = HexUtils.HexToBinary(validationKey); var legacyFormsAuthenticationTicketEncryptor = new LegacyFormsAuthenticationTicketEncryptor(decryptionKeyBytes, validationKeyBytes); // Act // We encrypt the forms auth cookie. var encryptedText = legacyFormsAuthenticationTicketEncryptor.Encrypt(formsAuthenticationTicket); Assert.IsNotNull(encryptedText); // We decrypt the encypted text back into a forms auth ticket, and compare it to the original ticket to make sure it // roundtripped successfully. FormsAuthenticationTicket decryptedFormsAuthenticationTicket = legacyFormsAuthenticationTicketEncryptor.DecryptCookie(encryptedText); Assert.AreEqual(formsAuthenticationTicket.CookiePath, decryptedFormsAuthenticationTicket.CookiePath); Assert.AreEqual(formsAuthenticationTicket.Expiration, decryptedFormsAuthenticationTicket.Expiration); Assert.AreEqual(formsAuthenticationTicket.Expired, decryptedFormsAuthenticationTicket.Expired); Assert.AreEqual(formsAuthenticationTicket.IsPersistent, decryptedFormsAuthenticationTicket.IsPersistent); Assert.AreEqual(formsAuthenticationTicket.IssueDate, decryptedFormsAuthenticationTicket.IssueDate); Assert.AreEqual(formsAuthenticationTicket.UserData, decryptedFormsAuthenticationTicket.UserData); Assert.AreEqual(formsAuthenticationTicket.Version, decryptedFormsAuthenticationTicket.Version); }
public async Task <IActionResult> ExternalLoginCallback() { // This is the SecureAuth callback, which is reached by a 302. The token that // SecureAuth sends is a cookie. var viewDataErrorKey = "secureAuthError"; var tokenName = _configuration["SecureAuth:TokenName"]; string token = Request.Cookies[tokenName]; if (token != null) { // Decrypt the token with our SecureAuth keys. var validationKey = _configuration["SecureAuth:ValidationKey"]; var decryptionKey = _configuration["SecureAuth:DecryptionKey"]; // Default to Framework45 for compatibility mode. CompatibilityMode compatibilityMode = CompatibilityMode.Framework45; if (_configuration.GetValue <bool>("SecureAuth:UseCompatibilityMode20SP2")) { compatibilityMode = CompatibilityMode.Framework20SP2; } if (validationKey == null || decryptionKey == null) { ViewData[viewDataErrorKey] = "SecureAuth keys missing from configuration file."; } else { byte[] decryptionKeyBytes = HexUtils.HexToBinary(decryptionKey); byte[] validationKeyBytes = HexUtils.HexToBinary(validationKey); try { var legacyFormsAuthenticationTicketEncryptor = new LegacyFormsAuthenticationTicketEncryptor(decryptionKeyBytes, validationKeyBytes, ShaVersion.Sha1, compatibilityMode); FormsAuthenticationTicket decryptedTicket = legacyFormsAuthenticationTicketEncryptor.DecryptCookie(token); // If already authenticated and usernames don't match, log out. if (User.Identity.IsAuthenticated) { if (decryptedTicket.Name != User.Identity.Name) { return(await LogoutAsync()); } } else { // Let's authenticate! // Create a user principal object for this user. var principal = CreateIdentity(decryptedTicket.Name, decryptedTicket.UserData); // Authenticate using the identity. await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal); // Now redirect to determine this user's roles. return(RedirectToAction("CheckCAAM", "Login")); } } catch (Exception ex) { ViewData[viewDataErrorKey] = ex.Message; } } } else { // No token. ViewData[viewDataErrorKey] = "SecureAuth post-authentication token is missing."; } // Append our common error message. ViewData[viewDataErrorKey] = String.Format("{0} {1}", ViewData[viewDataErrorKey], _sharedLocalizer["CaptureAndEmailUsMessage"]); return(View()); }
public async Task <IActionResult> ExternalLoginCallback() { User qmsUser = null; string logSnippet = new StringBuilder("[") .Append(DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss")) .Append("][LoginController][ExternalLoginCallback] => ") .ToString(); ///////////////////////////////////////////////////////////////////////////// // This is the SecureAuth callback, which is reached by a 302. The token that // SecureAuth sends is a cookie. ///////////////////////////////////////////////////////////////////////////// var tokenName = _config.GetValue <string>("SecureAuth:TokenName"); Console.WriteLine(logSnippet + $"(SecureAuth:TokenName IS NULL): {tokenName == null}"); Console.WriteLine(logSnippet + $"(tokenName): '{tokenName}'"); string token = Request.Cookies[tokenName]; Console.WriteLine(logSnippet + $"(SecureAuth Cookie IS NULL): {token == null}"); Console.WriteLine(logSnippet + $"(SecureAuth Cookie): '{token}'"); if (token != null) { //////////////////////////////////////////////////////////////////////////////// // Decrypt the token with our SecureAuth keys (validation and decryption) //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Validation Key //////////////////////////////////////////////////////////////////////////////// string validationKey = _config["SecureAuth:ValidationKey:Failover"]; Console.WriteLine(logSnippet + $"(validationKey IS NULL): {validationKey == null}"); Console.WriteLine(logSnippet + $"(validationKey): {validationKey}"); //////////////////////////////////////////////////////////////////////////////// // Decryption Key //////////////////////////////////////////////////////////////////////////////// string decryptionKey = _config["SecureAuth:DecryptionKey:Failover"]; Console.WriteLine(logSnippet + $"(decryptionKey IS NULL): {decryptionKey == null}"); Console.WriteLine(logSnippet + $"(decryptionKey): {decryptionKey}"); byte[] decryptionKeyBytes = HexUtils.HexToBinary(decryptionKey); byte[] validationKeyBytes = HexUtils.HexToBinary(validationKey); string compatabilityMode = _config.GetValue <string>(MiscConstants.ENCRYPTION_COMPATABILITY_MODE); Console.WriteLine(logSnippet + $"(compatabilityMode IsNullOrEmpty).....: {String.IsNullOrEmpty(compatabilityMode)}"); Console.WriteLine(logSnippet + $"(compatabilityMode IsNullOrWhiteSpace): {String.IsNullOrWhiteSpace(compatabilityMode)}"); Console.WriteLine(logSnippet + $"(compatabilityMode)...................: '{compatabilityMode}'"); LegacyFormsAuthenticationTicketEncryptor legacyFormsAuthenticationTicketEncryptor = null; if (compatabilityMode.Equals(MiscConstants.FRAMEWORK45)) { legacyFormsAuthenticationTicketEncryptor = new LegacyFormsAuthenticationTicketEncryptor(decryptionKeyBytes, validationKeyBytes, ShaVersion.Sha1, CompatibilityMode.Framework45); } else { legacyFormsAuthenticationTicketEncryptor = new LegacyFormsAuthenticationTicketEncryptor(decryptionKeyBytes, validationKeyBytes, ShaVersion.Sha1, CompatibilityMode.Framework20SP2); } Console.WriteLine(logSnippet + $"Decrypting post-authentication cookie sent back from SecureAuth ..."); FormsAuthenticationTicket decryptedTicket = legacyFormsAuthenticationTicketEncryptor.DecryptCookie(token); Console.WriteLine(logSnippet + $"(decryptedTicket IS NULL): {decryptedTicket == null}"); if (decryptedTicket != null) { Console.WriteLine(logSnippet + $"(decryptedTicket.Name).....: '{decryptedTicket.Name}'"); Console.WriteLine(logSnippet + $"(decryptedTicket.UserData).: '{decryptedTicket.UserData}'"); HttpContext.Session.SetObject(MiscConstants.USER_EMAIL_ADDRESS, decryptedTicket.UserData); } //////////////////////////////////////////////////////////////////////////////// // If user is already authenticated but user names don't match, log user out. //////////////////////////////////////////////////////////////////////////////// Console.WriteLine(logSnippet + $"(User.Identity.IsAuthenticated): '{User.Identity.IsAuthenticated}'"); //////////////////////////////////////////////////////////////////////////////// // User is Authenticated //////////////////////////////////////////////////////////////////////////////// if (User.Identity.IsAuthenticated == true) { Console.WriteLine(logSnippet + $"(decryptedTicket.UserData): '{decryptedTicket.UserData}'"); Console.WriteLine(logSnippet + $"(decryptedTicket.Name)....: '{decryptedTicket.Name}'"); Console.WriteLine(logSnippet + $"(User.Identity.Name)......: '{User.Identity.Name}'"); if (decryptedTicket.Name != User.Identity.Name) { Console.WriteLine(logSnippet + $"decryptedTicket.Name AND User.Identity.Name DON'T MATCH - logging user out"); return(await LogoutAsync()); } } //////////////////////////////////////////////////////////////////////////////// // User is NOT Authenticated //////////////////////////////////////////////////////////////////////////////// if (User.Identity.IsAuthenticated == false) { Console.WriteLine(logSnippet + $"Calling UserService.RetrieveByEmailAddress for: '{decryptedTicket.UserData}'"); try { qmsUser = _userService.RetrieveByEmailAddress(decryptedTicket.UserData, true); } catch (UserNotFoundException) { ///////////////////////////////////////////////////////////////////////////////////////// // User record not found in the sec_user table. Redirecting to 'UnauthorizedUser page. ///////////////////////////////////////////////////////////////////////////////////////// Console.WriteLine(logSnippet + $"qmsUser NOT FOUND for '{decryptedTicket.UserData}'. Redirecting to 'UnauthorizedUser page"); return(RedirectToAction("UnauthorizedUser", "Login")); } if (qmsUser.UserRoles == null || qmsUser.UserRoles.Count < 1) { /////////////////////////////////////////////////////////////////////////////////////// // User is Unauthorized to use QMS (no roles)(No rows found insec_user_org_role table) /////////////////////////////////////////////////////////////////////////////////////// Console.WriteLine(logSnippet + $"No QMS roles found for authenticated user '{decryptedTicket.UserData}'. Redirecting to 'UnauthorizedUser page."); return(RedirectToAction("UnauthorizedUser", "Login")); } Console.WriteLine(logSnippet + $"'{decryptedTicket.UserData}' IS AUTHORIZED to use QMS. Creating ClaimsPrincipal."); var claimsPrincipal = this.CreateClaimsPrincipal(qmsUser, decryptedTicket.Name, decryptedTicket.UserData); if (claimsPrincipal == null) { // ViewBag.LoginError = _localizer["User {0} does not have access to QMS.", decryptedTicket.Name]; ViewBag.LoginError = _localizer[$"User '{decryptedTicket.Name}' does not have access to QMS."]; } else if (this.UserHasMultipleSessions(claimsPrincipal)) { ViewBag.LoginError = _localizer["You have too many existing sessions. Please log out of one or them or wait 30 minutes and try again."]; } else { Console.WriteLine(logSnippet + $"Calling HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal)"); //////////////////////////////////////////////////////////////////////////// // Place SecUser in Session //////////////////////////////////////////////////////////////////////////// await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal); HttpContext.Session.SetObject(MiscConstants.USER_SESSION_KEY, qmsUser); HttpContext.Session.SetObject(MiscConstants.USER_SESSION_VM_KEY, UserUtil.MapToViewModel(qmsUser)); //////////////////////////////////////////////////////////////////////////// // Place MenuItemViewModel List in Session //////////////////////////////////////////////////////////////////////////// //HashSet<MenuItemViewModel> menuBuilder = MenuUtil.GetMenuItemsforUser(qmsUser); //HttpContext.Session.SetObject(MiscConstants.MENU_SESSION_KEY, menuBuilder); //////////////////////////////////////////////////////////////////////////// // Place ModuleMenuItem in Session //////////////////////////////////////////////////////////////////////////// List <ModuleMenuItem> moduleMenuItems = _menuBuilderService.RetrieveMenuForUser(qmsUser.UserId); HttpContext.Session.SetObject(MiscConstants.MODULE_MENU_ITEMS_SESSION_KEY, moduleMenuItems); this.debug(moduleMenuItems, qmsUser.UserId); } } } string requestedUri = HttpContext.Session.GetObject <string>(MiscConstants.REQUESTED_URI); Console.WriteLine(logSnippet + $"(Request.Protocol): '{Request.Protocol}'"); Console.WriteLine(logSnippet + $"(Request.Host)....: '{Request.Host}'"); Console.WriteLine(logSnippet + $"(Request.PathBase): '{Request.PathBase}'"); Console.WriteLine(logSnippet + $"(requestedUri)....: '{requestedUri}'"); //string redirectUrl = $"https://dev-hrqms.gsa.gov/{requestedUri}"; string redirectUrl = $"https://{Request.Host}{Request.PathBase}/{requestedUri}"; Console.WriteLine(logSnippet + $"(redirectUrl).....: '{redirectUrl}'"); if (string.IsNullOrEmpty(requestedUri) == false && string.IsNullOrWhiteSpace(requestedUri) == false) // && Url.IsLocalUrl(requestedUri) ) { HttpContext.Session.Remove(MiscConstants.REQUESTED_URI); //return LocalRedirect(requestedUri); return(Redirect(redirectUrl)); } else { return(RedirectToAction("Index", "Home")); } }