Exemplo n.º 1
0
        public IActionResult AuthCodeV2_Grant([FromQuery] AuthCodeV2 input)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            //clean out cruft from encoding...
            input.issuer       = HttpUtility.UrlDecode(input.issuer);
            input.client       = HttpUtility.UrlDecode(input.client);
            input.user         = HttpUtility.UrlDecode(input.user);
            input.redirect_uri = HttpUtility.UrlDecode(input.redirect_uri);
            input.code         = HttpUtility.UrlDecode(input.code);
            input.state        = HttpUtility.UrlDecode(input.state);

            if (!Uri.IsWellFormedUriString(input.redirect_uri, UriKind.Absolute))
            {
                ModelState.AddModelError(MessageType.UriInvalid.ToString(), $"Uri:{input.redirect_uri}");
                return(BadRequest(ModelState));
            }

            Guid       issuerID;
            tbl_Issuer issuer;

            //check if identifier is guid. resolve to guid if not.
            if (Guid.TryParse(input.issuer, out issuerID))
            {
                issuer = uow.Issuers.Get(x => x.Id == issuerID).SingleOrDefault();
            }
            else
            {
                issuer = uow.Issuers.Get(x => x.Name == input.issuer).SingleOrDefault();
            }

            if (issuer == null)
            {
                ModelState.AddModelError(MessageType.IssuerNotFound.ToString(), $"Issuer:{input.issuer}");
                return(NotFound(ModelState));
            }
            else if (!issuer.IsEnabled)
            {
                ModelState.AddModelError(MessageType.IssuerInvalid.ToString(), $"Issuer:{issuer.Id}");
                return(BadRequest(ModelState));
            }

            Guid     userID;
            tbl_User user;

            //check if identifier is guid. resolve to guid if not.
            if (Guid.TryParse(input.user, out userID))
            {
                user = uow.Users.Get(x => x.Id == userID).SingleOrDefault();
            }
            else
            {
                user = uow.Users.Get(x => x.UserName == input.user).SingleOrDefault();
            }

            if (user == null)
            {
                ModelState.AddModelError(MessageType.UserNotFound.ToString(), $"User:{input.user}");
                return(NotFound(ModelState));
            }
            //check that user is confirmed...
            //check that user is not locked...
            else if (uow.Users.IsLockedOut(user) ||
                     !user.EmailConfirmed ||
                     !user.PasswordConfirmed)
            {
                ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}");
                return(BadRequest(ModelState));
            }

            var audienceList = uow.Audiences.Get(QueryExpressionFactory.GetQueryExpression <tbl_Audience>()
                                                 .Where(x => x.tbl_Roles.Any(y => y.tbl_UserRoles.Any(z => z.UserId == user.Id))).ToLambda());
            var audiences = new List <tbl_Audience>();

            //check if client is single, multiple or undefined...
            if (string.IsNullOrEmpty(input.client))
            {
                audiences = uow.Audiences.Get(x => audienceList.Contains(x) &&
                                              x.IsLockedOut == false).ToList();
            }
            else
            {
                foreach (string entry in input.client.Split(","))
                {
                    Guid         audienceID;
                    tbl_Audience audience;

                    //check if identifier is guid. resolve to guid if not.
                    if (Guid.TryParse(entry.Trim(), out audienceID))
                    {
                        audience = uow.Audiences.Get(x => x.Id == audienceID, y => y.Include(z => z.tbl_Urls)).SingleOrDefault();
                    }
                    else
                    {
                        audience = uow.Audiences.Get(x => x.Name == entry.Trim(), y => y.Include(z => z.tbl_Urls)).SingleOrDefault();
                    }

                    if (audience == null)
                    {
                        ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:{input.client}");
                        return(NotFound(ModelState));
                    }
                    else if (audience.IsLockedOut ||
                             !audienceList.Contains(audience))
                    {
                        ModelState.AddModelError(MessageType.AudienceInvalid.ToString(), $"Audience:{audience.Id}");
                        return(BadRequest(ModelState));
                    }

                    audiences.Add(audience);
                }
            }

            if (audiences.Count == 0)
            {
                ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:None");
                return(BadRequest(ModelState));
            }

            //check if client uri is valid...
            var redirect = new Uri(input.redirect_uri);

            foreach (var entry in audiences)
            {
                if (!entry.tbl_Urls.Where(x => x.UrlHost == null && x.UrlPath == redirect.AbsolutePath).Any() &&
                    !entry.tbl_Urls.Where(x => new Uri(x.UrlHost + x.UrlPath).AbsoluteUri == redirect.AbsoluteUri).Any())
                {
                    ModelState.AddModelError(MessageType.UriInvalid.ToString(), $"Uri:{input.redirect_uri}");
                    return(BadRequest(ModelState));
                }
            }

            //check if state is valid...
            var state = uow.States.Get(x => x.StateValue == input.state &&
                                       x.ValidFromUtc <DateTime.UtcNow &&
                                                       x.ValidToUtc> DateTime.UtcNow &&
                                       x.StateType == ConsumerType.User.ToString()).SingleOrDefault();

            if (state == null)
            {
                ModelState.AddModelError(MessageType.StateNotFound.ToString(), $"User code:{input.state}");
                return(BadRequest(ModelState));
            }

            //check that payload can be decrypted and validated...
            if (!new PasswordTokenFactory(uow.InstanceType.ToString()).Validate(user.SecurityStamp, input.code, user.Id.ToString(), user.SecurityStamp))
            {
                uow.AuthActivity.Create(
                    map.Map <tbl_AuthActivity>(new AuthActivityV1()
                {
                    UserId       = user.Id,
                    LoginType    = GrantFlowType.AuthorizationCodeV2.ToString(),
                    LoginOutcome = GrantFlowResultType.Failure.ToString(),
                }));

                uow.Commit();

                ModelState.AddModelError(MessageType.TokenInvalid.ToString(), $"Token:{input.code}");
                return(BadRequest(ModelState));
            }

            var ac_claims = uow.Users.GenerateAccessClaims(issuer, user);
            var ac        = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), ac_claims);

            uow.AuthActivity.Create(
                map.Map <tbl_AuthActivity>(new AuthActivityV1()
            {
                UserId       = user.Id,
                LoginType    = GrantFlowType.AuthorizationCodeV2.ToString(),
                LoginOutcome = GrantFlowResultType.Success.ToString(),
            }));

            var rt_claims = uow.Users.GenerateRefreshClaims(issuer, user);
            var rt        = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), rt_claims);

            uow.Refreshes.Create(
                map.Map <tbl_Refresh>(new RefreshV1()
            {
                IssuerId     = issuer.Id,
                UserId       = user.Id,
                RefreshType  = ConsumerType.User.ToString(),
                RefreshValue = rt.RawData,
                ValidFromUtc = rt.ValidFrom,
                ValidToUtc   = rt.ValidTo,
            }));

            uow.AuthActivity.Create(
                map.Map <tbl_AuthActivity>(new AuthActivityV1()
            {
                UserId       = user.Id,
                LoginType    = GrantFlowType.RefreshTokenV2.ToString(),
                LoginOutcome = GrantFlowResultType.Success.ToString(),
            }));

            uow.Commit();

            var result = new UserJwtV2()
            {
                token_type    = "bearer",
                access_token  = ac.RawData,
                refresh_token = rt.RawData,
                user          = user.UserName,
                client        = audiences.Select(x => x.Name).ToList(),
                issuer        = issuer.Name + ":" + conf["IdentityTenant:Salt"],
                expires_in    = (int)(new DateTimeOffset(ac.ValidTo).Subtract(DateTime.UtcNow)).TotalSeconds,
            };

            return(Ok(result));
        }
Exemplo n.º 2
0
        public IActionResult ResourceOwnerV2_Grant([FromForm] ResourceOwnerV2 input)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            Guid       issuerID;
            tbl_Issuer issuer;

            //check if identifier is guid. resolve to guid if not.
            if (Guid.TryParse(input.issuer, out issuerID))
            {
                issuer = uow.Issuers.Get(x => x.Id == issuerID).SingleOrDefault();
            }
            else
            {
                issuer = uow.Issuers.Get(x => x.Name == input.issuer).SingleOrDefault();
            }

            if (issuer == null)
            {
                ModelState.AddModelError(MessageType.IssuerNotFound.ToString(), $"Issuer:{input.issuer}");
                return(NotFound(ModelState));
            }
            else if (!issuer.IsEnabled)
            {
                ModelState.AddModelError(MessageType.IssuerInvalid.ToString(), $"Issuer:{issuer.Id}");
                return(BadRequest(ModelState));
            }

            Guid     userID;
            tbl_User user;

            //check if identifier is guid. resolve to guid if not.
            if (Guid.TryParse(input.user, out userID))
            {
                user = uow.Users.Get(x => x.Id == userID).SingleOrDefault();
            }
            else
            {
                user = uow.Users.Get(x => x.UserName == input.user).SingleOrDefault();
            }

            if (user == null)
            {
                ModelState.AddModelError(MessageType.UserNotFound.ToString(), $"User:{input.user}");
                return(NotFound(ModelState));
            }
            //check that user is confirmed...
            //check that user is not locked...
            else if (uow.Users.IsLockedOut(user) ||
                     !user.EmailConfirmed ||
                     !user.PasswordConfirmed)
            {
                ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}");
                return(BadRequest(ModelState));
            }

            var audienceList = uow.Audiences.Get(QueryExpressionFactory.GetQueryExpression <tbl_Audience>()
                                                 .Where(x => x.tbl_Roles.Any(y => y.tbl_UserRoles.Any(z => z.UserId == user.Id))).ToLambda());

            var audiences = new List <tbl_Audience>();

            //check if client is single, multiple or undefined...
            if (string.IsNullOrEmpty(input.client))
            {
                audiences = uow.Audiences.Get(x => audienceList.Contains(x) &&
                                              x.IsLockedOut == false).ToList();
            }
            else
            {
                foreach (string entry in input.client.Split(","))
                {
                    Guid         audienceID;
                    tbl_Audience audience;

                    //check if identifier is guid. resolve to guid if not.
                    if (Guid.TryParse(entry.Trim(), out audienceID))
                    {
                        audience = uow.Audiences.Get(x => x.Id == audienceID).SingleOrDefault();
                    }
                    else
                    {
                        audience = uow.Audiences.Get(x => x.Name == entry.Trim()).SingleOrDefault();
                    }

                    if (audience == null)
                    {
                        ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:{entry}");
                        return(NotFound(ModelState));
                    }
                    else if (audience.IsLockedOut ||
                             !audienceList.Contains(audience))
                    {
                        ModelState.AddModelError(MessageType.AudienceInvalid.ToString(), $"Audience:{audience.Id}");
                        return(BadRequest(ModelState));
                    }

                    audiences.Add(audience);
                }
            }

            if (audiences.Count == 0)
            {
                ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:None");
                return(BadRequest(ModelState));
            }

            var logins = uow.Logins.Get(QueryExpressionFactory.GetQueryExpression <tbl_Login>()
                                        .Where(x => x.tbl_UserLogins.Any(y => y.UserId == user.Id)).ToLambda());

            switch (uow.InstanceType)
            {
            case InstanceContext.DeployedOrLocal:
            case InstanceContext.End2EndTest:
            {
                //check if login provider is local...
                if (logins.Where(x => x.Name.Equals(DefaultConstants.LoginName, StringComparison.OrdinalIgnoreCase)).Any())
                {
                    //check that password is valid...
                    if (!PBKDF2.Validate(user.PasswordHashPBKDF2, input.password))
                    {
                        uow.AuthActivity.Create(
                            map.Map <tbl_AuthActivity>(new AuthActivityV1()
                            {
                                UserId       = user.Id,
                                LoginType    = GrantFlowType.ResourceOwnerPasswordV2.ToString(),
                                LoginOutcome = GrantFlowResultType.Failure.ToString(),
                            }));

                        uow.Commit();

                        ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}");
                        return(BadRequest(ModelState));
                    }
                }
                else
                {
                    ModelState.AddModelError(MessageType.LoginNotFound.ToString(), $"No login for user:{user.Id}");
                    return(NotFound(ModelState));
                }
            }
            break;

            case InstanceContext.SystemTest:
            case InstanceContext.IntegrationTest:
            {
                //check if login provider is local or test...
                if (logins.Where(x => x.Name.Equals(DefaultConstants.LoginName, StringComparison.OrdinalIgnoreCase)).Any() ||
                    logins.Where(x => x.Name.StartsWith(TestDefaultConstants.LoginName, StringComparison.OrdinalIgnoreCase)).Any())
                {
                    //check that password is valid...
                    if (!PBKDF2.Validate(user.PasswordHashPBKDF2, input.password))
                    {
                        uow.AuthActivity.Create(
                            map.Map <tbl_AuthActivity>(new AuthActivityV1()
                            {
                                UserId       = user.Id,
                                LoginType    = GrantFlowType.ResourceOwnerPasswordV2.ToString(),
                                LoginOutcome = GrantFlowResultType.Failure.ToString(),
                            }));

                        uow.Commit();

                        ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}");
                        return(BadRequest(ModelState));
                    }
                }
                else
                {
                    ModelState.AddModelError(MessageType.LoginNotFound.ToString(), $"No login for user:{user.Id}");
                    return(NotFound(ModelState));
                }
            }
            break;

            default:
                throw new NotImplementedException();
            }

            var rop_claims = uow.Users.GenerateAccessClaims(issuer, user);
            var rop        = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), rop_claims);

            uow.AuthActivity.Create(
                map.Map <tbl_AuthActivity>(new AuthActivityV1()
            {
                UserId       = user.Id,
                LoginType    = GrantFlowType.ResourceOwnerPasswordV2.ToString(),
                LoginOutcome = GrantFlowResultType.Success.ToString(),
            }));

            var rt_claims = uow.Users.GenerateRefreshClaims(issuer, user);
            var rt        = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), rt_claims);

            uow.Refreshes.Create(
                map.Map <tbl_Refresh>(new RefreshV1()
            {
                IssuerId     = issuer.Id,
                UserId       = user.Id,
                RefreshType  = ConsumerType.User.ToString(),
                RefreshValue = rt.RawData,
                IssuedUtc    = rt.ValidFrom,
                ValidFromUtc = rt.ValidFrom,
                ValidToUtc   = rt.ValidTo,
            }));

            uow.AuthActivity.Create(
                map.Map <tbl_AuthActivity>(new AuthActivityV1()
            {
                UserId       = user.Id,
                LoginType    = GrantFlowType.RefreshTokenV2.ToString(),
                LoginOutcome = GrantFlowResultType.Success.ToString(),
            }));

            uow.Commit();

            var result = new UserJwtV2()
            {
                token_type    = "bearer",
                access_token  = rop.RawData,
                refresh_token = rt.RawData,
                user          = user.UserName,
                client        = audiences.Select(x => x.Name).ToList(),
                issuer        = issuer.Name + ":" + conf["IdentityTenant:Salt"],
                expires_in    = (int)(new DateTimeOffset(rop.ValidTo).Subtract(DateTime.UtcNow)).TotalSeconds,
            };

            return(Ok(result));
        }
Exemplo n.º 3
0
        public IActionResult ResourceOwnerV2_Refresh([FromForm] RefreshTokenV2 input)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            var refresh = uow.Refreshes.Get(QueryExpressionFactory.GetQueryExpression <tbl_Refresh>()
                                            .Where(x => x.RefreshValue == input.refresh_token).ToLambda()).SingleOrDefault();

            if (refresh == null)
            {
                ModelState.AddModelError(MessageType.TokenInvalid.ToString(), $"Token:{input.refresh_token}");
                return(NotFound(ModelState));
            }
            else if (!string.Equals(refresh.RefreshType, ConsumerType.User.ToString(), StringComparison.OrdinalIgnoreCase) ||
                     (refresh.ValidFromUtc >= DateTime.UtcNow || refresh.ValidToUtc <= DateTime.UtcNow))
            {
                ModelState.AddModelError(MessageType.TokenInvalid.ToString(), $"Token:{input.refresh_token}");
                return(BadRequest(ModelState));
            }

            Guid       issuerID;
            tbl_Issuer issuer;

            //check if identifier is guid. resolve to guid if not.
            if (Guid.TryParse(input.issuer, out issuerID))
            {
                issuer = uow.Issuers.Get(x => x.Id == issuerID).SingleOrDefault();
            }
            else
            {
                issuer = uow.Issuers.Get(x => x.Name == input.issuer).SingleOrDefault();
            }

            if (issuer == null)
            {
                ModelState.AddModelError(MessageType.IssuerNotFound.ToString(), $"Issuer:{input.issuer}");
                return(NotFound(ModelState));
            }
            else if (!issuer.IsEnabled)
            {
                ModelState.AddModelError(MessageType.IssuerInvalid.ToString(), $"Issuer:{issuer.Id}");
                return(BadRequest(ModelState));
            }

            var user = uow.Users.Get(x => x.Id == refresh.UserId).SingleOrDefault();

            //check that user exists...
            if (user == null)
            {
                ModelState.AddModelError(MessageType.UserNotFound.ToString(), $"User:{refresh.UserId}");
                return(NotFound(ModelState));
            }
            //check that user is not locked...
            else if (uow.Users.IsLockedOut(user) ||
                     !user.EmailConfirmed ||
                     !user.PasswordConfirmed)
            {
                ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}");
                return(BadRequest(ModelState));
            }

            var clientList = uow.Audiences.Get(QueryExpressionFactory.GetQueryExpression <tbl_Audience>()
                                               .Where(x => x.tbl_Roles.Any(y => y.tbl_UserRoles.Any(z => z.UserId == user.Id))).ToLambda());

            var audiences = new List <tbl_Audience>();

            //check if client is single, multiple or undefined...
            if (string.IsNullOrEmpty(input.client))
            {
                audiences = uow.Audiences.Get(x => clientList.Contains(x) &&
                                              x.IsLockedOut == false).ToList();
            }
            else
            {
                foreach (string entry in input.client.Split(","))
                {
                    Guid         audienceID;
                    tbl_Audience audience;

                    //check if identifier is guid. resolve to guid if not.
                    if (Guid.TryParse(entry.Trim(), out audienceID))
                    {
                        audience = uow.Audiences.Get(x => x.Id == audienceID).SingleOrDefault();
                    }
                    else
                    {
                        audience = uow.Audiences.Get(x => x.Name == entry.Trim()).SingleOrDefault();
                    }

                    if (audience == null)
                    {
                        ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:{entry}");
                        return(NotFound(ModelState));
                    }
                    else if (audience.IsLockedOut ||
                             !clientList.Contains(audience))
                    {
                        ModelState.AddModelError(MessageType.AudienceInvalid.ToString(), $"Audience:{audience.Id}");
                        return(BadRequest(ModelState));
                    }

                    audiences.Add(audience);
                }
            }

            if (audiences.Count == 0)
            {
                ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:None");
                return(BadRequest(ModelState));
            }

            var rop_claims = uow.Users.GenerateAccessClaims(issuer, user);
            var rop        = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), rop_claims);

            var rt_claims = uow.Users.GenerateRefreshClaims(issuer, user);
            var rt        = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], audiences.Select(x => x.Name).ToList(), rt_claims);

            uow.Refreshes.Create(
                map.Map <tbl_Refresh>(new RefreshV1()
            {
                IssuerId     = issuer.Id,
                UserId       = user.Id,
                RefreshType  = ConsumerType.User.ToString(),
                RefreshValue = rt.RawData,
                IssuedUtc    = rt.ValidFrom,
                ValidFromUtc = rt.ValidFrom,
                ValidToUtc   = rt.ValidTo,
            }));

            uow.AuthActivity.Create(
                map.Map <tbl_AuthActivity>(new AuthActivityV1()
            {
                UserId       = user.Id,
                LoginType    = GrantFlowType.RefreshTokenV2.ToString(),
                LoginOutcome = GrantFlowResultType.Success.ToString(),
            }));

            uow.Commit();

            var result = new UserJwtV2()
            {
                token_type    = "bearer",
                access_token  = rop.RawData,
                refresh_token = rt.RawData,
                user          = user.UserName,
                client        = audiences.Select(x => x.Name).ToList(),
                issuer        = issuer.Name + ":" + conf["IdentityTenant:Salt"],
                expires_in    = (int)(new DateTimeOffset(rop.ValidTo).Subtract(DateTime.UtcNow)).TotalSeconds,
            };

            return(Ok(result));
        }
Exemplo n.º 4
0
        public IActionResult DeviceCodeV2_Grant([FromForm] DeviceCodeV2 input)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            Guid       issuerID;
            tbl_Issuer issuer;

            //check if identifier is guid. resolve to guid if not.
            if (Guid.TryParse(input.issuer, out issuerID))
            {
                issuer = uow.Issuers.Get(x => x.Id == issuerID).SingleOrDefault();
            }
            else
            {
                issuer = uow.Issuers.Get(x => x.Name == input.issuer).SingleOrDefault();
            }

            if (issuer == null)
            {
                ModelState.AddModelError(MessageType.IssuerNotFound.ToString(), $"Issuer:{input.issuer}");
                return(NotFound(ModelState));
            }
            else if (!issuer.IsEnabled)
            {
                ModelState.AddModelError(MessageType.IssuerInvalid.ToString(), $"Issuer:{issuer.Id}");
                return(BadRequest(ModelState));
            }

            Guid         audienceID;
            tbl_Audience audience;

            //check if identifier is guid. resolve to guid if not.
            if (Guid.TryParse(input.client, out audienceID))
            {
                audience = uow.Audiences.Get(x => x.Id == audienceID).SingleOrDefault();
            }
            else
            {
                audience = uow.Audiences.Get(x => x.Name == input.client).SingleOrDefault();
            }

            if (audience == null)
            {
                ModelState.AddModelError(MessageType.AudienceNotFound.ToString(), $"Audience:{input.client}");
                return(NotFound(ModelState));
            }
            else if (audience.IsLockedOut)
            {
                ModelState.AddModelError(MessageType.AudienceInvalid.ToString(), $"Audience:{audience.Id}");
                return(BadRequest(ModelState));
            }

            var polling = uow.Settings.Get(x => x.IssuerId == issuer.Id && x.AudienceId == null && x.UserId == null &&
                                           x.ConfigKey == SettingsConstants.PollingMax).Single();

            //check if state is valid...
            var state = uow.States.Get(x => x.StateValue == input.device_code &&
                                       x.StateType == ConsumerType.Device.ToString() &&
                                       x.ValidFromUtc <DateTime.UtcNow &&
                                                       x.ValidToUtc> DateTime.UtcNow).SingleOrDefault();

            if (state == null ||
                state.StateConsume == true)
            {
                ModelState.AddModelError(MessageType.StateInvalid.ToString(), $"Device code:{input.device_code}");
                return(BadRequest(ModelState));
            }
            //check if device is polling too frequently...
            else if (uint.Parse(polling.ConfigValue) <= (state.LastPollingUtc.Subtract(DateTime.UtcNow)).TotalSeconds)
            {
                state.LastPollingUtc = DateTime.UtcNow;
                state.StateConsume   = false;

                uow.States.Update(state);
                uow.Commit();

                ModelState.AddModelError(MessageType.StateSlowDown.ToString(), $"Device code:{input.device_code}");
                return(BadRequest(ModelState));
            }

            //check if device has been approved/denied...
            if (!state.StateDecision.HasValue)
            {
                ModelState.AddModelError(MessageType.StatePending.ToString(), $"Device code:{input.device_code}");
                return(BadRequest(ModelState));
            }
            else if (state.StateDecision.HasValue &&
                     !state.StateDecision.Value)
            {
                ModelState.AddModelError(MessageType.StateDenied.ToString(), $"Device code:{input.device_code}");
                return(BadRequest(ModelState));
            }

            var user = uow.Users.Get(x => x.Id == state.UserId).SingleOrDefault();

            if (user == null)
            {
                ModelState.AddModelError(MessageType.UserNotFound.ToString(), $"User:{state.UserId}");
                return(NotFound(ModelState));
            }
            //check that user is confirmed...
            //check that user is not locked...
            else if (uow.Users.IsLockedOut(user) ||
                     !user.EmailConfirmed ||
                     !user.PasswordConfirmed)
            {
                ModelState.AddModelError(MessageType.UserInvalid.ToString(), $"User:{user.Id}");
                return(BadRequest(ModelState));
            }

            if (!new TimeBasedTokenFactory(8, 10).Validate(user.SecurityStamp, input.user_code, user.Id.ToString()))
            {
                uow.AuthActivity.Create(
                    map.Map <tbl_AuthActivity>(new AuthActivityV1()
                {
                    UserId       = user.Id,
                    LoginType    = GrantFlowType.DeviceCodeV2.ToString(),
                    LoginOutcome = GrantFlowResultType.Failure.ToString(),
                }));

                uow.Commit();

                ModelState.AddModelError(MessageType.TokenInvalid.ToString(), $"Token:{input.user_code}");
                return(BadRequest(ModelState));
            }

            //no reuse of state after this...
            state.LastPollingUtc = DateTime.UtcNow;
            state.StateConsume   = true;

            //adjust state...
            uow.States.Update(state);

            var dc_claims = uow.Users.GenerateAccessClaims(issuer, user);
            var dc        = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], new List <string>()
            {
                audience.Name
            }, dc_claims);

            uow.AuthActivity.Create(
                map.Map <tbl_AuthActivity>(new AuthActivityV1()
            {
                UserId       = user.Id,
                LoginType    = GrantFlowType.DeviceCodeV2.ToString(),
                LoginOutcome = GrantFlowResultType.Success.ToString(),
            }));

            var rt_claims = uow.Users.GenerateRefreshClaims(issuer, user);
            var rt        = auth.ResourceOwnerPassword(issuer.Name, issuer.IssuerKey, conf["IdentityTenant:Salt"], new List <string>()
            {
                audience.Name
            }, rt_claims);

            uow.Refreshes.Create(
                map.Map <tbl_Refresh>(new RefreshV1()
            {
                IssuerId     = issuer.Id,
                UserId       = user.Id,
                RefreshType  = ConsumerType.User.ToString(),
                RefreshValue = rt.RawData,
                ValidFromUtc = rt.ValidFrom,
                ValidToUtc   = rt.ValidTo,
            }));

            uow.AuthActivity.Create(
                map.Map <tbl_AuthActivity>(new AuthActivityV1()
            {
                UserId       = user.Id,
                LoginType    = GrantFlowType.RefreshTokenV2.ToString(),
                LoginOutcome = GrantFlowResultType.Success.ToString(),
            }));

            uow.Commit();

            var result = new UserJwtV2()
            {
                token_type    = "bearer",
                access_token  = dc.RawData,
                refresh_token = rt.RawData,
                user          = user.UserName,
                client        = new List <string>()
                {
                    audience.Name
                },
                issuer     = issuer.Name + ":" + conf["IdentityTenant:Salt"],
                expires_in = (int)(new DateTimeOffset(dc.ValidTo).Subtract(DateTime.UtcNow)).TotalSeconds,
            };

            return(Ok(result));
        }