diff --git a/Scrummer/Code/BusinessLogic/Sessions.cs b/Scrummer/Code/BusinessLogic/Sessions.cs new file mode 100644 index 0000000..c9cc464 --- /dev/null +++ b/Scrummer/Code/BusinessLogic/Sessions.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Web; +using Scrummer.Code.Entities; + +namespace Scrummer.Code.BusinessLogic +{ + public class Sessions + { + #region declarations + + private static Sessions _currentInstance = null; + + private List _sessions = new List(); + + private string _cookieName = "ScrummerSID"; + private int _cookieExpirationDays = 30; + + #endregion + + #region Properties + + public static Sessions Current + { + get + { + if (_currentInstance == null) + { + _currentInstance = new Sessions(); + } + return _currentInstance; + } + set { _currentInstance = value; } + } + + public string CookieName + { + get { return _cookieName; } + set { _cookieName = value; } + } + + public int CookieExpirationDays + { + get { return _cookieExpirationDays; } + set { _cookieExpirationDays = value; } + } + + #endregion + + #region Public methods + + public void Session_SetCookie(HttpContext context, Session session) + { + HttpCookie cookie = new HttpCookie(_cookieName, session.SessionToken); + cookie.Expires = DateTime.Now.AddDays(_cookieExpirationDays); + context.Response.Cookies.Add(cookie); + } + + public bool Session_Init(HttpContext context, string userName) + { + lock (_sessions) + { + var session = new Session(); + session.UserName = userName; + session.SessionToken = CryptoUtils.GetCryptoToken(); + session.StartDate = DateTime.UtcNow; + _sessions.Add(session); + + Session_SetCookie(context, session); + } + return true; + } + + public Session Session_GetCurrent(HttpContext context) + { + HttpCookie cookie = context.Request.Cookies[_cookieName]; + if (cookie == null) { return null; } + + string sessionToken = cookie.Value; + if (string.IsNullOrEmpty(sessionToken)) { return null; } + + Session session = Session_GetByToken(sessionToken); + return session; + } + + public bool Session_FinalizeCurrent(HttpContext context) + { + lock (_sessions) + { + Session session = Session_GetCurrent(context); + if (session == null) { return false; } + + if (_sessions.Remove(session) == false) { return false; } + + HttpCookie cookie = new HttpCookie(_cookieName); + cookie.Expires = DateTime.Now.AddDays(-1d); + context.Response.Cookies.Add(cookie); + } + return true; + } + + #endregion + + #region Private methods + + private Session Session_GetByToken(string sessionToken) + { + foreach (Session session in _sessions) + { + if (session.SessionToken == sessionToken) + { + return session; + } + } + return null; + } + + #endregion + } +} \ No newline at end of file diff --git a/Scrummer/Code/BusinessLogic/Users.cs b/Scrummer/Code/BusinessLogic/Users.cs new file mode 100644 index 0000000..04e0097 --- /dev/null +++ b/Scrummer/Code/BusinessLogic/Users.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using Scrummer.Code.Entities; + +namespace Scrummer.Code.BusinessLogic +{ + public class Users + { + #region declarations + + private static Users _currentInstance = null; + + private List _users = new List(); + + #endregion + + #region Properties + + public static Users Current + { + get + { + if (_currentInstance == null) + { + _currentInstance = new Users(); + } + return _currentInstance; + } + set { _currentInstance = value; } + } + + #endregion + + #region Public methods + + public User User_GetByName(string name) + { + name=name.ToLower(); + foreach (User userAux in _users) + { + if (name.CompareTo(userAux.Name.ToLower()) == 0) + { + return userAux; + } + } + return null; + } + + public User User_GetByEmail(string email) + { + email = email.ToLower(); + foreach (User userAux in _users) + { + if (email.CompareTo(userAux.Email.ToLower()) == 0) + { + return userAux; + } + } + return null; + } + + public User User_GetByNameOrEmail(string name, string email) + { + name = name.ToLower(); + email = email.ToLower(); + foreach (User userAux in _users) + { + if (name.CompareTo(userAux.Name.ToLower()) == 0 || + email.CompareTo(userAux.Email.ToLower()) == 0) + { + return userAux; + } + } + return null; + } + + public User User_Set(string name, string email, string password) + { + User user = null; + bool isNew = false; + lock (_users) + { + user = User_GetByName(name); + if (user == null) { user = User_GetByEmail(name); } + if (user == null) { user = new User(); isNew = true; } + + user.Name = name; + user.Email = email; + if (string.IsNullOrEmpty(password) == false) + { + user.PasswordSalt = CryptoUtils.GetCryptoToken(); + user.PasswordHash = CryptoUtils.GetSHA1(String.Format("{1}{0}{1}", password, user.PasswordSalt)); + } + + if (isNew) { _users.Add(user); } + } + return user; + } + + public bool User_Authenticate(string nameOrMail, string password) + { + User user = User_GetByNameOrEmail(nameOrMail, nameOrMail); + if (user == null) { return false; } + + string passwordHash = CryptoUtils.GetSHA1(String.Format("{1}{0}{1}", password, user.PasswordSalt)); + if (passwordHash != user.PasswordHash) { return false; } + + return true; + } + + #endregion + } +} \ No newline at end of file diff --git a/Scrummer/Code/CryptoUtils.cs b/Scrummer/Code/CryptoUtils.cs index 9d873c1..be29826 100644 --- a/Scrummer/Code/CryptoUtils.cs +++ b/Scrummer/Code/CryptoUtils.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography; +using System.Security.Cryptography; using System.Text; -using System.Web; namespace Scrummer.Code { @@ -23,7 +19,7 @@ namespace Scrummer.Code public static string GetRandString(int len) { byte[] bytes = new byte[len]; - var cryptoRandom = new System.Security.Cryptography.RNGCryptoServiceProvider(); + var cryptoRandom = new RNGCryptoServiceProvider(); cryptoRandom.GetBytes(bytes); UTF8Encoding encoding = new UTF8Encoding(); diff --git a/Scrummer/Code/Entities/Session.cs b/Scrummer/Code/Entities/Session.cs new file mode 100644 index 0000000..d1efe8c --- /dev/null +++ b/Scrummer/Code/Entities/Session.cs @@ -0,0 +1,11 @@ +using System; + +namespace Scrummer.Code.Entities +{ + public class Session + { + public string UserName { get; set; } + public string SessionToken { get; set; } + public DateTime StartDate { get; set; } + } +} diff --git a/Scrummer/Code/Entities/User.cs b/Scrummer/Code/Entities/User.cs new file mode 100644 index 0000000..577c9d0 --- /dev/null +++ b/Scrummer/Code/Entities/User.cs @@ -0,0 +1,11 @@ + +namespace Scrummer.Code.Entities +{ + public class User + { + public string Name { get; set; } + public string Email { get; set; } + public string PasswordHash { get; set; } + public string PasswordSalt { get; set; } + } +} \ No newline at end of file diff --git a/Scrummer/Code/Pages/FrmBoard.cs b/Scrummer/Code/Pages/FrmBoard.cs index 99cc0ca..74feadd 100644 --- a/Scrummer/Code/Pages/FrmBoard.cs +++ b/Scrummer/Code/Pages/FrmBoard.cs @@ -21,7 +21,7 @@ namespace Scrummer.Code.Pages ChatControl chatControl = new ChatControl(); chatControl.ID = "ctrChat"; chatControl.IDBoard = _idBoard; - chatControl.UserName = Convert.ToString(new Random().Next()); + chatControl.UserName = CurrentUser.Name; Controls.Add(chatControl); } } diff --git a/Scrummer/Code/Pages/FrmLogin.cs b/Scrummer/Code/Pages/FrmLogin.cs new file mode 100644 index 0000000..fe7cc25 --- /dev/null +++ b/Scrummer/Code/Pages/FrmLogin.cs @@ -0,0 +1,71 @@ +using System; +using System.Web.UI.WebControls; +using Scrummer.Code.BusinessLogic; +using Scrummer.Code.Controls; + +namespace Scrummer.Code.Pages +{ + public class FrmLogin : PageCommon + { + #region Declarations + + private CTextBox _txtNameEmail = new CTextBox { ID = "txtNameEmail", CssClassExtra = "width150px", AllowEmpty = false }; + private CTextBox _txtPassword = new CTextBox { ID = "txtPassword", CssClassExtra = "width150px", AllowEmpty = false, TextMode = TextBoxMode.Password }; + private CButton _btnLogin = new CButton { ID = "btnLogin"}; + + #endregion + + #region Page life cycle + + public FrmLogin() + { + MustBeAutenticated = false; + Init += FrmLogin_Init; + } + + private void FrmLogin_Init(object sender, EventArgs e) + { + InitializeControls(); + } + + #endregion + + #region UI Events + + private void btnLogin_Click(object sender, EventArgs e) + { + if (FormUtils.Controls_AreValid(Controls) == false) { return; } + + if (Users.Current.User_Authenticate(_txtNameEmail.Text, _txtPassword.Text) == false) + { + _txtPassword.Text = string.Empty; + return; + } + + Sessions.Current.Session_Init(Context, _txtNameEmail.Text); + Response.Redirect("."); + } + + #endregion + + #region Private methods + + private void InitializeControls() + { + Title = "Login"; + var lblTitle = new CLabel { Text = "Login", Tag = "h2" }; + Controls.Add(lblTitle); + + Controls.Add(FormUtils.CreateField("Name/Mail", _txtNameEmail)); + Controls.Add(FormUtils.CreateField("Password", _txtPassword)); + + Controls.Add(FormUtils.CreateField(String.Empty, _btnLogin)); + _btnLogin.Text = "Login"; + _btnLogin.Click += btnLogin_Click; + + Controls.Add(FormUtils.CreateField(String.Empty, new HyperLink { Text = "Register user", NavigateUrl = "FrmRegister" })); + } + + #endregion + } +} \ No newline at end of file diff --git a/Scrummer/Code/Pages/FrmRegister.cs b/Scrummer/Code/Pages/FrmRegister.cs new file mode 100644 index 0000000..a0398c9 --- /dev/null +++ b/Scrummer/Code/Pages/FrmRegister.cs @@ -0,0 +1,122 @@ +using System; +using System.Web.UI.WebControls; +using Scrummer.Code.BusinessLogic; +using Scrummer.Code.Controls; +using Scrummer.Code.Entities; + +namespace Scrummer.Code.Pages +{ + public class FrmRegister : PageCommon + { + #region Declarations + + private Panel _pnlRegister = new Panel { ID = "pnlRegister" }; + private CTextBox _txtName = new CTextBox { ID = "txtName", CssClassExtra = "width150px", AllowEmpty = false }; + private CTextBox _txtEmail = new CTextBox { ID = "txtEmail", CssClassExtra = "width150px", AllowEmpty = false }; + private CTextBox _txtPassword1 = new CTextBox { ID = "txtPassword1", CssClass = "width150px", AllowEmpty = false, TextMode = TextBoxMode.Password }; + private CTextBox _txtPassword2 = new CTextBox { ID = "txtPassword2", CssClass = "width150px", AllowEmpty = false, TextMode = TextBoxMode.Password }; + private CButton _btnRegister = new CButton { ID = "btnRegister" }; + private CButton _btnExit = new CButton { ID = "btnExit" }; + private Panel _pnlSuccess = new Panel { ID = "pnlSuccess" }; + private CLabel _lblSuccess = new CLabel { ID = "lblSuccess" }; + private CButton _btnExitSuccess = new CButton { ID = "btnExitSuccess" }; + + #endregion + + #region Page life cycle + + public FrmRegister() + { + MustBeAutenticated = false; + Init += FrmRegister_Init; + } + + void FrmRegister_Init(object sender, EventArgs e) + { + InitializeComponents(); + } + + #endregion + + #region UI Events + + void btnRegister_Click(object sender, EventArgs e) + { + if (FormUtils.Controls_AreValid(Controls) == false) { return; } + + // FIXME: Check Email + + // Check password + if (_txtPassword1.Text != _txtPassword2.Text) + { + _txtPassword1.MarkedInvalid = true; + _txtPassword2.MarkedInvalid = true; + _txtPassword1.Text = String.Empty; + _txtPassword2.Text = String.Empty; + return; + } + + User user = Users.Current.User_Set(_txtName.Text, _txtEmail.Text, _txtPassword1.Text); + + _pnlRegister.Visible = false; + _pnlSuccess.Visible = true; + _lblSuccess.Text = String.Format("User {0} created sucessfully", user.Name); + } + + void btnExit_Click(object sender, EventArgs e) + { + Response.Redirect("."); + } + + #endregion + + + #region Private methods + + private void InitializeComponents() + { + Title = "Register"; + var lblTitle = new CLabel { Text = "Register", Tag = "h2" }; + Controls.Add(lblTitle); + + Controls.Add(_pnlRegister); + + _pnlRegister.Controls.Add(FormUtils.CreateField("Name", _txtName)); + _txtName.PlaceHolder = "Name"; + + _pnlRegister.Controls.Add(FormUtils.CreateField("Email", _txtEmail)); + _txtEmail.PlaceHolder = "Email"; + + _pnlRegister.Controls.Add(FormUtils.CreateField("Password", _txtPassword1)); + _txtPassword1.PlaceHolder = "Password"; + + _pnlRegister.Controls.Add(FormUtils.CreateField(String.Empty, _txtPassword2)); + _txtPassword2.PlaceHolder = "Password"; + + _btnRegister.Text = "Register"; + _btnRegister.Click += btnRegister_Click; + + _btnExit.Text = "Exit"; + _btnExit.Click += btnExit_Click; + + Panel pnlButtons=new Panel(); + pnlButtons.Controls.Add(_btnRegister); + pnlButtons.Controls.Add(_btnExit); + _pnlRegister.Controls.Add(FormUtils.CreateField(String.Empty, pnlButtons)); + + + Controls.Add(_pnlSuccess); + _pnlSuccess.Visible = false; + + _pnlSuccess.Controls.Add(_lblSuccess); + + _btnExitSuccess.Text = "Exit"; + _btnExitSuccess.Click += btnExit_Click; + _pnlSuccess.Controls.Add(FormUtils.CreateField(String.Empty, _btnExitSuccess)); + + } + + #endregion + + } +} \ No newline at end of file diff --git a/Scrummer/Code/Pages/PageCommon.cs b/Scrummer/Code/Pages/PageCommon.cs index 92b2af7..a53fc4a 100644 --- a/Scrummer/Code/Pages/PageCommon.cs +++ b/Scrummer/Code/Pages/PageCommon.cs @@ -4,7 +4,9 @@ using System.Text; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; +using Scrummer.Code.BusinessLogic; using Scrummer.Code.Controls; +using Scrummer.Code.Entities; namespace Scrummer.Code.Pages { @@ -17,6 +19,9 @@ namespace Scrummer.Code.Pages private HtmlForm _form; private Panel _pnlContainer = new Panel(); + private bool _mustBeAutenticated = true; + private User _currentUser = null; + #endregion #region Properties @@ -26,16 +31,45 @@ namespace Scrummer.Code.Pages get { return _pnlContainer.Controls; } } + public bool MustBeAutenticated + { + get { return _mustBeAutenticated; } + set { _mustBeAutenticated = value; } + } + + public User CurrentUser + { + get { return _currentUser; } + } + #endregion #region Life cycle public PageCommon() { + PreInit += PageCommon_PreInit; Init += PageCommon_Init; PreRender += PageCommon_PreRender; } + void PageCommon_PreInit(object sender, EventArgs e) + { + Session session = Sessions.Current.Session_GetCurrent(Context); + if (session != null) + { + _currentUser = Users.Current.User_GetByName(session.UserName); + if (_mustBeAutenticated) + { + Sessions.Current.Session_SetCookie(Context, session); + } + } + if (_currentUser == null && _mustBeAutenticated) + { + Response.Redirect("FrmLogin"); + } + } + void PageCommon_Init(object sender, EventArgs e) { CreateControls(); diff --git a/Scrummer/Scrummer.csproj b/Scrummer/Scrummer.csproj index 698a8b0..4de7b21 100644 --- a/Scrummer/Scrummer.csproj +++ b/Scrummer/Scrummer.csproj @@ -66,6 +66,8 @@ + + @@ -74,6 +76,8 @@ + + @@ -81,6 +85,12 @@ ASPXCodeBehind + + ASPXCodeBehind + + + ASPXCodeBehind + ASPXCodeBehind