Exemple #1
0
        /// <summary>
        /// We need a way to generate users on the fly.
        /// </summary>
        /// <param name="addRecipientRequest"></param>
        /// <returns></returns>
        private async Task <UserModel> GenerateUserForEDiscovery(AddRecipientRequest addRecipientRequest, string password)
        {
            await InitializePrivilegedConnectionAsync();

            var folderIdentifier = addRecipientRequest.FolderIdentifier;
            var userModel        = new UserModel
            {
                Identifier   = ModuleUtility.GetFolderScopedUserIdentifier(folderIdentifier, addRecipientRequest.RecipientEmail),
                EmailAddress = addRecipientRequest.RecipientEmail,
                FirstName    = addRecipientRequest.FirstName,
                LastName     = addRecipientRequest.LastName,
            };

            userModel = await privilegedConnection.User.PostAsync(userModel);

            await privilegedConnection.User.PasswordPutAsync(userModel.Identifier, password);

            var accessIdentifiers = new[]
            {
                $"o:{folderIdentifier.OrganizationKey}",
                $"r:eDiscovery{{{folderIdentifier.FolderKey.Replace(" ", "_")}}}", // used to actually control access
                $"r:eDiscovery",                                                   // used to test whether a given user is an eDiscovery user
                $"x:pcms",                                                         // disable PCMS rules
                $"x:leo",                                                          // disable LEO rules
            };

            await privilegedConnection.User.AccessIdentifiersPutAsync(userModel.Identifier, accessIdentifiers);

            return(userModel);
        }
Exemple #2
0
        private async Task <UserModel> GenerateUser(RecipientRequestBase addRecipientRequest, string password)
        {
            await InitializePrivilegedConnectionAsync();

            var folderIdentifier = addRecipientRequest.FolderIdentifier;
            var userModel        = new UserModel
            {
                Identifier   = ModuleUtility.GetFolderScopedUserIdentifier(folderIdentifier, addRecipientRequest.RecipientEmail, "leo"),
                EmailAddress = addRecipientRequest.RecipientEmail,
                FirstName    = addRecipientRequest.FirstName,
                LastName     = addRecipientRequest.LastName,
            };

            userModel = await privilegedConnection.User.PostAsync(userModel);

            await privilegedConnection.User.PasswordPutAsync(userModel.Identifier, password);

            await privilegedConnection.User.AccessIdentifiersPutAsync(userModel.Identifier, new[] {
                "r:leoUpload",
                $"o:{folderIdentifier.OrganizationKey}",
                "x:pcms",
                "x:eDiscovery",
                $"u:{userModel.Identifier.UserKey.Replace(" ", "_")}"
            });

            return(userModel);
        }
Exemple #3
0
        public async Task <RecipientResponse> RemoveRecipientAsync(RemoveRecipientRequest removeRequest)
        {
            var folder = await connection.Folder.GetAsync(removeRequest.FolderIdentifier);

            var recipients = folder.MetaEDiscoveryRecipientListRead();

            folder.MetaEDiscoveryRecipientListRemove(removeRequest.RecipientEmail);

            await connection.Folder.PutAsync(folder);

            await InitializePrivilegedConnectionAsync();

            // Using the special connection here to delete the user.
            await privilegedConnection.User.DeleteAsync(ModuleUtility.GetFolderScopedUserIdentifier(folder.Identifier, removeRequest.RecipientEmail));

            await this.auditLogStore.AddEntry(
                new AuditLogEntry()
            {
                EntryType  = AuditLogEntryType.eDiscoveryRecipientDeleted,
                Message    = $"An eDiscovery User has been removed {removeRequest.RecipientEmail}",
                ModuleType = Modules.ModuleType.eDiscovery
            },
                folder.Identifier
                );

            return(new RecipientResponse()
            {
                Email = removeRequest.RecipientEmail,
            });
        }
Exemple #4
0
        public async Task <RecipientResponse> RegenerateRecipientPasswordAsync(RegenerateRecipientPasswordRequest regenRequest)
        {
            var folder = await connection.Folder.GetAsync(regenRequest.FolderIdentifier);

            var recipients = folder.MetaEDiscoveryRecipientListRead();

            var password = ModuleUtility.GeneratePassword(folder, MetadataKeyConstants.E_DISCOVERY_RND_PASSWORD_LENGTH, EDiscoveryUtility.E_DISCOVERY_DEFAULT_PASSWORD_LENGTH, MetadataKeyConstants.E_DISCOVERY_RND_PASSWORD_CHARS);

            var recipient = recipients.Where(rec => rec.Email.ToLower() == regenRequest.RecipientEmail.ToLower()).FirstOrDefault();

            if (recipient != null)
            {
                // Using the special connection here to update their password.
                var userIdentifier = ModuleUtility.GetFolderScopedUserIdentifier(folder.Identifier, regenRequest.RecipientEmail);

                await InitializePrivilegedConnectionAsync();

                await privilegedConnection.User.PasswordPutAsync(userIdentifier, password.Plain);

                await this.auditLogStore.AddEntry(
                    new AuditLogEntry()
                {
                    EntryType  = AuditLogEntryType.eDiscoveryRecipientRegenerated,
                    Message    = $"An eDiscovery has had their password regenerated {recipient.Email}",
                    ModuleType = Modules.ModuleType.eDiscovery
                },
                    folder.Identifier
                    );

                recipient.PasswordHash   = password.Hashed;
                recipient.ExpirationDate = ModuleUtility.GetLinkExpirationDate(folder, MetadataKeyConstants.E_DISCOVERY_EXPIRATION_LENGTH_SECONDS).Value;
                recipient.MagicLink      = ModuleUtility.CreateMagicLink(regenRequest, managerConfiguration.EDiscoveryLandingLocation, managerConfiguration.EDiscoveryLinkEncryptionKey, regenRequest.FolderIdentifier, recipient.ExpirationDate, userIdentifier);

                await connection.ConcurrencyRetryBlock(async() =>
                {
                    folder = await connection.Folder.GetAsync(regenRequest.FolderIdentifier);

                    folder.MetaEDiscoveryRecipientListUpsert(recipient);
                    await connection.Folder.PutAsync(folder);
                });

                // now we also want to send back the magic link that we generated before.
                return(new RecipientResponse()
                {
                    Email = regenRequest.RecipientEmail,
                    FirstName = recipient.FirstName,
                    LastName = recipient.LastName,
                    Password = password.Plain,
                    MagicLink = recipient.MagicLink,
                    ExpirationDate = recipient.ExpirationDate,
                });
            }

            return(new RecipientResponse());
        }
Exemple #5
0
        private async Task <ModelBase> RemoveOfficerAsync(RemoveOfficerRequest removeRequest)
        {
            FolderModel folder = null;

            await connection.ConcurrencyRetryBlock(async() =>
            {
                folder         = await connection.Folder.GetAsync(removeRequest.FolderIdentifier);
                var recipients = folder.MetaLEOUploadOfficerListRead();

                var recipient = recipients.FirstOrDefault(f => f.Email == removeRequest.RecipientEmail);

                folder.MetaLEOUploadOfficerListRemove(removeRequest.RecipientEmail);

                var paths = folder.Read <List <string> >("_paths");
                if (paths != null && recipient != null)
                {
                    var officerPath = GetOfficerPath(folder.Identifier, recipient.FirstName, recipient.LastName);
                    if (paths.Contains(officerPath.PathKey))
                    {
                        paths = paths.Where(p => !p.StartsWith(officerPath.PathKey)).ToList();
                    }

                    folder.Write("_paths", paths);
                }

                await connection.Folder.PutAsync(folder);
            });

            await InitializePrivilegedConnectionAsync();

            // Using the special connection here to delete the user.
            await privilegedConnection.User.DeleteAsync(ModuleUtility.GetFolderScopedUserIdentifier(folder.Identifier, removeRequest.RecipientEmail, "leo"));

            await this.auditLogStore.AddEntry(
                new AuditLogEntry()
            {
                EntryType  = AuditLogEntryType.LEOUploadOfficerDeleted,
                Message    = $"An officer has been removed {removeRequest.RecipientEmail}",
                ModuleType = Modules.ModuleType.LEOUpload
            },
                folder.Identifier
                );

            return(new RecipientResponse()
            {
                Email = removeRequest.RecipientEmail,
            });
        }
Exemple #6
0
        public async Task <RecipientResponse> AddRecipientAsync(AddRecipientRequest addRecipientRequest, string landingLocation, string passphrase)
        {
            var folder = await connection.Folder.GetAsync(addRecipientRequest.FolderIdentifier);

            DateTime?expirationDate = ModuleUtility.GetLinkExpirationDate(folder, MetadataKeyConstants.E_DISCOVERY_EXPIRATION_LENGTH_SECONDS);

            var password = ModuleUtility.GeneratePassword(folder, MetadataKeyConstants.E_DISCOVERY_RND_PASSWORD_LENGTH, EDiscoveryUtility.E_DISCOVERY_DEFAULT_PASSWORD_LENGTH, MetadataKeyConstants.E_DISCOVERY_RND_PASSWORD_CHARS);

            // We're going to generate a user for eDicsovery.  This user will have restricted priveleges.
            var user = await GenerateUserForEDiscovery(addRecipientRequest, password.Plain);

            string completeUrl = ModuleUtility.CreateMagicLink(addRecipientRequest, landingLocation, passphrase, folder.Identifier, expirationDate, user.Identifier);

            folder.MetaEDiscoveryRecipientListUpsert(new ExternalUser()
            {
                Email          = addRecipientRequest.RecipientEmail,
                FirstName      = addRecipientRequest.FirstName,
                LastName       = addRecipientRequest.LastName,
                PasswordHash   = password.Hashed,
                MagicLink      = completeUrl,
                ExpirationDate = expirationDate.GetValueOrDefault()
            });
            await connection.Folder.PutAsync(folder);

            await EnsureFolderSecurityConfiguration(folder.Identifier);

            await this.auditLogStore.AddEntry(
                new AuditLogEntry()
            {
                EntryType  = AuditLogEntryType.eDiscoveryRecipientAdded,
                Message    = $"An eDiscovery User has been added. {addRecipientRequest.RecipientEmail}",
                ModuleType = Modules.ModuleType.eDiscovery
            },
                folder.Identifier
                );

            // build up the response
            return(new RecipientResponse()
            {
                Email = addRecipientRequest.RecipientEmail,
                ExpirationDate = expirationDate.GetValueOrDefault(),
                MagicLink = completeUrl,
                Password = password.Plain,
                FirstName = addRecipientRequest.FirstName,
                LastName = addRecipientRequest.LastName,
            });
        }
Exemple #7
0
        public async Task <RecipientResponse> AddRecipientAsync(AddOfficerRequest addOfficerRequest, string landingLocation, string passphrase)
        {
            var folder = await connection.Folder.GetAsync(addOfficerRequest.FolderIdentifier);

            DateTime?expirationDate = ModuleUtility.GetLinkExpirationDate(folder, MetadataKeyConstants.LEO_UPLOAD_EXPIRATION_LENGTH_SECONDS);

            var password = ModuleUtility.GeneratePassword(
                folder,
                MetadataKeyConstants.LEO_UPLOAD_RND_PASSWORD_LENGTH,
                LEOUploadUtility.LEO_UPLOAD_DEFAULT_PASSWORD_LENGTH,
                MetadataKeyConstants.LEO_UPLOAD_RND_PASSWORD_CHARS);

            // We're going to generate a user for eDicsovery.  This user will have restricted priveleges.
            var user = await GenerateUser(addOfficerRequest, password.Plain);

            string completeUrl = ModuleUtility.CreateMagicLink(addOfficerRequest, landingLocation, passphrase, folder.Identifier, expirationDate, user.Identifier);

            await connection.ConcurrencyRetryBlock(async() =>
            {
                folder = await connection.Folder.GetAsync(addOfficerRequest.FolderIdentifier);

                folder.MetaLEOUploadOfficerListUpsert(new ExternalUser()
                {
                    Email          = addOfficerRequest.RecipientEmail,
                    FirstName      = addOfficerRequest.FirstName,
                    LastName       = addOfficerRequest.LastName,
                    PasswordHash   = password.Hashed,
                    MagicLink      = completeUrl,
                    ExpirationDate = expirationDate.GetValueOrDefault()
                });

                var childPath = GetOfficerPath(addOfficerRequest.FolderIdentifier, addOfficerRequest.FirstName, addOfficerRequest.LastName);

                var allPaths = folder.Read("_paths", defaultValue: new List <string>());

                allPaths.Add(childPath.FullName);

                folder.Write("_paths", allPaths);

                await connection.Folder.PutAsync(folder);
            });

            await this.auditLogStore.AddEntry(
                new AuditLogEntry()
            {
                EntryType  = AuditLogEntryType.LEOUploadOfficerAdded,
                Message    = $"A LEO officer has been added. {addOfficerRequest.RecipientEmail}",
                ModuleType = Modules.ModuleType.LEOUpload
            },
                folder.Identifier
                );

            // build up the response
            return(new RecipientResponse()
            {
                Email = addOfficerRequest.RecipientEmail,
                ExpirationDate = expirationDate.GetValueOrDefault(),
                MagicLink = completeUrl,
                Password = password.Plain,
                FirstName = addOfficerRequest.FirstName,
                LastName = addOfficerRequest.LastName,
            });
        }
Exemple #8
0
        public async Task <UserAuthenticatedResponse> AuthenticateUserAsync(AuthenticateUserRequest authenticateUserRequest, string linkEncryptionKey)
        {
            if (String.IsNullOrEmpty(authenticateUserRequest.Token))
            {
                return(new UserAuthenticatedResponse()
                {
                    IsAuthenticated = false
                });
            }

            // Get the magic link object back out from the token.
            var magicLink = ModuleUtility.DecryptMagicLink(authenticateUserRequest.Token, linkEncryptionKey);

            // Now we have a magic link object, we need to compare the email on the token, with the one that was passed in.
            if (magicLink.RecipientEmail.ToLower() != authenticateUserRequest.Email.ToLower() ||
                magicLink.ExipirationDate < DateTime.UtcNow // next let's check that this link hasn't expired.
                )                                           // Next we check to make sure the folder keys are the same.
            {
                return(new UserAuthenticatedResponse()
                {
                    IsAuthenticated = false
                });
            }

            // Before we can operate, and get any folder details, we're also going to need to authenticate the user in the backend. This will properly set things on the connection
            // such that it can make a backed call.
            try
            {
                await connection.User.AuthenticateAsync(new TokenRequestModel
                {
                    Identifier = ModuleUtility.GetFolderScopedUserIdentifier(magicLink.FolderIdentifier, authenticateUserRequest.Email, "leo"),
                    Password   = authenticateUserRequest.Password
                });

                connection.AddCookieTokenToResponse();

                // Now we can do the password check.  We're going to check that the password in our database matches on hash
                // the password that came in on the request.
                var folder = await connection.Folder.GetAsync(magicLink.FolderIdentifier);

                // get the recipients, so we can find this particular recipient.
                var officers  = folder.MetaLEOUploadOfficerListRead();
                var recipient = officers.Where(rec => rec.Email.ToLower() == magicLink.RecipientEmail.ToLower()).FirstOrDefault();

                // We check to make sure that there's a recipient on this folder that matches by email, and that the plain text
                // password that was passed in matches the password in our database.
                if (recipient != null && BCrypt.Verify(authenticateUserRequest.Password, recipient.PasswordHash))
                {
                    await this.auditLogStore.AddEntry(
                        new AuditLogEntry()
                    {
                        EntryType  = AuditLogEntryType.LEOUploadUserLogin,
                        Message    = "An officer Has Logged in.",
                        ModuleType = Modules.ModuleType.LEOUpload
                    },
                        folder.Identifier,
                        connection
                        );

                    return(new UserAuthenticatedResponse()
                    {
                        IsAuthenticated = true,
                        FolderIdentifier = folder.Identifier,
                        PathIdentifier = GetOfficerPath(folder.Identifier, recipient.FirstName, recipient.LastName)
                    });
                }
                else
                {
                    return(new UserAuthenticatedResponse()
                    {
                        IsAuthenticated = false
                    });
                }
            }
            catch (Exception)
            {
                return(new UserAuthenticatedResponse()
                {
                    IsAuthenticated = false
                });
            }
        }