protected void Application_AuthenticateRequest(Object sender, EventArgs e) { // reset Context.User = null; FeeblPrincipal.Current = null; // get new FeeblPrincipal.Current = new FeeblPrincipal(); var cookieName = FormsAuthentication.FormsCookieName; var authCookie = Context.Request.Cookies[cookieName]; if (authCookie == null) { return; } using (var ctx = new FeeblDataContext()) { var ticket = FormsAuthentication.Decrypt(authCookie.Value); if (ticket == null) { return; } var password = ticket.UserData; var userIdentity = new FeeblIdentity(ctx, ticket.Name, password); var userPrincipal = new FeeblPrincipal(userIdentity); Context.User = userPrincipal; FeeblPrincipal.Current = userPrincipal; } }
public void Update(string applicationID, string customerID, string processID, int counter, string hash, DateTime utcProcessingTime) { #region Rate limiting (TokenBucket) while (TokenBucket.ContainsKey(processID) && TokenBucket[processID] > DateTime.Now.AddSeconds(-Limit).Ticks) { Thread.Sleep(Refresh); } TokenBucket[processID] = DateTime.Now.Ticks; #endregion #region Check challenge HashAlgorithm algorithm = SHA1.Create(); var x = algorithm.ComputeHash(Encoding.UTF8.GetBytes(applicationID + customerID + processID + counter)); var sb = new StringBuilder(); foreach (var b in x) { sb.Append(b.ToString("X2")); } var counterchallenge = sb[17] + sb[Math.Abs(counter) % sb.Length] + sb.ToString().Substring(1, 7); if (counterchallenge != hash) { throw new ArgumentException("Invalid hash."); } #endregion using (var ctx = new FeeblDataContext()) { var application = ctx.Applications.FirstOrDefault(a => a.Name == applicationID.Trim()) ?? new Application { Name = applicationID }; var customer = ctx.Customers.FirstOrDefault(c => c.Name == customerID.Trim()) ?? new Customer { Name = customerID }; var process = ctx.Processes.FirstOrDefault(p => p.Application == application && p.Customer == customer && p.Name == processID) ?? new Process { Application = application, Customer = customer, Name = processID, URL = string.Empty, GroupID = string.Empty }; process.LastRunTime = utcProcessingTime; var groupIndex = processID.IndexOf("@", StringComparison.Ordinal); if (groupIndex > 0) { process.GroupID = processID.Substring(groupIndex + 1).Trim(); } ctx.Events.InsertOnSubmit(new Event { Process = process, CreationTime = utcProcessingTime, Counter = counter }); ctx.SubmitChanges(); } }
public void Update(FeeblDataContext ctx, bool isMet, string remark, int?counter) { // if the demand was still not met (it failed previously and is still failed) and it's priority is Normal or higher // we will initiate a ticket log for support if (!IsMet && !isMet && Priority >= (int)Lists.Priority.Normal) { // find the last log of state change for this demand var log = (from h in Histories orderby h.HistoryID descending select h).FirstOrDefault(); // create a buffer of MaxRunTime ?? 30 minutes and check the IsExported flag to prevent doubles if (log != null && log.Status == "Failed" && !log.IsExported && log.CreationTime <= DateTime.UtcNow.AddMinutes(-(MaxRunTime ?? 30))) { var subject = string.Format("{0} failed for {1} @ {2}", Process.Name, Process.Application.Name, Process.Customer.Name); if (Priority >= (int)Lists.Priority.High) { subject = "[PRIO: HIGH] " + subject; } var message = counter.HasValue ? string.Format("{0} / {1}", Methods.GetCounterValue(counter.Value), Methods.GetCounterValue(QuantityValue)) : string.Format("{0}, last run {1}", NextRunTime.Value.ToCET().ToString("MM/dd HH:mm"), Process.LastRunTime.HasValue ? Process.LastRunTime.Value.ToCET().ToString("MM/dd HH:mm") : "never"); var subscribers = Process.UserSubscriptions.Select(s => s.User.Email).Distinct().ToArray(); // include related users, in case of backup procedures var related = (from p in ctx.Processes from s in p.UserSubscriptions where p.CustomerID == Process.CustomerID && p.ApplicationID == Process.ApplicationID select s.User.Email).Distinct().ToArray(); var mail = new Email { Subject = subject, Body = $"{subject}<br /><br />Failed at {message}<br /><br />{Comment}<br /><br />Subscribers: {string.Join(",", subscribers)}<br />Related: {string.Join(",", related)}<br /><br />{Methods.GetUrl($"Demand?processID={ProcessID}")}" }; mail.AddReceipient("*****@*****.**"); mail.Send(); log.IsExported = true; } } // if there was a change in condition (we either failed a green process or just resolved a red process) // make sure the proper users are notified of this change else if (IsMet != isMet) { var diff = !isMet ? "Failed" : "Resolved"; ctx.Histories.InsertOnSubmit(new History { Counter = counter, CreationTime = DateTime.UtcNow, Demand = this, DemandID = DemandID, Status = diff, Remark = remark }); var emails = (from s in Process.UserSubscriptions where s.User.Email != null && s.User.Email != string.Empty && s.Email select s.User.Email).Distinct().ToList(); var mobiles = (from s in Process.UserSubscriptions where s.User.Mobile != null && s.User.Mobile != string.Empty && s.SMS select s.User.Mobile).Distinct().ToList(); // if this is triggered from a user itself (through Ignore) // remove this user from SMS notification if applicable if (FeeblPrincipal.Current != null) { var user = (FeeblIdentity)FeeblPrincipal.Current.Identity; if (!string.IsNullOrEmpty(user.Mobile)) { mobiles.Remove(user.Mobile); } } var subject = string.Format("{0} {1} for {2} @ {3}", Process.Name, diff.ToLower(), Process.Application.Name, Process.Customer.Name); var detail = counter.HasValue ? string.Format("{0} / {1}", Methods.GetCounterValue(counter.Value), Methods.GetCounterValue(QuantityValue)) : isMet ? string.Format("at {1} - next @{0}", NextRunTime.Value.ToCET().ToString("MM/dd HH:mm"), Process.LastRunTime.HasValue?Process.LastRunTime.Value.ToCET().ToString("MM/dd HH:mm") : "never") : string.Format("{0}, last run {1}", NextRunTime.Value.ToCET().ToString("MM/dd HH:mm"), Process.LastRunTime.HasValue ? Process.LastRunTime.Value.ToCET().ToString("MM/dd HH:mm") : "never"); if (!string.IsNullOrEmpty(remark)) { detail += ", " + remark; } if (emails.Any()) { var mail = new Email { Subject = subject, Body = detail + "<br /><br />" + Comment + "<br /><br />" + Methods.GetUrl($"Demand?processID={ProcessID}") }; foreach (var to in emails) { mail.AddReceipient(to); } mail.Send(); } if (mobiles.Any() && Priority >= (int)Lists.Priority.Low) { var sms = new SmsMessage { Body = subject + ", " + detail }; if (sms.Body.Length > 160) { sms.Body = subject; } if (sms.Body.Length > 160) { sms.Body = string.Format("{0} {1}!", Process.Name, diff.ToLower()); } foreach (var to in mobiles) { sms.AddReceipient(to); } sms.Send(); } var slack = new Slack { Body = string.Format("<{0}|{1}>, {2}", Methods.GetUrl($"Demand?processID={ProcessID}"), subject, detail), Success = isMet }; slack.AddReceipient("feebl"); slack.AddReceipient(Process.Application.Name.ToLower()); slack.AddReceipient(Process.Customer.Name.ToLower()); slack.Send(); IsMet = isMet; } ErrorMessage = (!isMet && counter.HasValue) ? string.Format("{0} / {1}", Methods.GetCounterValue(counter.Value), Methods.GetCounterValue(QuantityValue)) : string.Empty; }
public void Check(FeeblDataContext ctx) { // if we've not yet determined next run, calculate and bail if (!NextRunTime.HasValue) { CalculateNextRunTime(); return; } // when do we expect to have a message from this job var threshold = NextRunTime.Value.AddMinutes(MaxRunTime ?? 0); // if it's in the future, we're all good - just bail if (threshold > DateTime.UtcNow) { return; } // if there's no event, make a special case to signal and bail if (!Process.LastRunTime.HasValue) { Update(ctx, true, "No events", null); return; } // if the last event was from a previous run, signal failure and bail // prevent this from executing if we left MaxRunTime empty (= pure counter check) //// also reducing scheduled time by 1 minute to prevent time sync issues if (MaxRunTime.HasValue && Process.LastRunTime.Value < NextRunTime.Value.AddMinutes(-1)) { Update(ctx, false, null, null); return; } int?quantity = null; if (QuantityValue.HasValue) { // if quantity time was given, use this as interval // otherwise, use start time of this demand (minute 1 minute time sync issue) var fromTime = QuantityTime.HasValue ? DateTime.UtcNow.AddMinutes(-QuantityTime.Value) : NextRunTime.Value; quantity = (from e in Process.Events where e.CreationTime >= fromTime.AddMinutes(-1) select e.Counter ?? 0).Sum(); // when the quantity demands are not met, signal failure and bail if (quantity < QuantityValue.Value) { Update(ctx, false, null, quantity); return; } } // we've passed all the checks, and the current "NextRunTime" conditions were met // so move on to the next and signal success CalculateNextRunTime(); Update(ctx, true, null, quantity); }