예제 #1
0
        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);
        }
예제 #2
0
        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());
        }
예제 #3
0
        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"));
            }
        }