// ReSharper disable once InconsistentNaming public static string TestCredentials(string credentialsLogin, string credentialsPass, string credentials2FA, string logonUriEncoded) { if (!string.IsNullOrEmpty(credentialsLogin.Trim()) && !string.IsNullOrEmpty(credentialsPass.Trim())) { string logonUri = HttpUtility.UrlDecode(logonUriEncoded); try { Person authenticatedPerson = Authentication.Authenticate(credentialsLogin, credentialsPass); int lastOrgId = authenticatedPerson.LastLogonOrganizationId; if (PilotInstallationIds.IsPilot(PilotInstallationIds.PiratePartySE) && (lastOrgId == 3 || lastOrgId == 0)) { lastOrgId = 1; // legacy: log on to Piratpartiet SE if indeterminate; prevent sandbox for this pilot authenticatedPerson.LastLogonOrganizationId = 1; // avoid future legacy problems } else if (lastOrgId == 0) { lastOrgId = Organization.SandboxIdentity; } Authority testAuthority = Authority.FromLogin(authenticatedPerson, Organization.FromIdentity(lastOrgId)); if (!authenticatedPerson.MemberOfWithInherited(lastOrgId) && !testAuthority.HasSystemAccess(AccessType.Read)) { // If the person doesn't have access to the last organization (anymore), log on to Sandbox // unless first pilot, in which case throw (deny login) if (PilotInstallationIds.IsPilot(PilotInstallationIds.PiratePartySE)) { throw new UnauthorizedAccessException(); } lastOrgId = Organization.SandboxIdentity; } GuidCache.Set(logonUri + "-LoggedOn", Authority.FromLogin(authenticatedPerson, Organization.FromIdentity(lastOrgId)).ToEncryptedXml()); return("Success"); // Prepare here for "2FARequired" return code } catch (UnauthorizedAccessException) { return("Fail"); } } return("Fail"); }
protected void ButtonCheat_Click(object sender, EventArgs e) { // If we're debugging, enable the auto- / impersonation login. This MUST NEVER fire outside of development environment. if (Debugger.IsAttached && Path.DirectorySeparatorChar == '\\') // on Windows, with a debugger attached, so this is not a production environment { // but check that we're running against Localhost on non-SSL on a nonstandard port as well if (Request.Url.ToString().StartsWith("http://localhost:")) { Authority cheatLogon = Authority.FromLogin(Person.FromIdentity(1), Organization.Sandbox); FormsAuthentication.RedirectFromLoginPage(cheatLogon.ToEncryptedXml(), true); } } }
public static AjaxCallResult Commence(int personId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); if (!authData.Authority.HasSystemAccess()) { // Restrict impersonation to system-level access for now: it's a debugging tool return(new AjaxCallResult { Success = false, DisplayMessage = CommonV5.JavascriptEscape(Resources.Pages.Admin.CommenceImpersonation_Failed) }); } // BEGIN IMPERSONATION Person impersonatedPerson = Person.FromIdentity(personId); SwarmopsLogEntry newEntry = SwarmopsLog.CreateEntry(impersonatedPerson, new ImpersonationLogEntry { ImpersonatorPersonId = authData.CurrentUser.PersonId, Started = true }); newEntry.CreateAffectedObject(authData.CurrentUser); // link impersonator to log entry for searchability // Someone who has system level access can always impersonate => no further access control at this time // SECURITY CONSIDERATIONS: If somebody replaces/fires a superior? Trivially undoable at the database level DateTime utcNow = DateTime.UtcNow; Authority impersonatingAuthority = Authority.FromLogin(impersonatedPerson, authData.CurrentOrganization); impersonatingAuthority.Impersonation = new Impersonation { ImpersonatedByPersonId = authData.CurrentUser.PersonId, ImpersonationStarted = utcNow }; FormsAuthentication.SetAuthCookie(impersonatingAuthority.ToEncryptedXml(), false); HttpContext.Current.Response.AppendCookie(new HttpCookie("DashboardMessage", CommonV5.JavascriptEscape(String.Format(Resources.Pages.Admin.CommenceImpersonation_Success, utcNow)))); return(new AjaxCallResult { Success = true }); }
public static AjaxCallResult TerminateImpersonation() { AuthenticationData authData = GetAuthenticationDataAndCulture(); if (!authData.Authority.ImpersonationActive) { return(new AjaxCallResult { Success = false }); // no impersonation active. Race condition? } int realUserPersonId = authData.Authority.Impersonation.ImpersonatedByPersonId; Person impersonator = Person.FromIdentity(realUserPersonId); // Terminate impersonation and set new authority cookie from the impersonator data. // VERY SECURITY SENSITIVE: The identity as impersonator will be the new user. // TODO: LOG LOG LOG LOG SwarmopsLogEntry logEntry = SwarmopsLog.CreateEntry(authData.CurrentUser, new ImpersonationLogEntry { ImpersonatorPersonId = impersonator.Identity, Started = false }); logEntry.CreateAffectedObject(impersonator); // link impersonator to log entry for searchability DateTime utcNow = DateTime.UtcNow; Authority authority = Authority.FromLogin(impersonator, authData.CurrentOrganization); FormsAuthentication.SetAuthCookie(authority.ToEncryptedXml(), false); HttpContext.Current.Response.AppendCookie(new HttpCookie("DashboardMessage", CommonV5.JavascriptEscape(String.Format(Resources.Pages.Admin.CommenceImpersonation_Ended, utcNow)))); // returning Success will force a reload, resetting dashboard to original user return(new AjaxCallResult { Success = true }); }
protected void ButtonLogin_Click(object sender, EventArgs args) { // Check the host names and addresses again as a security measure - after all, we can be called from outside our intended script if (!(VerifyHostName(this.TextServerName.Text) && VerifyHostAddress(this.TextServerAddress.Text))) { if (!Debugger.IsAttached) { return; // Probable hack attempt - fail silently } } // Protect against race condition on a really really slow server: wait until there is a first person or 15 seconds have expired DateTime utcTimeout = DateTime.UtcNow.AddSeconds(15); People people = People.GetAll(); while (people.Count < 1 && DateTime.UtcNow < utcTimeout) { Thread.Sleep(500); people = People.GetAll(); } if (people.Count < 1) { throw new InvalidOperationException("First person has not been created despite 15-second timeout; cannot login"); } // Get authenticated person Person expectedPersonOne = Authentication.Authenticate("1", this.TextFirstUserPassword1.Text); if (expectedPersonOne != null) { Authority firstAuthority = Authority.FromLogin(expectedPersonOne, Organization.Sandbox); FormsAuthentication.RedirectFromLoginPage(firstAuthority.ToEncryptedXml(), true); Response.Redirect("/", true); } }
protected void Page_Load(object sender, EventArgs e) { // Check if this is the first run ever. If so, redirect to Init. if (!SupportFunctions.DatabaseConfigured) { // ReSharper disable once Html.PathError <-- this line is required for Resharper to not flag the next line as invalid Response.Redirect("/Initialize", true); return; } // Persistence.Key["Debug_RawData"] = Request.ToRaw(); // Check for POST data - for BitId via Webform if (Request.HttpMethod == "POST") { // We should ONLY get here if we're getting a BitId by Webform submission. // Persistence.Key["BitId_RawData"] = Request.ToRaw(); if (Request.Params["address"] != null) { // yes, indeed looks like it BitIdCredentials credentials = new BitIdCredentials { address = Request.Params["address"], uri = Request.Params["uri"], signature = Request.Params["signature"] }; ProcessRespondBitId(credentials, Response); return; } if (Request.ContentType == "application/json") { BitIdCredentials credentials = new JavaScriptSerializer().Deserialize <BitIdCredentials> ( new StreamReader(Request.InputStream).ReadToEnd()); // TODO: untested but seems to work. Throws? ProcessRespondBitId(credentials, Response); return; } } string requestHost = Request.Url.Host; // If this is the Dev Sandbox, autologin if ((requestHost == "sandbox.swarmops.com" || requestHost == "dev.swarmops.com") && PilotInstallationIds.IsPilot(PilotInstallationIds.DevelopmentSandbox) && Request.QueryString["SuppressAutologin"] != "true") { DashboardMessage.Set("<p>You have been logged on as <strong>Sandbox Administrator</strong> to the Swarmops Development Sandbox.</p><br/><p>This machine runs the latest development build, so you may run into diagnostic code and half-finished features. All data here is bogus test data and is reset every night.</p><br/><p><strong>In other words, welcome, and play away!</strong></p>"); FormsAuthentication.SetAuthCookie(Authority.FromLogin(Person.FromIdentity(1), Organization.Sandbox).ToEncryptedXml(), true); Response.Redirect(HttpContext.Current.Request ["ReturnUrl"]); // Returns to the requested URL with auth cookie set } // If we're on an Open Ledgers domain, autologin as Open Ledgers Organization organizationOpenLedgers = Organization.FromOpenLedgersDomain(requestHost); // returns null if doesn't exist if (organizationOpenLedgers != null) { DashboardMessage.Set(String.Format(Resources.Pages.Security.Login_AsOpenLedgers, organizationOpenLedgers.Name)); FormsAuthentication.SetAuthCookie(Authority.FromLogin(Person.FromIdentity(Person.OpenLedgersIdentity), organizationOpenLedgers).ToEncryptedXml(), true); if (HttpContext.Current.Request["ReturnUrl"] == "/") { Response.Redirect(@"/Ledgers/Balance"); } else { Response.Redirect(HttpContext.Current.Request["ReturnUrl"]); // Returns to the requested URL with auth cookie set } } // Check for SSL and force it // Special case for CloudFlare deployments - there is a case where somebody will get their connections de-SSLed at the server string cloudFlareVisitorScheme = Request.Headers["CF-Visitor"]; bool cloudFlareSsl = false; if (!string.IsNullOrEmpty(cloudFlareVisitorScheme)) { if (cloudFlareVisitorScheme.Contains("\"scheme\":\"https\"")) { cloudFlareSsl = true; } } // TODO: Same thing for Pound/HAProxy deployments // Rewrite if applicable if (Request.Url.ToString().StartsWith("http://") && !cloudFlareSsl) // only check client-side as many server sites de-SSL the connection before reaching the web server { if (!Request.Url.ToString().StartsWith("http://dev.swarmops.com/") && !(Request.Url.ToString().StartsWith("http://*****:*****@"//" + vanityOrganization.VanityDomain + @"/Signup"; // this.LabelSelfSignup.Text = String.Format (Resources.Pages.Security.Login_SelfSignup, vanityOrganization.Name); // this.LabelSelfSignupHeader.Text = Resources.Pages.Security.Login_SelfSignupHeader; // this.PanelJoin.Visible = true; } // If we're debugging, enable the auto- / impersonation login. This MUST NEVER fire outside of development environment. if (Debugger.IsAttached && Path.DirectorySeparatorChar == '\\') // on Windows, with a debugger attached, so this is not a production environment { // but check that we're running against Localhost as well if (Request.Url.ToString().StartsWith("http://localhost:")) { this.PanelCheat.Visible = true; } } // this.ImageCultureIndicator.Style[HtmlTextWriterStyle.MarginTop] = "-3px"; // this.ImageCultureIndicator.Style[HtmlTextWriterStyle.MarginRight] = "3px"; // this.ImageCultureIndicator.Style[HtmlTextWriterStyle.Cursor] = "pointer"; _cacheVersionMark = Logic.Support.Formatting.SwarmopsVersion; if (_cacheVersionMark.StartsWith("Debug")) { _cacheVersionMark = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.ffff"); } _cacheVersionMark = SHA1.Hash(_cacheVersionMark).Replace(" ", "").Substring(0, 8); Localize(); // Generate BitID tokens Guid guid = Guid.NewGuid(); string guidString = guid.ToString().Replace("-", ""); string nonce = guidString + DateTime.UtcNow.Ticks.ToString("x8"); string hostName = Request.Url.Host; string bitIdUri = "bitid://" + hostName + "/Security/Login.aspx/BitIdLogin?x=" + nonce; /* -- commented out: NEVER permit BitId over non-SSL * if (Request.Url.ToString().StartsWith ("http://") && !cloudFlareSsl) * { * bitIdUri += "&u=1"; * }*/ this.LiteralUri.Text = HttpUtility.UrlEncode(bitIdUri); this.LiteralNonce.Text = nonce; GuidCache.Set(bitIdUri + "-Logon", "Unauth"); // TODO: need to NOT USE GOOGLE CHARTS for this but bring home a free QR package this.ImageBitIdQr.ImageUrl = "https://chart.googleapis.com/chart?cht=qr&chs=400x400&chl=" + HttpUtility.UrlEncode(bitIdUri); }
protected string _cacheVersionMark; // CSS cache buster protected static void ProcessRespondBitId(BitIdCredentials credentials, HttpResponse response) { BitcoinPubKeyAddress testAddress = new BitcoinPubKeyAddress(credentials.address); if (testAddress.VerifyMessage(credentials.uri, credentials.signature)) { // woooooo try { // Test for registration string intent = GuidCache.Get(credentials.uri + "-Intent") as string; if (!string.IsNullOrEmpty(intent)) { if (intent.StartsWith("Register")) { int personId = Int32.Parse(intent.Substring("Register-".Length)); Person person = Person.FromIdentity(personId); person.BitIdAddress = credentials.address; GuidCache.Set(credentials.uri + "-Intent", "Complete"); } } // Otherwise, test for logon if (GuidCache.Get(credentials.uri + "-Logon") as string == "Unauth") { Person person = Person.FromBitIdAddress(credentials.address); // TODO: If above throws, show friendly "unknown wallet" message int lastOrgId = person.LastLogonOrganizationId; if (lastOrgId == 0) { lastOrgId = Organization.SandboxIdentity; person.LastLogonOrganizationId = lastOrgId; } GuidCache.Set(credentials.uri + "-LoggedOn", Authority.FromLogin(person, Organization.FromIdentity(person.LastLogonOrganizationId)).ToEncryptedXml()); } } catch (Exception e) { Persistence.Key["BitIdLogin_Debug_Exception"] = e.ToString(); } // TODO: Error codes response.StatusCode = 200; response.SetJson(); response.Write("{\"address\":\"" + credentials.address + "\",\"signature\":\"" + credentials.signature + "\"}"); response.End(); } else { response.StatusCode = 401; // Be a bit more friendly in your return codes } }
public static AjaxCallResult SignupParticipant(string name, int organizationId, string mail, string password, string phone, string street1, string street2, string postalCode, string city, string countryCode, string dateOfBirth, int geographyId, bool activist, PersonGender gender, int[] positionIdsVolunteer) { CommonV5.CulturePreInit(HttpContext.Current.Request); // Set culture, for date parsing if (geographyId == 0) { geographyId = Geography.RootIdentity; // if geo was undetermined, set it to "Global" } Organization organization = Organization.FromIdentity(organizationId); DateTime parsedDateOfBirth = new DateTime(1800, 1, 1); // Default if unspecified if (dateOfBirth.Length > 0) { parsedDateOfBirth = DateTime.Parse(dateOfBirth); } Person newPerson = Person.Create(name, mail, password, phone, street1 + "\n" + street2.Trim(), postalCode, city, countryCode, parsedDateOfBirth, gender); Participation participation = newPerson.AddParticipation(organization, DateTime.UtcNow.AddYears(1)); // TODO: set duration from organization settings of Participantship // TODO: SEND NOTIFICATIONS // Log the signup SwarmopsLog.CreateEntry(newPerson, new PersonAddedLogEntry(participation, newPerson)); // Create notification OutboundComm.CreateParticipantNotification(newPerson, newPerson, organization, NotificationResource.Participant_Signup); // Add the bells and whistles if (activist) { newPerson.CreateActivist(false, false); } if (positionIdsVolunteer.Length > 0) { Volunteer volunteer = newPerson.CreateVolunteer(); foreach (int positionId in positionIdsVolunteer) { Position position = Position.FromIdentity(positionId); volunteer.AddPosition(position); SwarmopsLog.CreateEntry(newPerson, new VolunteerForPositionLogEntry(newPerson, position)); } } newPerson.LastLogonOrganizationId = organizationId; // Create a welcome message to the Dashboard HttpContext.Current.Response.AppendCookie(new HttpCookie("DashboardMessage", CommonV5.JavascriptEscape(String.Format(Resources.Pages.Public.Signup_DashboardMessage, organization.Name)))); // Set authentication cookie, which will log the new person in using the credentials just given FormsAuthentication.SetAuthCookie(Authority.FromLogin(newPerson).ToEncryptedXml(), true); AjaxCallResult result = new AjaxCallResult { Success = true }; return(result); }
public static bool PerformReset(string mailAddress, string ticket, string newPassword) { People people = People.FromMail(mailAddress.Trim()); if (people.Count != 1) { return(false); } Person resetPerson = people[0]; string[] resetData = resetPerson.ResetPasswordTicket.Split(','); if (resetData.Length != 2) { return(false); // invalid data or no ticket } // This may throw on invalid data, which will give a slightly different error but that's fine too for now. DateTime ticketExpiresUtc = DateTime.Parse(resetData[0]); if (DateTime.UtcNow > ticketExpiresUtc) { // Ticket expired. return(false); } if (ticket != resetData[1]) { // Bad ticket. return(false); } // When we get here, all checks to reset the password have completed. Change the password, log the change, // notify the user that the password was changed, set a new authentication cookie, and have the web page // redirect to Dashboard (by returning true). // Clear password reset ticket resetPerson.ResetPasswordTicket = string.Empty; // Create lockdown code, notify string lockdownTicket = SupportFunctions.GenerateSecureRandomKey(16); OutboundComm.CreateSecurityNotification(resetPerson, null, null, lockdownTicket, NotificationResource.Password_Changed); resetPerson.AccountLockdownTicket = DateTime.UtcNow.AddDays(1).ToString(CultureInfo.InvariantCulture) + "," + lockdownTicket; // Set new password resetPerson.SetPassword(newPassword); // Log the password reset SwarmopsLog.CreateEntry(resetPerson, new PasswordResetLogEntry(resetPerson, SupportFunctions.GetRemoteIPAddressChain())); // Set authentication cookies int lastOrgId = resetPerson.LastLogonOrganizationId; if (lastOrgId == 0) { lastOrgId = Organization.SandboxIdentity; } if (!resetPerson.ParticipatesInOrganizationOrParent(lastOrgId)) { // If the person doesn't have access to the last organization (anymore), log on to Sandbox lastOrgId = 1; } // Set cookies FormsAuthentication.SetAuthCookie(Authority.FromLogin(resetPerson).ToEncryptedXml(), true); DashboardMessage.Set(Resources.Pages.Security.ResetPassword_Success); return(true); // temp // do NOT NOT NOT trim password - this is deliberate. Passwords starting/ending in whitespace must be possible }