예제 #1
0
        public override void OnNewIncident(IIncidentLog newEntry)
        {
            //if login failed with user name that matches a login in database, we log this loginId in KeyId1
            var failedUserName = newEntry.Key1;

            if (string.IsNullOrWhiteSpace(failedUserName))
            {
                return;
            }
            var tenantId = newEntry.KeyId2;

            var utcNow            = _app.TimeService.UtcNow;
            var session           = _app.OpenSystemSession();
            var fromDate          = utcNow.Subtract(Settings.TimeWindow);
            var strLoginFailed    = LoginEventType.LoginFailed.ToString();
            var qryRecentFailures = from lg in session.EntitySet <IIncidentLog>()
                                    where lg.CreatedOn >= fromDate && lg.Key1 == failedUserName &&
                                    lg.Type == LoginModule.LoginIncidentType && lg.SubType == strLoginFailed
                                    select lg;

            //Note: currently LINQ translator does not handle correctly comparing nullable values, so adding this separately
            if (tenantId != null)
            {
                qryRecentFailures = qryRecentFailures.Where(lg => lg.KeyId2 == tenantId.Value);
            }
            var failCount = qryRecentFailures.Count();

            if (failCount < Settings.FailureCount)
            {
                return; //not yet
            }
            // We have repeated login failures in short period of time; this might be an attack - suspend account(s) for several minutes
            // find Login(s) - might be more than one - we may have the same username for different tenants
            var loginSet   = session.EntitySet <ILogin>();
            var loginQuery = from lg in loginSet
                             where lg.UserName == failedUserName
                             select lg;

            if (tenantId != null)
            {
                loginQuery = loginQuery.Where(lg => lg.TenantId == tenantId.Value);
            }
            var logins = loginQuery.ToList();

            if (logins.Count == 0)
            {
                return; //it might happen if user name is not known
            }
            //Suspend login
            var suspendedUntil  = utcNow.Add(Settings.SuspensionPeriod);
            var loginLogService = _app.GetService <ILoginLogService>();
            var msg             = StringHelper.SafeFormat("{0} login failures. Login {1} suspended until {2}", failCount, failedUserName, suspendedUntil);
            var loginModule     = _app.GetModule <LoginModule>();

            foreach (var lg in logins)
            {
                // if already suspended or disabled, do not suspend again
                if (lg.Flags.IsSet(LoginFlags.Disabled | LoginFlags.Suspended))
                {
                    continue;
                }
                lg.Flags         |= LoginFlags.Suspended;
                lg.SuspendedUntil = suspendedUntil;
                //raise event - it will log to login log
                loginModule.OnLoginEvent(session.Context, LoginEventType.LoginSuspended, lg, msg, failedUserName);
            }
            session.SaveChanges();
            var incService = _app.GetService <IIncidentLogService>();

            incService.LogIncident(LoginModule.LoginIncidentType, msg, LoginEventType.LoginSuspended.ToString(), key1: failedUserName, keyId2: tenantId);
        }