Search code examples
c#asp.net-mvcauthenticationsimplificationapplication-security

Determining complex security and permissions


I've been put on a project that has a messy class that writes buttons to a page. The app is a document manager and has a popup list of buttons, such as download, email, and print. Depending on the user's roles, and the state of the document, different buttons are displayed.

Among other WTFs is something like this:

bool showEditButton = document.docTypeId == documentEnum.docType.text && 
( document.statusId == documentEnum.docStatus.Editable || (user.UserStatus == userEnum.Status.SuperUser) || ( user.UserID == document.CreatedByUserId ) )

And so on and so forth until I can't figure out what's going on.

I don't know if this is just a side effect of a deeper architectural flaw, or if there's a good method to deal with checking a mixture of permissions and status values. Should I just put all of these crazy conditions in a method and just forget about it? That doesn't benefit the next programmer to inherit the project though.


Solution

  • It's just a bunch of boolean logic in your example, but the readability could be cleaned up with a Compose Method refactoring. If you had a class that accepted a document and the current user principal, then you could have something like:

    public class DocumentPermissions
    {
        private Document document;
        private User user;
    
        public DocumentPermissions(Document doc, User currentUser)
        {
            document = doc;
            user = currentUser;
        }
    
        public bool ShouldShowEditButton()
        {
            if(!IsTextDocument())
            {
                return false;
            }
            return IsSuperUser() || IsDocumentOwner() ||  DocumentIsEditable();
        }
    
        private bool IsTextDocument()
        {
            return document.docTypeId == documentEnum.docType.text;
        }
    
        private bool IsSuperUser()
        {
            return user.UserStatus == userEnum.Status.SuperUser;
        }
    
        private bool IsDocumentOwner()
        {
            return user.UserID == document.CreatedByUserId ;
        }
    
        private bool DocumentIsEditable()
        {
            return document.statusId == documentEnum.docStatus.Editable ;
        }
    }
    

    Obviously this is a lot of code so I hope you can make reuse of many of the private methods.