protected override bool IsAuthorized(HttpActionContext httpContext)
        {
            JwtController jwtactions  = new JwtController();
            var           request     = httpContext.Request;
            var           headers     = request.Headers;
            var           UserManager = new UserManager <ApplicationUser>(new UserStore <ApplicationUser>(new ApplicationDbContext()));

            if (headers.Contains("Authorization"))
            {
                string token = headers.GetValues("Authorization").FirstOrDefault();
                if (token != null)
                {
                    string tokenUsername = jwtactions.ValidateToken(token);

                    if (tokenUsername == null)
                    {
                        throw new HttpResponseException(HttpStatusCode.Unauthorized);
                    }
                    else if (UserManager.FindByName(tokenUsername) == null)
                    {
                        throw new HttpResponseException(HttpStatusCode.Unauthorized);
                    }
                    else
                    {
                        return(true);
                    }
                }
                return(false);
            }
            return(false);
        }
Ejemplo n.º 2
0
        public void JwtController_Refresh_HandlesBadInput()
        {
            ///////////////////////////////////////////////////////////////////
            // Arrange
            //

            //   Options
            string secret = "A_KEY_MUST_BE_16_CHARS+";
            SymmetricSecurityKey signingKey         = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secret.PadRight(16)));
            SigningCredentials   signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

            var jwtIssuerOptions = new JwtIssuerOptions
            {
                Issuer             = "TokenIssuer",
                Audience           = "TokenAudience",
                AccessValidFor     = TimeSpan.FromSeconds(10),
                RefreshValidFor    = TimeSpan.FromSeconds(100),
                AccessClockSkew    = 0,
                RefreshClockSkew   = 0,
                Subject            = "Alice",
                SigningCredentials = signingCredentials
            };

            var mockOptions = new Mock <IOptions <JwtIssuerOptions> >();

            mockOptions.Setup(mo => mo.Value).Returns(jwtIssuerOptions);

            //   UserManager
            var fakeUserManager = new FakeUserManager();

            //   TokenStore
            var tokenStore = new ExampleTokenStore();

            //   Configuration
            var mockConfiguration = new Mock <IConfiguration>();

            mockConfiguration.SetupGet(m => m[Constants.SECRET_ENV_VAR]).Returns(secret);

            //   Logger
            var mockLogger = new Mock <ILogger <JwtController> >();

            JwtController controller = new JwtController(mockOptions.Object, fakeUserManager, tokenStore, mockConfiguration.Object, mockLogger.Object);


            // Act & Assert
            var actionResult = controller.Refresh(null);

            Assert.Equal("Microsoft.AspNetCore.Mvc.BadRequestObjectResult", actionResult.Result.GetType().ToString());

            actionResult = controller.Refresh("TotalGarbage");
            Assert.Equal("Microsoft.AspNetCore.Mvc.BadRequestObjectResult", actionResult.Result.GetType().ToString());

            actionResult = controller.Refresh("");
            Assert.Equal("Microsoft.AspNetCore.Mvc.BadRequestObjectResult", actionResult.Result.GetType().ToString());
        }
        public void LoginFail()
        {
            // Arrange
            MakeTokenViewModel model = new MakeTokenViewModel()
            {
                Id       = 7,
                UserName = "******",
                Role     = "admin",
                Fail     = true
            };
            var controller = new JwtController(_mockConfiguration.Object);

            // Act
            var result = controller.Login(model);

            // Assert
            ((ObjectResult)result).StatusCode.Should().Be(400);

            Console.WriteLine(result);
        }
Ejemplo n.º 4
0
        public ActionResult <string> Get()
        {
            // look for an Auth Header
            // we expect it to look like:
            //
            string authHeader = Request.Headers["Authorization"];

            if (string.IsNullOrEmpty(authHeader))
            {
                return(Unauthorized());
            }
            else
            {
                // parse the header
                var    parts          = authHeader.Split(" ");
                string jwtTokenString = parts[1];

                (bool isJwtTokenValid, string username, JwtSecurityToken jwtToken) = JwtController.ValidateJWTToken(jwtTokenString, JwtController.AUDIENCE);

                if (!isJwtTokenValid)
                {
                    return(Unauthorized());
                }
                else
                {
                    // at this point this controller would add the identity of the authenticated caller as a new HTTP header and call a downstream webapi

                    // in this POC just return the identity that we derived from the JWT
                    var authCResult = new AuthCResultBE()
                    {
                        IsValid = isJwtTokenValid, User = username, JwtToken = jwtTokenString
                    };
                    //return Ok(JsonConvert.SerializeObject(authCResult, Formatting.Indented));
                    return(Ok(authCResult));
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Console Loop
        /// </summary>
        static void ConsoleLoop()
        {
            const int MOD_PAYLOAD_OPTION = 99;

            // load the list of available users
            var users = UserController.LoadUsers();

            // Build a menu of Scenarions that can used to test
            StringBuilder sb      = new StringBuilder();
            int           userIdx = 1;

            sb.AppendLine();
            sb.AppendLine("DataCap POC for Auth via JWT Headers");
            sb.AppendLine();
            sb.AppendLine(" List of Test Users");
            sb.AppendLine("====================");
            sb.AppendLine($" [0] Anonymous (Do not send an Auth Header)");
            foreach (var user in users)
            {
                sb.AppendLine($" [{userIdx}] {user.User} " + (user.IsEnabled ? string.Empty : "(Disabled)"));

                userIdx++;
            }

            // pick a user to use for the Modified Payload
            var goodTestUser = users.Where(u => u.IsEnabled == true).FirstOrDefault();

            sb.AppendLine($" [{MOD_PAYLOAD_OPTION}] {goodTestUser.User} (Modified Body)");
            sb.AppendLine(" <enter> to exit");
            sb.AppendLine();

            // define variables outside the while loop to reduce GC pressure
            string         choiceText  = string.Empty;
            int            choiceIndex = 0;
            UserIdentityBE selectedUser;
            bool           shouldContinue      = true;
            AuthCRequestBE authcRequest        = null;
            string         httpBody            = string.Empty;
            Stopwatch      stw                 = null;
            string         jwtToken            = string.Empty;
            long           create1stJWTElapsed = 0;

            // =========================
            // start the message loop
            // =========================
            while (shouldContinue)
            {
                // reset variables
                choiceIndex  = -1;
                selectedUser = null;

                // clear the screen
                Console.Clear();

                // display the menu
                Console.WriteLine(sb.ToString());
                Console.Write("Choice: > ");
                choiceText = Console.ReadLine();

                if (string.IsNullOrEmpty(choiceText))
                {
                    // blank == exit
                    shouldContinue = false;
                }
                else
                {
                    // if the entry is a number and within the list, find the associated user
                    Int32.TryParse(choiceText, out choiceIndex);
                    if (choiceIndex == 0)
                    {
                        selectedUser = new UserIdentityBE()
                        {
                            User = @"Anonymous"
                        };
                        Console.WriteLine($" ==> Ready to send anonymous request");
                    }
                    else if (choiceIndex == MOD_PAYLOAD_OPTION)
                    {
                        selectedUser = goodTestUser;
                        Console.WriteLine($" ==> Ready to send request with tampered body");
                    }
                    else if (choiceIndex > 0 && choiceIndex <= users.Count)
                    {
                        selectedUser = users[choiceIndex - 1];
                        Console.WriteLine($" ==> Ready to send request for: {selectedUser.User} [{selectedUser.Company}].");
                    }

                    if (selectedUser == null)
                    {
                        Console.WriteLine($" [{choiceText}] is not at valid selection.");
                        Console.WriteLine($" ==> Press <enter> to continue");
                    }
                    else
                    {
                        // ==================================================
                        // this should be as short as possible to limit ability to fradualently reuse,
                        //  but long enough to tolerate clock skew between client and service
                        // ==================================================
                        int ttlMinutes = 5;

                        authcRequest = IsoMsgBuilder.GetAuthMsg();
                        httpBody     = authcRequest.ToString();

                        stw = new Stopwatch();
                        stw.Start();
                        jwtToken = (choiceIndex > 0) ? JwtController.CreateJWTToken(selectedUser.User, selectedUser.Company, JwtController.AUDIENCE, ttlMinutes, httpBody) : string.Empty;
                        stw.Stop();
                        create1stJWTElapsed = stw.ElapsedMilliseconds;

                        // test ben token
                        //string benToken = JwtController.CreateBENJWTToken(selectedUser.User, selectedUser.Company, JwtController.AUDIENCE, ttlMinutes);

                        //stw.Reset();
                        //stw.Start();
                        //jwtToken = (choiceIndex > 0) ? JwtController.CreateJWTToken(selectedUser.User, selectedUser.Company, JwtController.AUDIENCE, ttlMinutes, httpBody) : string.Empty;
                        //stw.Stop();
                        //var create2ndJWTElapsed = stw.ElapsedMilliseconds;

                        //string downstreamJwtToken = (choiceIndex > 0) ? JwtController.CreateDownstreamJWTToken(selectedUser.User, selectedUser.Company, JwtController.AUDIENCE, ttlMinutes, jwtToken) : string.Empty;
                        //stw.Reset();
                        //stw.Start();
                        //var dsT = JwtController.ValidateJWTToken(downstreamJwtToken, JwtController.AUDIENCE);
                        //stw.Stop();
                        //var validate1stJWTElapsed = stw.ElapsedMilliseconds;

                        //stw.Reset();
                        //stw.Start();
                        //dsT = JwtController.ValidateJWTToken(downstreamJwtToken, JwtController.AUDIENCE);
                        //stw.Stop();
                        //var validate2ndJWTElapsed = stw.ElapsedMilliseconds;

                        if (choiceIndex == MOD_PAYLOAD_OPTION)
                        {
                            // simulate man-in-the middle tampering with the payload
                            httpBody = httpBody + "123";
                        }

                        // make the call
                        (HttpStatusCode responseCode, IList <Parameter> responseHeaders, string responseContent) = CallWebApiPost(jwtToken, httpBody);

                        // evaluate the response
                        if (responseCode == HttpStatusCode.OK)
                        {
                            Console.ForegroundColor = ConsoleColor.Green;
                        }
                        else if (responseCode == HttpStatusCode.Unauthorized)
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                        }
                        else
                        {
                            Console.ForegroundColor = ConsoleColor.Cyan;
                        }

                        Console.WriteLine();
                        Console.WriteLine($"responseCode: [{responseCode.ToString()}]");
                        Console.WriteLine();
                        Console.WriteLine($"headers");
                        foreach (var responseHeader in responseHeaders)
                        {
                            Console.WriteLine($"   {responseHeader.Name} : {responseHeader.Value}");
                        }
                        Console.WriteLine();
                        Console.WriteLine($"content: [{responseContent}]");

                        Console.ResetColor();

                        Console.WriteLine($"Create 1st JWT: [{create1stJWTElapsed} mSec]");
                        //Console.WriteLine($"Create 2nd JWT: [{create2ndJWTElapsed} mSec]");
                        //Console.WriteLine($"Valdiate 1st JWT: [{validate1stJWTElapsed} mSec]");
                        //Console.WriteLine($"Valdiate 2nd JWT: [{validate2ndJWTElapsed} mSec]");

                        Console.WriteLine();
                        Console.WriteLine($" ==> Press <enter> to continue");
                    }

                    Console.ReadLine();
                }
            }
        }
Ejemplo n.º 6
0
        //public ActionResult<string> Post([FromBody] string rawRequest)
        public async Task <ActionResult <string> > Post()
        {
            // note: I specficially choose NOT to use the [FromBody] approach to make debugging easier
            //          if we use the [FromBody] approach this method never get control if the body cannot be correctly deserialized
            //          this approach lets us capture the raw body content passed
            string httpBody = Request.GetRawBodyString();

            AuthCRequestBE authRequest = null;

            try
            {
                authRequest = JsonConvert.DeserializeObject <AuthCRequestBE>(httpBody);
            }
            catch (Exception ex)
            {
                // you could do addl logging here to support debugging
                return(BadRequest());
            }

            // look for an Auth Header
            // we expect it to look like:
            // Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjFERTJERjQ2NkQyMTg4RDMyRjc0ODdCMjlCQzc2OTExNURDNTM0NzIiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiJodHRwczovL3d3dy5kYXRhY2Fwc3lzdGVtcy5jb20vIiwiYXVkIjoiaHR0cHM6Ly93d3cud29ybGRwYXkuY29tLyIsImV4cCI6MTU2NDk0MjEwN30.mwwaFczSPP1_EMDcgAdXIbf3hwHw26nTv-kG4b1_EH9q8TFrNMmPMjayyWzHDizbwF-As-6AppaNlMbEQFp-ilXLCx_MAgvff1vNA_qA_wh_t0rcsUO_Evbn5lapoDOCom97cddSIywUnb4zA14TRlrttfuOnpkj08WaR2WM38unpKjBpIHYZJYrrG5Gzyyjs2uzPfCydOCcXVuv3xcVTbmgDGVraDswDMF0xVKHwrFNG9HLfCsJhgA14_puVELPRceuXa_o-u9o05U8-BRrzvyEOxobpXc_z6c0FlnA5OcTGbVDChCASal-8kXjaZYzk1dF-FBQxK3Sj75wCi3IYg
            string authHeader = Request.Headers["Authorization"];

            if (string.IsNullOrEmpty(authHeader))
            {
                return(Unauthorized());
            }
            else
            {
                // parse the header
                var    parts          = authHeader.Split(" ");
                string jwtTokenString = parts[1];

                (bool isJwtTokenValid, string username, JwtSecurityToken jwtToken) = JwtController.ValidateJWTToken(jwtTokenString, JwtController.AUDIENCE);

                if (!isJwtTokenValid)
                {
                    return(Unauthorized());
                }
                else
                {
                    // at this point this controller would add the identity of the authenticated caller as a new HTTP header and call a downstream webapi
                    // this part would typically be in the downstream client and called using await

                    // validate that the body has not body modified
                    string hash = httpBody.SHA256Hash();
                    (string hashType, string bodyHash) = JwtController.GetBodyHashInfo(jwtToken.Payload);
                    if (!string.IsNullOrEmpty(hashType))
                    {
                        if (hashType.ToLower() != @"sha256")
                        {
                            return(BadRequest($"hash type: [{hashType}] is NOT supported, use sha256 instead!"));
                        }

                        if (httpBody.SHA256Hash() != bodyHash)
                        {
                            return(BadRequest($"Post Body has been modified"));
                        }
                    }


                    // in this POC just return the identity that we derived from the JWT
                    var authCResult = new AuthCResultBE()
                    {
                        IsValid = isJwtTokenValid, User = username, JwtToken = jwtTokenString
                    };
                    //return Ok(JsonConvert.SerializeObject(authCResult, Formatting.Indented));
                    return(Ok(authCResult));
                }
            }
        }
Ejemplo n.º 7
0
        public void JwtController_RefreshTokenClockSkewWorks()
        {
            ///////////////////////////////////////////////////////////////////
            // Arrange
            //

            //   Options
            string secret = "A_KEY_MUST_BE_16_CHARS+";
            SymmetricSecurityKey signingKey         = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secret.PadRight(16)));
            SigningCredentials   signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

            /////////////////////////
            int    iAccessValidFor   = 3;
            int    iRefreshValidFor  = 6; // <- Short refresh time for testing
            UInt32 iRefreshClockSkew = 5;
            /////////////////////////

            var jwtIssuerOptions = new JwtIssuerOptions
            {
                Issuer             = "TokenIssuer",
                Audience           = "TokenAudience",
                AccessValidFor     = TimeSpan.FromSeconds(iAccessValidFor),
                RefreshValidFor    = TimeSpan.FromSeconds(iRefreshValidFor),
                AccessClockSkew    = 0,
                RefreshClockSkew   = iRefreshClockSkew,
                Subject            = "Alice",
                SigningCredentials = signingCredentials
            };

            var mockOptions = new Mock <IOptions <JwtIssuerOptions> >();

            mockOptions.Setup(mo => mo.Value).Returns(jwtIssuerOptions);

            //   UserManager
            var fakeUserManager = new FakeUserManager();

            //   TokenStore
            var tokenStore = new ExampleTokenStore();

            //   Configuration
            var mockConfiguration = new Mock <IConfiguration>();

            mockConfiguration.SetupGet(m => m[Constants.SECRET_ENV_VAR]).Returns(secret);

            //   Logger
            var mockLogger = new Mock <ILogger <JwtController> >();

            JwtController controller = new JwtController(mockOptions.Object, fakeUserManager, tokenStore, mockConfiguration.Object, mockLogger.Object);

            // Credentials
            LoginCredentials creds = new LoginCredentials {
                UserName = "******", Password = "******"
            };



            ///////////////////////////////////////////////////////////////////
            // Act
            //

            var issueResult = controller.Issue(creds);

            var typedActionIssueResult = issueResult.Result as Microsoft.AspNetCore.Mvc.OkObjectResult;

            Assert.NotNull(typedActionIssueResult);

            string issueBody = typedActionIssueResult.Value as string;

            Assert.NotNull(issueBody);

            dynamic objResponses  = null;
            bool    bDeserialized = true;

            try
            {
                objResponses = JsonConvert.DeserializeObject <List <dynamic> >(issueBody);
            }
            catch
            {
                bDeserialized = false;
            }

            Assert.True(bDeserialized);
            if (!bDeserialized)
            {
                return;
            }

            // objResponses should be a list of dynamic objects, the first of
            // which should be an access token, the second of which should be
            // a refresh token
            var objResponse0 = objResponses[0]; // Access token wrapper
            var objResponse1 = objResponses[1]; // Refresh token wrapper

            string sRefreshToken = AppUtility.GetDynamicPropertyValueAsString(objResponse1, "refresh_token");

            // ALLOW TIME TO ELAPSE SO THAT THE REFRESH TOKEN IS STALE IF
            // ZERO CLOCK SKEW, BUT JUST ABOUT ACCEPTABLE IF CLOCK SKEW IS WORKING
            System.Threading.Thread.Sleep(1000 * (iRefreshValidFor + (int)iRefreshClockSkew - 2)); // Sleep for at least the timeout time of the refresh token, plus 1 second

            // Call the Refresh endpoint with the token to see if a new pair of tokens are issued.
            var refreshResult = controller.Refresh(sRefreshToken);

            ///////////////////////////////////////////////////////////////////
            // Assert
            //

            var actionResult = refreshResult.Result;

            Assert.Equal("Microsoft.AspNetCore.Mvc.OkObjectResult", actionResult.GetType().ToString());
        }
Ejemplo n.º 8
0
        public void JwtController_CanIssueAndRefreshTokens()
        {
            ///////////////////////////////////////////////////////////////////
            // Arrange
            //

            //   Options
            string secret = "A_KEY_MUST_BE_16_CHARS+";
            SymmetricSecurityKey signingKey         = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secret.PadRight(16)));
            SigningCredentials   signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

            var jwtIssuerOptions = new JwtIssuerOptions
            {
                Issuer             = "TokenIssuer",
                Audience           = "TokenAudience",
                AccessValidFor     = TimeSpan.FromSeconds(10),
                RefreshValidFor    = TimeSpan.FromSeconds(100),
                AccessClockSkew    = 0,
                RefreshClockSkew   = 0,
                Subject            = "Alice",
                SigningCredentials = signingCredentials
            };

            var mockOptions = new Mock <IOptions <JwtIssuerOptions> >();

            mockOptions.Setup(mo => mo.Value).Returns(jwtIssuerOptions);

            //   UserManager
            var fakeUserManager = new FakeUserManager();

            //   TokenStore
            var tokenStore = new ExampleTokenStore();

            //   Configuration
            var mockConfiguration = new Mock <IConfiguration>();

            mockConfiguration.SetupGet(m => m[Constants.SECRET_ENV_VAR]).Returns(secret);

            //   Logger
            var mockLogger = new Mock <ILogger <JwtController> >();

            JwtController controller = new JwtController(mockOptions.Object, fakeUserManager, tokenStore, mockConfiguration.Object, mockLogger.Object);

            // Credentials
            LoginCredentials creds = new LoginCredentials {
                UserName = "******", Password = "******"
            };



            ///////////////////////////////////////////////////////////////////
            // Act
            //

            var issueResult = controller.Issue(creds);

            var typedActionIssueResult = issueResult.Result as Microsoft.AspNetCore.Mvc.OkObjectResult;

            Assert.NotNull(typedActionIssueResult);

            string issueBody = typedActionIssueResult.Value as string;

            Assert.NotNull(issueBody);

            dynamic objResponses  = null;
            bool    bDeserialized = true;

            try
            {
                objResponses = JsonConvert.DeserializeObject <List <dynamic> >(issueBody);
            }
            catch
            {
                bDeserialized = false;
            }

            Assert.True(bDeserialized);
            if (!bDeserialized)
            {
                return;
            }

            // objResponses should be a list of dynamic objects, the first of
            // which should be an access token, the second of which should be
            // a refresh token
            var objResponse0 = objResponses[0]; // Access token wrapper
            var objResponse1 = objResponses[1]; // Refresh token wrapper

            string sRefreshToken = AppUtility.GetDynamicPropertyValueAsString(objResponse1, "refresh_token");

            // Call the Refresh endpoint with the token to see if a new pair of tokens are issued.

            var refreshResult = controller.Refresh(sRefreshToken);

            checkActionResult(refreshResult.Result, jwtIssuerOptions, signingKey);
        }
Ejemplo n.º 9
0
        public void JwtController_CanIssueTokens()
        {
            ///////////////////////////////////////////////////////////////////
            // Arrange
            //

            //   Options
            string secret = "A_KEY_MUST_BE_16_CHARS+";
            SymmetricSecurityKey signingKey         = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secret.PadRight(16)));
            SigningCredentials   signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

            var jwtIssuerOptions = new JwtIssuerOptions
            {
                Issuer          = "TokenIssuer", Audience = "TokenAudience",
                AccessValidFor  = TimeSpan.FromSeconds(10), RefreshValidFor = TimeSpan.FromSeconds(100),
                AccessClockSkew = 0, RefreshClockSkew = 0,
                Subject         = "Alice", SigningCredentials = signingCredentials
            };

            var mockOptions = new Mock <IOptions <JwtIssuerOptions> >();

            mockOptions.Setup(mo => mo.Value).Returns(jwtIssuerOptions);

            //   UserManager
            var fakeUserManager = new FakeUserManager();

            //   TokenStore
            var tokenStore = new ExampleTokenStore();

            //   Configuration
            var mockConfiguration = new Mock <IConfiguration>();

            mockConfiguration.SetupGet(m => m[Constants.SECRET_ENV_VAR]).Returns(secret);

            //   Logger
            var mockLogger = new Mock <ILogger <JwtController> >();

            JwtController controller = new JwtController(mockOptions.Object, fakeUserManager, tokenStore, mockConfiguration.Object, mockLogger.Object);

            // Credentials
            LoginCredentials creds = new LoginCredentials {
                UserName = "******", Password = "******"
            };



            ///////////////////////////////////////////////////////////////////
            // Act
            //

            var result = controller.Issue(creds);


            ///////////////////////////////////////////////////////////////////
            // Assert
            //

            // Task should finish
            var resultStatus = result.Status;

            // Result should be 200 OK
            var actionResult = result.Result;

            checkActionResult(actionResult, jwtIssuerOptions, signingKey);
        }