Example #1
0
        // Read existing stored values for token secrets & issuers
        private TokenSettingsFile ReadTokenSettingsFile()
        {
            try
            {
                // Attempt reading the file
                using (var reader = new StreamReader(Path.Combine(_config["ConfigFilePath"], JWT_CONFIG_FILENAME)))
                {
                    return(JsonSerializer.Deserialize <TokenSettingsFile>(reader.ReadToEnd()));
                }
            }
            catch (IOException)
            {
                // If any errors, then regenerate the local secrets file
                // Generate values and serialize object
                var tokenSettings = new TokenSettingsFile()
                {
                    Secret   = PasswordUtils.GenerateSalt(128),
                    Issuer   = Convert.ToBase64String(PasswordUtils.GenerateSalt(64), Base64FormattingOptions.None),
                    Audience = Convert.ToBase64String(PasswordUtils.GenerateSalt(64), Base64FormattingOptions.None)
                };

                // Write new values to file
                if (!Directory.Exists(_config["ConfigFilePath"]))
                {
                    Directory.CreateDirectory(_config["ConfigFilePath"]);
                }
                var file = File.Create(Path.Combine(_config["ConfigFilePath"], JWT_CONFIG_FILENAME));
                using (var writer = new StreamWriter(file, Encoding.UTF8))
                {
                    writer.WriteLine(JsonSerializer.Serialize(tokenSettings));
                    return(tokenSettings);
                }
            }
        }
Example #2
0
        public async Task <ActionResult <UserDTO> > CreateUser([FromBody] UserLoginRequestDTO dto, CancellationToken ct)
        {
            if (dto == null)
            {
                return(BadRequest());
            }

            if (!await _userSvc.CheckUsernameAvailableAsync(dto.Username, ct))
            {
                var modelErrors = new ModelStateDictionary();
                modelErrors.AddModelError("details", "That username is already in use.");
                return(Conflict(modelErrors));
            }

            if (Validators.CheckForbiddenName(dto.Username))
            {
                var modelErrors = new ModelStateDictionary();
                modelErrors.AddModelError("details", "That username is forbidden or reserved for system use.");
                return(Conflict(modelErrors));
            }

            var obj = _mapper.Map <User>(dto);

            obj.Id   = Guid.NewGuid();
            obj.Salt = PasswordUtils.GenerateSalt();
            obj.Hash = PasswordUtils.GenerateHash(dto.Password, obj.Salt);
            obj      = await _userSvc.AddUserAsync(obj, ct);

            return(CreatedAtAction(nameof(GetUser), new { id = obj.Id }, _mapper.Map <UserDTO>(obj)));
        }
Example #3
0
        public static UserAccount CreateNewUser()
        {
            var result = new UserAccount
            {
                UserId     = Guid.NewGuid(),
                UserSecret = PasswordUtils.GeneratePassword(),
                Salt       = PasswordUtils.GenerateSalt()
            };

            return(result);
        }
Example #4
0
        public async Task <ActionResult <UserDTO> > UpdateUser(Guid id, [FromBody] UserUpdateDTO dto, CancellationToken ct)
        {
            var obj = await _userSvc.GetUserAsync(id, ct : ct);

            if (obj == null)
            {
                return(NotFound());
            }
            obj.Salt = PasswordUtils.GenerateSalt();
            obj.Hash = PasswordUtils.GenerateHash(dto.Password, obj.Salt);
            obj      = await _userSvc.UpdateUserAsync(obj, ct);

            return(Ok(_mapper.Map <UserDTO>(obj)));
        }
Example #5
0
        public override async Task <User> UpdateAsync(User retrievedUser, User user)
        {
            if (!string.IsNullOrEmpty(user.Password))
            {
                string salt           = PasswordUtils.GenerateSalt();
                string hashedPassword = PasswordUtils.HashPasswordWithSalt(user.Password, salt);
                user.Salt     = salt;
                user.Password = hashedPassword;
            }
            else
            {
                user.Password = retrievedUser.Password;
                user.Salt     = retrievedUser.Salt;
            }

            if (user.Created == DateTimeOffset.MinValue)
            {
                user.Created = retrievedUser.Created;
            }

            if (string.IsNullOrEmpty(user.Username))
            {
                user.Username = retrievedUser.Username;
            }
            if (string.IsNullOrEmpty(user.DisplayName))
            {
                user.DisplayName = retrievedUser.DisplayName;
            }

            var now = DateTime.UtcNow;

            user.LastUpdate = now;

            // After password update
            DbContext.Entry(retrievedUser).CurrentValues.SetValues(new
            {
                user.Username,
                user.Password,
                user.DisplayName,
                user.Salt
            });
            await DbContext.SaveChangesAsync();

            return(retrievedUser);
        }
Example #6
0
        public override async Task <User> InsertAsync(User user)
        {
            var defaultAvatarPath = Configuration.GetValue <string>("DefaultAvatar");

            string originalPass = user.Password;
            string salt         = PasswordUtils.GenerateSalt();
            string hashedPass   = PasswordUtils.HashPasswordWithSalt(originalPass, salt);
            var    now          = DateTimeOffset.UtcNow;

            user.Username    = user.Username.Trim();
            user.DisplayName = user.DisplayName.Trim();
            user.Password    = hashedPass;
            user.Salt        = salt;
            user.Created     = now;
            user.LastUpdate  = now;

            var transaction = DbContext.Database.BeginTransaction();

            await UserDatabase.AddAsync(user);

            await DbContext.SaveChangesAsync();

            // create new avatar record
            var photo = new AvatarPhoto
            {
                UserId   = user.Id,
                FileName = defaultAvatarPath
            };

            DbContext.AvatarPhotos.Add(photo);
            await DbContext.SaveChangesAsync();

            await transaction.CommitAsync();

            // format output
            user.AvatarPhoto = photo;
            return(user);
        }
Example #7
0
        public UserDto Post([FromBody] UserDto userDto)
        {
            if (!userDto.IsValid())
            {
                throw new HttpResponseException(HttpStatusCode.BadRequest);
            }

            using (var db = new CompAgriConnection())
            {
                var previousUser = db.User.FirstOrDefault(u => (u.UserName != null && u.UserName == userDto.UserName) || (u.Email != null && u.Email == userDto.Email));
                if (previousUser != null)
                {
                    throw WebExceptionsFactory.GetUserDuplicatedException();
                }

                var userBeforeSave = userDto.User();
                userBeforeSave.PasswordSalt = PasswordUtils.GenerateSalt();
                userBeforeSave.Password     = PasswordUtils.HashPassword(userBeforeSave.Password, userBeforeSave.PasswordSalt);

                var user = db.User.Add(userBeforeSave);
                db.SaveChanges();
                return(new UserDto(user));
            }
        }
Example #8
0
        public EnrollmentResponse EnrollNewStudent(EnrollmentStudentRequest enrollmentStudentRequest)
        {
            using var connection = new SqlConnection(AppSettingsUtils.GetConnectionString());
            using var command    = new SqlCommand { Connection = connection };
            connection.Open();
            var transaction = connection.BeginTransaction();

            command.Transaction = transaction;

            command.CommandText = "SELECT s.IdStudy FROM Studies s WHERE s.Name = @StudiesName";
            command.Parameters.AddWithValue("StudiesName", enrollmentStudentRequest.Studies);
            var dataReader = command.ExecuteReader();

            if (!dataReader.Read())
            {
                throw new ResourceNotFoundException(
                          $"Studies by name {enrollmentStudentRequest.Studies} does not exist in database");
            }
            var idStudy = Parse(dataReader["IdStudy"].ToString());

            dataReader.Close();
            command.Parameters.Clear();
            command.CommandText =
                "SELECT * FROM Enrollment E WHERE E.Semester = 1 AND E.IdStudy = @IdStudy";
            command.Parameters.AddWithValue("IdStudy", idStudy);
            dataReader = command.ExecuteReader();

            var enrollmentResponse = new EnrollmentResponse();

            if (!dataReader.Read())
            {
                dataReader.Close();
                command.Parameters.Clear();

                command.CommandText =
                    @"INSERT INTO Enrollment(IdEnrollment, Semester, StartDate, IdStudy) 
                OUTPUT INSERTED.IdEnrollment, INSERTED.Semester, INSERTED.StartDate, INSERTED.IdStudy 
                VALUES((SELECT MAX(E.IdEnrollment) FROM Enrollment E) + 1, @Semester, @StartDate, @IdStudy);";
                command.Parameters.AddWithValue("Semester", 1);
                command.Parameters.AddWithValue("StartDate", DateTime.Now);
                command.Parameters.AddWithValue("IdStudy", idStudy);

                enrollmentResponse.IdEnrollment = Parse(command.ExecuteScalar().ToString());
                enrollmentResponse.Semester     = Parse(command.Parameters["Semester"].Value.ToString());
                enrollmentResponse.IdStudy      = Parse(command.Parameters["IdStudy"].Value.ToString());
                enrollmentResponse.StartDate    =
                    DateTime.Parse(command.Parameters["StartDate"].Value.ToString()).ToString("yyyy-MM-dd");
            }
            else
            {
                enrollmentResponse.IdEnrollment = Parse(dataReader["IdEnrollment"].ToString());
                enrollmentResponse.Semester     = Parse(dataReader["Semester"].ToString());
                enrollmentResponse.IdStudy      = Parse(dataReader["IdStudy"].ToString());
                enrollmentResponse.StartDate    =
                    DateTime.Parse(dataReader["StartDate"].ToString()).ToString("yyyy-MM-dd");
            }

            dataReader.Close();
            command.Parameters.Clear();
            command.CommandText = "SELECT S.IndexNumber FROM Student S WHERE IndexNumber = @indexNumber";
            command.Parameters.AddWithValue("indexNumber", enrollmentStudentRequest.Index);
            dataReader = command.ExecuteReader();
            if (dataReader.Read())
            {
                throw new BadRequestException("Student Index number not unique");;
            }

            dataReader.Close();
            command.Parameters.Clear();
            var salt = PasswordUtils.GenerateSalt();

            command.CommandText =
                @"INSERT INTO Student(IndexNumber, FirstName, LastName, BirthDate, IdEnrollment, Password, Salt) 
                VALUES (@IndexNumber, @FirstName, @LastName, @BirthDate, @IdEnrollment, @Password, @Salt)";
            command.Parameters.AddWithValue("IndexNumber", enrollmentStudentRequest.Index);
            command.Parameters.AddWithValue("FirstName", enrollmentStudentRequest.FirstName);
            command.Parameters.AddWithValue("LastName", enrollmentStudentRequest.LastName);
            command.Parameters.AddWithValue("BirthDate", enrollmentStudentRequest.BirthDate);
            command.Parameters.AddWithValue("IdEnrollment", enrollmentResponse.IdEnrollment);
            command.Parameters.AddWithValue("Password",
                                            PasswordUtils.CreateSaltedPasswordHash(enrollmentStudentRequest.Password, salt));
            command.Parameters.AddWithValue("Salt", salt);
            command.ExecuteNonQuery();

            transaction.Commit();
            return(enrollmentResponse);
        }
Example #9
0
        protected override void OnModelCreating(ModelBuilder model)
        {
            #region Model configuration
            // Set certain columns to be *case insensitive*
            model.Entity <User>()
            .Property(u => u.Username)
            .HasColumnType("TEXT COLLATE NOCASE");
            model.Entity <SettingsEntry>()
            .Property(s => s.Key)
            .HasColumnType("TEXT COLLATE NOCASE");

            // Set default values
            model.Entity <Slide>()
            .Property(s => s.Order)
            .ValueGeneratedNever()
            .HasDefaultValue(999);

            model.Entity <Slide>()
            .Property(s => s.DisplaySeconds)
            .ValueGeneratedNever()
            .HasDefaultValue(20);
            #endregion

            #region Settings seeding
            #endregion

            #region Users seeding
            // Generate an admin user with a default known password.
            var adminUserSalt = PasswordUtils.GenerateSalt();
            model.Entity <User>().HasData(
                new User()
            {
                Id       = Guid.NewGuid(),
                Username = "******",
                Salt     = adminUserSalt,
                Hash     = PasswordUtils.GenerateHash("letmeslaps", adminUserSalt)
            });
            #endregion

            #region DateTimeOffset converter
            if (Database.ProviderName == "Microsoft.EntityFrameworkCore.Sqlite")
            {
                // NB: Taken from https://blog.dangl.me/archive/handling-datetimeoffset-in-sqlite-with-entity-framework-core/

                // SQLite does not have proper support for DateTimeOffset via Entity Framework Core, see the limitations
                // here: https://docs.microsoft.com/en-us/ef/core/providers/sqlite/limitations#query-limitations
                // To work around this, when the Sqlite database provider is used, all model properties of type DateTimeOffset
                // use the DateTimeOffsetToBinaryConverter
                // Based on: https://github.com/aspnet/EntityFrameworkCore/issues/10784#issuecomment-415769754
                // This only supports millisecond precision, but should be sufficient for most use cases.
                foreach (var entityType in model.Model.GetEntityTypes())
                {
                    var properties = entityType.ClrType.GetProperties().Where(p => p.PropertyType == typeof(DateTimeOffset) ||
                                                                              p.PropertyType == typeof(DateTimeOffset?));
                    foreach (var property in properties)
                    {
                        model.Entity(entityType.Name)
                        .Property(property.Name)
                        .HasConversion(new DateTimeOffsetToBinaryConverter());
                    }
                }
            }
            #endregion
        }
Example #10
0
        public EnrollmentResponse EnrollNewStudentEntity(EnrollmentStudentRequest enrollmentStudentRequest)
        {
            var context = new StudentDbContext();
            var studies = context.Studies
                          .FirstOrDefault(stud => enrollmentStudentRequest.Studies.Equals(stud.Name));

            if (studies == null)
            {
                throw new ResourceNotFoundException("Studies with name = " + enrollmentStudentRequest.Studies
                                                    + " dont exist");
            }

            var enrollment = context.Enrollment.FirstOrDefault(enroll => 1.Equals(enroll.Semester) &&
                                                               studies.IdStudy.Equals(enroll.IdStudy));

            var enrollmentResponse = new EnrollmentResponse();

            if (enrollment == null)
            {
                var enrollmentNew = new Enrollment
                {
                    IdEnrollment = context.Enrollment.Select(enroll =>
                                                             enroll.IdEnrollment).OrderByDescending(i => i).First() + 1,
                    Semester  = 1,
                    StartDate = DateTime.Now,
                    IdStudy   = studies.IdStudy
                };

                context.Enrollment.Add(enrollmentNew);

                enrollmentResponse.IdEnrollment = enrollmentNew.IdEnrollment;
                enrollmentResponse.Semester     = enrollmentNew.Semester;
                enrollmentResponse.IdStudy      = enrollmentNew.IdStudy;
                enrollmentResponse.StartDate    = enrollmentNew.StartDate.ToString("yyyy-MM-dd");
            }
            else
            {
                enrollmentResponse.IdEnrollment = enrollment.IdEnrollment;
                enrollmentResponse.Semester     = enrollment.Semester;
                enrollmentResponse.IdStudy      = enrollment.IdStudy;
                enrollmentResponse.StartDate    = enrollment.StartDate.ToString("yyyy-MM-dd");
            }

            if (context.Student.Any(student => enrollmentStudentRequest.Index.Equals(student.IndexNumber)))
            {
                throw new BadRequestException("Student Index number not unique");
                ;
            }

            var salt = PasswordUtils.GenerateSalt();

            context.Student.Add(new Student
            {
                IndexNumber  = enrollmentStudentRequest.Index,
                FirstName    = enrollmentStudentRequest.FirstName,
                LastName     = enrollmentStudentRequest.LastName,
                BirthDate    = enrollmentStudentRequest.BirthDate,
                IdEnrollment = enrollmentResponse.IdEnrollment,
                Password     = PasswordUtils.CreateSaltedPasswordHash(enrollmentStudentRequest.Password, salt),
                Salt         = salt
            });

            context.SaveChanges();

            return(enrollmentResponse);
        }