コード例 #1
0
        /// <summary>
        ///     Decrypt and validate an encrypted and signed cookie value
        /// </summary>
        /// <param name="decodedCookieValue">Encrypted and signed cookie value</param>
        /// <param name="configuration">Current configuration</param>
        /// <returns>Decrypted value, or empty on error or if failed validation</returns>
        public static string DecryptAndValidateAuthenticationCookie(
            string decodedCookieValue,
            FormsAuthenticationConfiguration configuration)
        {
            var hmacStringLength =
                Base64Helpers.GetBase64Length(configuration.CryptographyConfiguration.HmacProvider.HmacLength);

            var encryptedCookie = decodedCookieValue.Substring(hmacStringLength);
            var hmacString = decodedCookieValue.Substring(0, hmacStringLength);

            var encryptionProvider = configuration.CryptographyConfiguration.EncryptionProvider;

            // Check the hmacs, but don't early exit if they don't match
            var hmacBytes = Convert.FromBase64String(hmacString);
            var newHmac = GenerateHmac(encryptedCookie, configuration);
            var hmacValid = HmacComparer.Compare(
                newHmac,
                hmacBytes,
                configuration.CryptographyConfiguration.HmacProvider.HmacLength);

            var decrypted = encryptionProvider.Decrypt(encryptedCookie);

            // Only return the decrypted result if the hmac was ok
            return hmacValid ? decrypted : string.Empty;
        }
コード例 #2
0
        /// <summary>
        ///     Enables forms authentication for the application
        /// </summary>
        /// <param name="pipelines">Pipelines to add handlers to (usually "this")</param>
        /// <param name="configuration">Forms authentication configuration</param>
        public static void Enable(IPipelines pipelines, FormsAuthenticationConfiguration configuration)
        {
            if (pipelines == null)
            {
                throw new ArgumentNullException(nameof(pipelines));
            }

            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            configuration.Validate();

            currentConfiguration = configuration;

            pipelines.BeforeRequest.AddItemToStartOfPipeline(GetLoadAuthenticationHook(configuration));

            if (!configuration.DisableRedirect)
            {
                pipelines.AfterRequest.AddItemToEndOfPipeline(GetRedirectToLoginHook(configuration));
            }

            pipelines.AfterRequest.AddItemToEndOfPipeline(GetUpdateSessionCookieHook(configuration));
        }
コード例 #3
0
        private static Action<NancyContext> GetUpdateSessionCookieHook(FormsAuthenticationConfiguration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            return context =>
                {
                    var userHasLoggedOut = context.Items.ContainsKey(UserLoggedOutKey);

                    var shouldCopyExistingCookie = context.Request.Cookies.ContainsKey(FormsAuthenticationCookieName)
                                                   && !userHasLoggedOut 
                                                   && context.CurrentUser != null;

                    if (shouldCopyExistingCookie)
                    {
                        var formsAuthCookieValue = context.Request.Cookies[FormsAuthenticationCookieName];

                        var expires = DateTime.UtcNow.AddMinutes(configuration.SlidingSessionExpirationMinutes);

                        var newCookie = new NancyCookie(
                            FormsAuthenticationCookieName,
                            formsAuthCookieValue,
                            true,
                            configuration.RequiresSSL,
                            expires);

                        context.Response.WithCookie(newCookie);

                        // Also update the cache entry to keep consistent
                        configuration.AuthSessionIdStore.Extend((Guid)context.Items[AuthSessionIdItemKey], expires);
                    }
                };
        }
コード例 #4
0
        /// <summary>
        ///     Gets the post request hook for redirecting to the login page
        /// </summary>
        /// <param name="configuration">Forms authentication configuration to use</param>
        /// <returns>Post request hook delegate</returns>
        private static Action<NancyContext> GetRedirectToLoginHook(FormsAuthenticationConfiguration configuration)
        {
            return context =>
                {
                    if (context.Response.StatusCode == HttpStatusCode.Unauthorized)
                    {
                        var redirectQuerystringKey = GetRedirectQuerystringKey(configuration);

                        context.Response =
                            context.GetRedirect(
                                $"{configuration.RedirectUrl}?{redirectQuerystringKey}={context.ToFullPath("~" + context.Request.Path + HttpUtility.UrlEncode(context.Request.Url.Query))}");
                    }
                };
        }
コード例 #5
0
        /// <summary>
        ///     Gets the redirect query string key from <see cref="FormsAuthenticationConfiguration" />
        /// </summary>
        /// <param name="configuration">The forms authentication configuration.</param>
        /// <returns>Redirect Querystring key</returns>
        private static string GetRedirectQuerystringKey(FormsAuthenticationConfiguration configuration)
        {
            string redirectQuerystringKey = null;

            if (configuration != null)
            {
                redirectQuerystringKey = configuration.RedirectQuerystringKey;
            }

            if (string.IsNullOrWhiteSpace(redirectQuerystringKey))
            {
                redirectQuerystringKey = FormsAuthenticationConfiguration.DefaultRedirectQuerystringKey;
            }

            return redirectQuerystringKey;
        }
コード例 #6
0
        /// <summary>
        ///     Gets the pre request hook for loading the authenticated user's details
        ///     from the cookie.
        /// </summary>
        /// <param name="configuration">Forms authentication configuration to use</param>
        /// <returns>Pre request hook delegate</returns>
        private static Func<NancyContext, Response> GetLoadAuthenticationHook(
            FormsAuthenticationConfiguration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            return context =>
                {
                    var userGuid = GetAuthenticatedUserFromCookie(context, configuration);

                    if (userGuid != Guid.Empty)
                    {
                        context.CurrentUser = configuration.UserMapper.GetUserFromIdentifier(userGuid, context);
                    }

                    return null;
                };
        }
コード例 #7
0
        /// <summary>
        ///     Gets the authenticated user GUID from the incoming request cookie if it exists
        ///     and is valid.
        /// </summary>
        /// <param name="context">Current context</param>
        /// <param name="configuration">Current configuration</param>
        /// <returns>Returns user guid, or Guid.Empty if not present or invalid</returns>
        private static Guid GetAuthenticatedUserFromCookie(
            NancyContext context,
            FormsAuthenticationConfiguration configuration)
        {
            if (!context.Request.Cookies.ContainsKey(FormsAuthenticationCookieName))
            {
                return Guid.Empty;
            }

            if (string.IsNullOrEmpty(context.Request.Cookies[FormsAuthenticationCookieName]))
            {
                return Guid.Empty;
            }

            var cookieValue =
                DecryptAndValidateAuthenticationCookie(
                    context.Request.Cookies[FormsAuthenticationCookieName],
                    configuration);

            Guid returnGuid;

            if (string.IsNullOrEmpty(cookieValue) || !Guid.TryParse(cookieValue, out returnGuid))
            {
                return Guid.Empty;
            }

            // Add the auth session id to the context - we need it later to extend the session
            context.Items[AuthSessionIdItemKey] = returnGuid;

            // Translate the AuthSessionId to a User Id
            return configuration.AuthSessionIdStore.Get(returnGuid);
        }
コード例 #8
0
 /// <summary>
 ///     Generate a hmac for the encrypted cookie string
 /// </summary>
 /// <param name="encryptedCookie">Encrypted cookie string</param>
 /// <param name="configuration">Current configuration</param>
 /// <returns>Hmac byte array</returns>
 private static byte[] GenerateHmac(string encryptedCookie, FormsAuthenticationConfiguration configuration)
 {
     return configuration.CryptographyConfiguration.HmacProvider.GenerateHmac(encryptedCookie);
 }
コード例 #9
0
        /// <summary>
        ///     Encrypt and sign the cookie contents
        /// </summary>
        /// <param name="cookieValue">Plain text cookie value</param>
        /// <param name="configuration">Current configuration</param>
        /// <returns>Encrypted and signed string</returns>
        private static string EncryptAndSignCookie(string cookieValue, FormsAuthenticationConfiguration configuration)
        {
            var encryptedCookie = configuration.CryptographyConfiguration.EncryptionProvider.Encrypt(cookieValue);
            var hmacBytes = GenerateHmac(encryptedCookie, configuration);
            var hmacString = Convert.ToBase64String(hmacBytes);

            return string.Format("{1}{0}", encryptedCookie, hmacString);
        }
コード例 #10
0
        /// <summary>
        ///     Builds a cookie for logging a user out
        /// </summary>
        /// <param name="configuration">Current configuration</param>
        /// <returns>Nancy cookie instance</returns>
        private static INancyCookie BuildLogoutCookie(FormsAuthenticationConfiguration configuration)
        {
            var cookie = new NancyCookie(FormsAuthenticationCookieName, string.Empty, true, configuration.RequiresSSL)
                             {
                                 Expires = DateTime.Now.AddDays(-1)
                             };

            if (!string.IsNullOrEmpty(configuration.Domain))
            {
                cookie.Domain = configuration.Domain;
            }

            if (!string.IsNullOrEmpty(configuration.Path))
            {
                cookie.Path = configuration.Path;
            }

            return cookie;
        }
コード例 #11
0
        /// <summary>
        ///     Build the forms authentication cookie
        /// </summary>
        /// <param name="userIdentifier">Authenticated user identifier</param>
        /// <param name="cookieExpiry">Optional expiry date for the cookie (for 'Remember me')</param>
        /// <param name="configuration">Current configuration</param>
        /// <returns>Nancy cookie instance</returns>
        private static INancyCookie BuildCookie(Guid userIdentifier, FormsAuthenticationConfiguration configuration)
        {
            var expiryTime = DateTime.UtcNow.AddMinutes(configuration.SlidingSessionExpirationMinutes);

            var authSessionId = configuration.AuthSessionIdStore.Add(userIdentifier, expiryTime);

            var cookieContents = EncryptAndSignCookie(authSessionId.ToString(), configuration);

            var cookie = new NancyCookie(FormsAuthenticationCookieName, cookieContents, true, configuration.RequiresSSL)
                             {
                                 Expires = expiryTime
                             };

            if (!string.IsNullOrEmpty(configuration.Domain))
            {
                cookie.Domain = configuration.Domain;
            }

            if (!string.IsNullOrEmpty(configuration.Path))
            {
                cookie.Path = configuration.Path;
            }

            return cookie;
        }