public async Task <Result <Agent> > Add(UserDescriptionInfo agentRegistration, string externalIdentity, string email) { var(_, isFailure, error) = await Validate(agentRegistration, externalIdentity); if (isFailure) { return(Result.Failure <Agent>(error)); } var createdAgent = new Agent { Title = agentRegistration.Title, FirstName = agentRegistration.FirstName, LastName = agentRegistration.LastName, Position = agentRegistration.Position, Email = email, IdentityHash = HashGenerator.ComputeSha256(externalIdentity), Created = _dateTimeProvider.UtcNow() }; _context.Agents.Add(createdAgent); await _context.SaveChangesAsync(); return(Result.Success(createdAgent)); }
public override async Task OnConnectedAsync() { var identityId = Context.User?.FindFirstValue("sub"); if (string.IsNullOrEmpty(identityId)) { return; } var agentId = await _context.Agents .Where(a => a.IdentityHash == HashGenerator.ComputeSha256(identityId)) .Select(a => a.Id) .SingleOrDefaultAsync(); if (agentId == default) { return; } // TODO: In the future, we will take this information from the token. var agencyId = await _context.AgentAgencyRelations .Where(aar => aar.AgentId == agentId) .Select(aar => aar.AgencyId) .SingleOrDefaultAsync(); if (agencyId == default) { return; } await Groups.AddToGroupAsync(Context.ConnectionId, BuildGroupName(agencyId, agentId)); await base.OnConnectedAsync(); }
public async Task <Result> Accept(string invitationCode, string identity, string email) { return(await GetActiveInvitation() .Ensure(IsIdentityPresent, "User should have identity") .Ensure(IsInvitationTypeCorrect, "Incorrect invitation type") .Ensure(IsEmailUnique, "Administrator with same mail is already registered") .BindWithTransaction(_context, invitation => Result.Success(invitation) .Tap(SaveAccepted) .Bind(CreateAdmin) .Tap(WriteAuditLog))); Task <Result <UserInvitation> > GetActiveInvitation() => _invitationRecordService.GetActiveInvitationByCode(invitationCode); bool IsIdentityPresent(UserInvitation _) => !string.IsNullOrWhiteSpace(identity); bool IsInvitationTypeCorrect(UserInvitation invitation) => invitation.InvitationType == UserInvitationTypes.Administrator; async Task <bool> IsEmailUnique(UserInvitation _) => !await _context.Administrators.AnyAsync(a => a.Email == email); Task SaveAccepted(UserInvitation _) => _invitationRecordService.SetAccepted(invitationCode); async Task <Result <Administrator> > CreateAdmin(UserInvitation invitation) { var now = _dateTimeProvider.UtcNow(); var invitationData = _invitationRecordService.GetInvitationData(invitation); var administrator = new Administrator { Email = email, FirstName = invitationData.UserRegistrationInfo.FirstName, LastName = invitationData.UserRegistrationInfo.LastName, IdentityHash = HashGenerator.ComputeSha256(identity), Position = invitationData.UserRegistrationInfo.Position, AdministratorRoleIds = invitationData.RoleIds, Created = now, Updated = now }; _context.Administrators.Add(administrator); await _context.SaveChangesAsync(); return(administrator); } Task WriteAuditLog(Administrator administrator) => _managementAuditService.Write(ManagementEventType.AdministratorRegistration, new AdministrationRegistrationEvent(administrator.Email, administrator.Id, invitationCode)); }
public Task <Result <string> > Create(UserInvitationData prefilledData, UserInvitationTypes invitationType, int inviterUserId, int?inviterAgencyId = null) { var invitationCode = GenerateRandomCode(); var now = _dateTimeProvider.UtcNow(); return(Result.Success() .Ensure(AllProvidedRolesExist, "All roles should exist") .Bind(SaveInvitation) .Tap(LogInvitationCreated) .Map(_ => invitationCode)); string GenerateRandomCode() { using var provider = new RNGCryptoServiceProvider(); var byteArray = new byte[64]; provider.GetBytes(byteArray); return(Base64UrlEncoder.Encode(byteArray)); } async Task <bool> AllProvidedRolesExist() { var allRoleIds = await _context.AgentRoles.Select(r => r.Id).ToListAsync(); return(prefilledData.RoleIds.All(x => allRoleIds.Contains(x))); } async Task <Result <UserInvitation> > SaveInvitation() { var newInvitation = new UserInvitation { CodeHash = HashGenerator.ComputeSha256(invitationCode), Email = prefilledData.UserRegistrationInfo.Email, Created = now, InviterUserId = inviterUserId, InviterAgencyId = inviterAgencyId, InvitationType = invitationType, InvitationStatus = UserInvitationStatuses.Active, Data = JsonConvert.SerializeObject(prefilledData) }; _context.UserInvitations.Add(newInvitation); await _context.SaveChangesAsync(); return(newInvitation); } void LogInvitationCreated() => _logger.LogInvitationCreated(invitationType, prefilledData.UserRegistrationInfo.Email); }
public Task <Result> Set(int agencyId, int agentId, ApiClientData clientData) { return(Validate() .BindWithTransaction(_context, () => SetClient() .Bind(WriteAuditLog))); async Task <Result> Validate() { var doesAgencyExist = await _context.AgentAgencyRelations .AnyAsync(r => r.AgencyId == agencyId && r.AgentId == agentId); return(doesAgencyExist ? Result.Success() : Result.Failure("Could not find agent and agency")); } async Task <Result> SetClient() { var existingClient = await _context.ApiClients .SingleOrDefaultAsync(a => a.AgentId == agentId && a.AgencyId == agencyId); if (existingClient is null) { var doesSameNameClientExist = await _context.ApiClients.AnyAsync(a => a.Name == clientData.Name); if (doesSameNameClientExist) { return(Result.Failure("Client with same name already exists")); } _context.ApiClients.Add(new ApiClient { AgentId = agentId, AgencyId = agencyId, Name = clientData.Name, PasswordHash = HashGenerator.ComputeSha256(clientData.Password) }); } else { existingClient.Name = clientData.Name; existingClient.PasswordHash = HashGenerator.ComputeSha256(clientData.Password); _context.Update(existingClient); } await _context.SaveChangesAsync(); return(Result.Success()); } Task <Result> WriteAuditLog() => _managementAuditService.Write(ManagementEventType.AgentApiClientCreateOrEdit, new AgentApiClientEventData(agentId, agencyId)); }
public Task <Result <string> > Create(UserInvitationData prefilledData, int inviterUserId) { if (prefilledData.RoleIds is null || !prefilledData.RoleIds.Any()) { return(Task.FromResult(Result.Failure <string>("Invitation should have role ids"))); } var invitationCode = GenerateRandomCode(); var now = _dateTimeProvider.UtcNow(); var registrationInfo = prefilledData.UserRegistrationInfo; return(SaveInvitation() .Tap(LogInvitationCreated) .Map(_ => invitationCode)); string GenerateRandomCode() { using var provider = new RNGCryptoServiceProvider(); var byteArray = new byte[64]; provider.GetBytes(byteArray); return(Base64UrlEncoder.Encode(byteArray)); } async Task <Result <UserInvitation> > SaveInvitation() { var newInvitation = new UserInvitation { CodeHash = HashGenerator.ComputeSha256(invitationCode), Email = registrationInfo.Email, Created = now, InviterUserId = inviterUserId, InvitationType = UserInvitationTypes.Administrator, InvitationStatus = UserInvitationStatuses.Active, Data = JsonConvert.SerializeObject(prefilledData) }; _context.UserInvitations.Add(newInvitation); await _context.SaveChangesAsync(); return(newInvitation); } void LogInvitationCreated() => _logger.LogInvitationCreated(UserInvitationTypes.Administrator, registrationInfo.Email); }
public async Task <Result <Administrator> > GetCurrent() { var identity = _tokenInfoAccessor.GetIdentity(); if (string.IsNullOrWhiteSpace(identity)) { return(Result.Failure <Administrator>("Identity is empty")); } var identityHash = HashGenerator.ComputeSha256(identity); var administrator = await _context.Administrators .SingleOrDefaultAsync(c => c.IdentityHash == identityHash); if (administrator != default) { return(Result.Success(administrator)); } return(Result.Failure <Administrator>("Could not get administrator")); }
public override async Task OnConnectedAsync() { var identityId = Context.User?.FindFirstValue("sub"); if (string.IsNullOrEmpty(identityId)) { return; } var adminId = await _context.Administrators .Where(a => a.IdentityHash == HashGenerator.ComputeSha256(identityId) && a.IsActive) .Select(a => a.Id) .SingleOrDefaultAsync(); if (adminId == default) { return; } await Groups.AddToGroupAsync(Context.ConnectionId, BuildGroupName(adminId)); await base.OnConnectedAsync(); }
public async Task <Result> RegisterByInvitation(string invitationCode, string identity) { return(await _invitationService.GetPendingInvitation(invitationCode) .BindWithTransaction(_context, invitation => Result.Success(invitation) .Map(CreateAdministrator) .Tap(AcceptInvitation) .Bind(WriteAuditLog))); async Task <Administrator> CreateAdministrator(AdministratorInvitationInfo info) { var now = _dateTimeProvider.UtcNow(); var administrator = new Administrator { Email = info.Email, FirstName = info.FirstName, LastName = info.LastName, IdentityHash = HashGenerator.ComputeSha256(identity), Position = info.Position, Created = now, Updated = now }; _context.Administrators.Add(administrator); await _context.SaveChangesAsync(); return(administrator); } Task <Result> WriteAuditLog(Administrator administrator) => _managementAuditService.Write(ManagementEventType.AdministratorRegistration, new AdministrationRegistrationEvent(administrator.Email, administrator.Id, invitationCode)); Task AcceptInvitation() => _invitationService.AcceptInvitation(invitationCode); }
private async Task <Result> CheckIdentityIsUnique(string identity) { return(await _context.Agents.AnyAsync(a => a.IdentityHash == HashGenerator.ComputeSha256(identity)) ? Result.Failure("User is already registered") : Result.Success()); }
public Task <Result <UserInvitation> > GetActiveInvitationByCode(string code) => GetActiveInvitationByHash(HashGenerator.ComputeSha256(code));