Beispiel #1
0
        public async Task <IActionResult> Issue(LoginCredentials creds)
        {
            string prefix = nameof(Issue) + Constants.FNSUFFIX;

            string sInvalid = "Invalid Credentials - ";

            if (!ModelState.IsValid)
            {
                return(BadRequest(sInvalid + "(A)"));
            }
            if (creds == null)
            {
                return(BadRequest(sInvalid + "(B)"));
            }
            if (string.IsNullOrWhiteSpace(creds.UserName))
            {
                return(BadRequest(sInvalid + "(C)"));
            }
            if (string.IsNullOrWhiteSpace(creds.Password))
            {
                return(BadRequest(sInvalid + "(D)"));
            }

            var identity = await getClaimsIdentity(creds); // creds=un+pw

            if (identity == null)
            {
                _logger.LogInformation(prefix + $"Invalid username ({creds.UserName}) or password ({creds.Password})");
                return(BadRequest("Invalid credentials (E)"));
            }

            string ip = AppUtility.GetRequestIP(HttpContext, true);

            return(await issueTokens(identity, ip));
        }
Beispiel #2
0
        public async Task <IActionResult> Refresh(string sRefreshToken)
        {
            var    prefix = "Refresh() - ";
            string msg    = "";

            string sInvalid = "Invalid Refesh Token - ";

            if (!ModelState.IsValid)
            {
                return(BadRequest(sInvalid + "(A)"));
            }

            var handler = new JwtSecurityTokenHandler();

            string secret = _configuration[Constants.SECRET_ENV_VAR] ?? "DEFAULT_SECRET_KEY"; // SECRET KEY MUST BE 16 CHARS OR MORE
            SymmetricSecurityKey signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secret.PadRight(16)));

            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer    = _jwtOptions.Issuer,

                ValidateAudience = true,
                ValidAudience    = _jwtOptions.Audience,

                ValidateIssuerSigningKey = true,
                IssuerSigningKey         = signingKey,

                RequireExpirationTime = true,
                ValidateLifetime      = true,

                ClockSkew = TimeSpan.FromSeconds(_jwtOptions.RefreshClockSkew)
            };

            SecurityToken   validatedToken  = null;
            ClaimsPrincipal claimsPrincipal = null;

            try
            {
                claimsPrincipal = handler.ValidateToken(sRefreshToken, tokenValidationParameters, out validatedToken);
            }
            catch (Exception ex)
            {
                msg = $"Refresh Token failed JwtSecurityTokenHandler.ValidateToken(); Token:[{sRefreshToken}]; Ex:[{ex.Message}]; Base:[{ex.GetBaseException().Message}]";
                _logger.LogInformation(prefix + msg);
                return(BadRequest(sInvalid + "(B)"));
            }

            if (validatedToken == null)
            {
                return(BadRequest(sInvalid + "(C)"));
            }

            // OK, we have a valid refresh token.  Does it have the correct custom payload?
            var validatedJwtSecurityToken = validatedToken as JwtSecurityToken;

            if (validatedJwtSecurityToken == null)
            {
                return(BadRequest(sInvalid + "(D)"));
            }

            object objPayloadGuid = null;
            string sPayloadGuid   = "";

            if (validatedJwtSecurityToken.Payload.TryGetValue(GUIDKEY, out objPayloadGuid))
            {
                sPayloadGuid = (objPayloadGuid == null) ? "" : (string)objPayloadGuid;
            }

            if (string.IsNullOrWhiteSpace(sPayloadGuid))
            {
                return(BadRequest(sInvalid + "(E)"));
            }

            object objPayloadName = null;
            string sPayloadName   = "";

            if (validatedJwtSecurityToken.Payload.TryGetValue(NAMEKEY, out objPayloadName))
            {
                sPayloadName = (objPayloadName == null) ? "" : (string)objPayloadName;
            }

            if (string.IsNullOrWhiteSpace(sPayloadName))
            {
                return(BadRequest(sInvalid + "(F)"));
            }

            object objPayloadIP = null;
            string sPayloadIP   = "";

            if (validatedJwtSecurityToken.Payload.TryGetValue(IPKEY, out objPayloadIP))
            {
                sPayloadIP = (objPayloadIP == null) ? "" : (string)objPayloadIP;
            }
            // IP address may be empty

            // Payload values are now known to not be null

            // Check against database.
            var appJwtRefreshToken = await _tokenStore.ExtractByGuidAsync(sPayloadGuid, new CancellationToken());

            if (!string.Equals(appJwtRefreshToken.Guid, sPayloadGuid, StringComparison.OrdinalIgnoreCase))
            {
                return(BadRequest(sInvalid + "(G)"));
            }

            if (!string.Equals(appJwtRefreshToken.Name, sPayloadName, StringComparison.OrdinalIgnoreCase))
            {
                return(BadRequest(sInvalid + "(H)"));
            }

            if (!string.Equals(appJwtRefreshToken.IP, sPayloadIP, StringComparison.OrdinalIgnoreCase))
            {
                return(BadRequest(sInvalid + "(I)"));
            }

            // Payload values match those in the database.

            // The token has an IP address in it;  The request has an IP address;  The database has the issued IP address;
            // If the incoming request's IP address differs from the recorded IP address, the user may have legitimately
            // switched IP addresses, or a legitimate refresh token may have been stolen by a bad actor and they may be
            // trying to get access tokens using a stolen token.  Force a re-authentication just in case.
            string ip = AppUtility.GetRequestIP(HttpContext, true);

            if (!string.Equals(ip, appJwtRefreshToken.IP))
            {
                return(BadRequest(sInvalid + "(I)"));
            }


            // If valid, re-pull the claims in case the roles have changed,
            // or the user has been locked out for being evil, and re-issue.
            ApplicationUser user = _userManager.FindByNameAsync(sPayloadName).Result;

            if (user == null)
            {
                return(BadRequest($"User [{user.UserName}] not found"));
            }

            if (!user.Enabled)
            {
                return(BadRequest($"User [{user.UserName}] is not enabled"));
            }

            // We have an active user, who is not evil.
            // Re-pulling their claimsIdentity ensures that the new tokens issued have recent claims.

            ClaimsIdentity identity = getClaimsIdentityForAppUser(user).Result;

            return(await issueTokens(identity, ip));
        }