/// <summary> /// Validates whether a <see cref="LocalFileSystemProvider"/> was configured /// with access restricted to a given <see cref="LocalFileSystemProvider.RootDirectory"/>, /// and makes sure that the requested <paramref name="file"/> is indeed contained /// within that folder. /// </summary> /// <param name="file">The requested file resource.</param> /// <param name="submittedFilePath">The path that was submitted in the original request.</param> /// <param name="context">The currently performed file system operation.</param> /// <exception cref="ResourceAccessException">If the requested resource is not /// a descendant of a configured <see cref="LocalFileSystemProvider.RootDirectory"/>.</exception> /// <exception cref="ArgumentNullException">If <paramref name="file"/> /// is a null reference.</exception> private void ValidateFileRequestAccess(FileItem file, string submittedFilePath, FileSystemTask context) { if (file == null) { throw new ArgumentNullException("file"); } //if there isn't a restricted custom root, every file resource can be accessed //(if the path is invalid, this will fail otherwise, depending on the action) if (RootDirectory == null) { return; } try { //if we have a custom root, make sure the resource is indeed a descendant of the root if (RootDirectory.IsParentOf(file.LocalFile.FullName)) { return; } } catch (ResourceAccessException e) { //just bubble a resource access exception if (e.Resource == null) { e.Resource = file.ResourceInfo; } throw; } catch (Exception e) { //exceptions can happen in case of invalid file paths //log detailed info string error = "Resource request for file [{0}] caused exception when validating against root directory [{1}]."; error = String.Format(error, submittedFilePath, RootDirectory.FullName); AuditHelper.AuditException(Auditor, e, AuditLevel.Warning, context, AuditEvent.InvalidFilePathFormat, error); //do not expose too much path information (e.g. absolute paths if disabled) error = String.Format("Invalid file path: [{0}].", submittedFilePath); throw new ResourceAccessException(error, e) { Resource = file.ResourceInfo, IsAudited = true }; } //if none of the above is true, the request is invalid //log detailed info string msg = "Resource request for file [{0}] was blocked. The resource is outside the root directory [{1}]."; msg = String.Format(msg, file.ResourceInfo.FullName, RootDirectory.FullName); Auditor.Audit(AuditLevel.Warning, context, AuditEvent.InvalidResourceLocationRequested, msg); //do not expose too much path information (e.g. absolute paths if disabled) msg = String.Format("Invalid file path: [{0}].", submittedFilePath); throw new ResourceAccessException(msg) { Resource = file.ResourceInfo, IsAudited = true }; }
public void Submitted_Exceptions_Should_Indicate_They_Have_Been_Audited_After_Processing() { VfsException e = new ResourceAccessException("hello"); Assert.IsFalse(e.IsAudited); AuditHelper.AuditException(auditor, e, FileSystemTask.RootFolderInfoRequest); Assert.IsTrue(e.IsAudited); }
public void Submitted_Exceptions_Should_Be_Logged() { VfsException e = new ResourceAccessException("hello"); AuditHelper.AuditException(auditor, e, FileSystemTask.RootFolderInfoRequest); Assert.AreEqual(1, auditor.Items.Count); Assert.AreEqual(FileSystemTask.RootFolderInfoRequest, auditor.Items[0].Context); }
public void Exceptions_With_Audit_Suppression_Should_Be_Ignored() { VfsException e = new ResourceAccessException("hello") { SuppressAuditing = true }; AuditHelper.AuditException(auditor, e, FileSystemTask.RootFolderInfoRequest); Assert.AreEqual(0, auditor.Items.Count); }
public void Already_Audited_Exceptions_Should_Not_Be_Audited_Anymore() { VfsException e = new ResourceAccessException("hello") { IsAudited = true }; AuditHelper.AuditException(auditor, e, FileSystemTask.RootFolderInfoRequest); Assert.AreEqual(0, auditor.Items.Count); }
/// <summary> /// Provides exception handling and auditing for a given function. /// </summary> /// <param name="task">The context, used for auditing exceptions that may occur.</param> /// <param name="action">The action to be invoked.</param> /// <param name="errorMessage">Returns an error message in case of an unhandled exception /// that is not derived from <see cref="VfsException"/>.</param> /// <param name="auditor">The auditor that receives the exceptions.</param> /// <returns>The result of the submitted <paramref name="action"/> function.</returns> public static void SecureAction(FileSystemTask task, Action action, Func <string> errorMessage, IAuditor auditor) { try { action(); } catch (VfsException e) { //just audit and rethrow VFS exceptions AuditHelper.AuditException(auditor, e, task); throw; } catch (Exception e) { //wrap unhandled exception into VFS exception var exception = new ResourceAccessException(errorMessage(), e); AuditHelper.AuditException(auditor, exception, task); throw exception; } }