示例#1
0
        public void UniqueOutput()
        {
            // Verify that we generate and use a unique IV for
            // every encryption run such that encrypting the same
            // data will return different results.  This is an
            // important security best practice.

            const int iterations = 1000;

            var decrypted   = "We hold these truths to be self-evident, that all men are created equal.";
            var encryptions = new HashSet <string>();

            using (var cipher = new AesCipher())
            {
                for (int i = 0; i < iterations; i++)
                {
                    var encrypted = cipher.EncryptToBase64(decrypted);

                    Assert.DoesNotContain(encrypted, encryptions);
                    Assert.Equal(decrypted, cipher.DecryptStringFrom(encrypted));

                    encryptions.Add(encrypted);
                }
            }
        }
示例#2
0
        /// <summary>
        /// <para>
        /// Transforms responses before sending them back to the client. In this case it intercepts the initial Bla
        /// </para>
        /// </summary>
        /// <param name="httpContext">The HTTP Context.</param>
        /// <param name="proxyResponse">The Proxied Response.</param>
        /// <returns></returns>
        public override async ValueTask <bool> TransformResponseAsync(HttpContext httpContext,
                                                                      HttpResponseMessage proxyResponse)
        {
            await SyncContext.Clear;

            await base.TransformResponseAsync(httpContext, proxyResponse);

            var session = new Session()
            {
                Id           = NeonHelper.CreateBase36Uuid(),
                UpstreamHost = proxyResponse.RequestMessage.RequestUri.Authority
            };

            var headers   = proxyResponse.Content.Headers;
            var mediaType = headers.ContentType?.MediaType ?? "";

            if (!httpContext.Request.Cookies.ContainsKey(Service.SessionCookieName) ||
                (mediaType == "text/html" && httpContext.Response.StatusCode == 200))
            {
                httpContext.Response.Cookies.Append(Service.SessionCookieName, cipher.EncryptToBase64($"{session.Id}"));
            }

            await cache.SetAsync(session.Id, NeonHelper.JsonSerializeToBytes(session));

            return(true);
        }
示例#3
0
        public void Encrypt_ToBase64()
        {
            // Encrypt a byte array:

            using (var cipher = new AesCipher())
            {
                var decrypted = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
                var encrypted = cipher.EncryptToBase64(decrypted);

                Assert.Equal(decrypted, cipher.DecryptBytesFrom(encrypted));
            }

            // Encrypt a string:

            using (var cipher = new AesCipher())
            {
                var decrypted = "1234567890";
                var encrypted = cipher.EncryptToBase64(decrypted);

                Assert.Equal(decrypted, cipher.DecryptStringFrom(encrypted));
            }
        }
示例#4
0
        /// <summary>
        /// Transforms the response before returning it to the client.
        ///
        /// <para>
        /// This method will add a <see cref="Cookie"/> to each response containing relevant information
        /// about the current authentication flow. It also intercepts redirects from Dex and saves any relevant
        /// tokens to a cache for reuse.
        /// </para>
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="proxyResponse"></param>
        /// <returns></returns>
        public override async ValueTask <bool> TransformResponseAsync(HttpContext httpContext,
                                                                      HttpResponseMessage proxyResponse)
        {
            await base.TransformResponseAsync(httpContext, proxyResponse);

            Cookie cookie = null;

            if (httpContext.Request.Cookies.TryGetValue(Service.SessionCookieName, out var requestCookieBase64))
            {
                try
                {
                    logger.LogDebug($"Decrypting existing cookie.");
                    cookie = NeonHelper.JsonDeserialize <Cookie>(cipher.DecryptBytesFrom(requestCookieBase64));
                }
                catch (Exception e)
                {
                    logger.LogError(e);
                    cookie = new Cookie();
                }
            }
            else
            {
                logger.LogDebug($"Cookie not present.");
                cookie = new Cookie();
            }

            // If we're being redirected, intercept request and save token to cookie.
            if (httpContext.Response.Headers.Location.Count > 0 &&
                Uri.IsWellFormedUriString(httpContext.Response.Headers.Location.Single(), UriKind.Absolute))
            {
                var location = new Uri(httpContext.Response.Headers.Location.Single());
                var code     = HttpUtility.ParseQueryString(location.Query).Get("code");
                if (!string.IsNullOrEmpty(code))
                {
                    if (cookie != null)
                    {
                        var redirect = cookie.RedirectUri;

                        var token = await dexClient.GetTokenAsync(cookie.ClientId, code, redirect, "authorization_code");

                        await cache.SetAsync(code, cipher.EncryptToBytes(NeonHelper.JsonSerializeToBytes(token)), cacheOptions);

                        logger.LogDebug(NeonHelper.JsonSerialize(token));
                        cookie.TokenResponse = token;

                        httpContext.Response.Cookies.Append(
                            Service.SessionCookieName,
                            cipher.EncryptToBase64(NeonHelper.JsonSerialize(cookie)),
                            new CookieOptions()
                        {
                            Path     = "/",
                            Expires  = DateTime.UtcNow.AddSeconds(token.ExpiresIn.Value).AddMinutes(-60),
                            Secure   = true,
                            SameSite = SameSiteMode.Strict
                        });

                        return(true);
                    }
                }
            }

            // Add query parameters to the cookie.
            if (httpContext.Request.Query.TryGetValue("client_id", out var clientId))
            {
                logger.LogDebug($"Client ID: [{clientId}]");
                cookie.ClientId = clientId;
            }

            if (httpContext.Request.Query.TryGetValue("state", out var state))
            {
                logger.LogDebug($"State: [{state}]");
                cookie.State = state;
            }

            if (httpContext.Request.Query.TryGetValue("redirect_uri", out var redirectUri))
            {
                logger.LogDebug($"Redirect Uri: [{redirectUri}]");
                cookie.RedirectUri = redirectUri;
            }

            if (httpContext.Request.Query.TryGetValue("scope", out var scope))
            {
                logger.LogDebug($"Scope: [{scope}]");
                cookie.Scope = scope;
            }

            if (httpContext.Request.Query.TryGetValue("response_type", out var responseType))
            {
                logger.LogDebug($"Response Type: [{responseType}]");
                cookie.ResponseType = responseType;
            }

            httpContext.Response.Cookies.Append(
                Service.SessionCookieName,
                cipher.EncryptToBase64(NeonHelper.JsonSerialize(cookie)),
                new CookieOptions()
            {
                Path     = "/",
                Expires  = DateTime.UtcNow.AddHours(24),
                Secure   = true,
                SameSite = SameSiteMode.Strict
            });

            return(true);
        }