Automated access control testing with BDD-Security

Where we left off last time, we had a BDD-Security project configured to test authentication and session management of TeamMentor web services. The bulk of the configuration was done by extending the abstract Application.java class and implementing the interfaces ILogin and Ilogout.

To perform automated authorisation (access control) tests, BDD-Security relies on annotating methods in that class- best explained in an example. First up, we need to pick a TeamMentor web services function to test and wrap it in a method in the TeamMentorWSApplication.java class.

public void listUsers() {
    port.getUsers();  //The TeamMentor WebService
}

BDD-Security uses the @Restricted annotation to define which user roles should be allowed to access the given method. It takes two arguments: An array of user roles and a regular expression that should match any of the HTTP responses, for example:

@Restricted(roles = {"admin"}, verifyTextPresent = "UserID")
public void listUsers() {
     port.getUsers();
}

The annotation is saying that the user role “admin” has access to all the operations in the listUsers() method, and if we look at the entire list of HTTP responses when calling that method, then the word “UserID” must be in one of those responses. Choosing the right “verifyTextPresent” word can be tricky, because it has to appear only in requests that succeed, and it absolutely must not appear if access control fails. This will probably require inspecting the raw HTTP requests to see what’s going on… for example, if we call getUsers() logged in as admin we get the following response:

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetUsersResponse xmlns="http://tempuri.org/"><GetUsersResult><TMUser><UserID xmlns="https://TeamMentor.securityinnovation.com:13415/">1713224071</UserID><UserName xmlns="https://TeamMentor.securityinnovation.com:13415/">admin</UserName><FirstName xmlns="https://TeamMentor.securityinnovation.com:13415/">John</FirstName><LastName xmlns="https://TeamMentor.securityinnovation.com:13415/">Smith</LastName><Title xmlns="https://TeamMentor.securityinnovation.com:13415/">Director</Title><Company xmlns="https://TeamMentor.securityinnovation.com:13415/">XYZ</Company><EMail xmlns="https://TeamMentor.securityinnovation.com:13415/" /><GroupID xmlns="https://TeamMentor.securityinnovation.com:13415/">1</GroupID><IsActive xmlns="https://TeamMentor.securityinnovation.com:13415/">false</IsActive><CSRF_Token xmlns="https://TeamMentor.securityinnovation.com:13415/">-1992161205</CSRF_Token><ExpirationDate xsi:nil="true" xmlns="https://TeamMentor.securityinnovation.com:13415/" /></TMUser><TMUser><UserID xmlns="https://TeamMentor.securityinnovation.com:13415/">1706173837</UserID>
...

And if we perform the same operation logged in as “reader” then the response is:

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>System.Web.Services.Protocols.SoapException: Server was unable to process request. ---&gt; System.Security.SecurityException: Request for principal permission failed.
   at System.Security.Permissions.PrincipalPermission.ThrowSecurityException()
   at System.Security.Permissions.PrincipalPermission.Demand()
   at System.Security.PermissionSet.DemandNonCAS()
   at SecurityInnovation.TeamMentor.WebClient.WebServices.TM_WebServices.GetUsers()
   --- End of inner exception stack trace ---</faultstring><detail /></soap:Fault></soap:Body></soap:Envelope>

So choosing the word “UserID”, which only appears in the valid response seems like a safe bet. Using the same idea we can implement more TeamMentor functionality:

    @Restricted(roles = {"admin"}, verifyTextPresent = "UserID")
    public void listUsers() {
        port.getUsers();
    }

    @Restricted(roles = {"admin","editor"}, verifyTextPresent = "CreateArticle_SimpleResult")
    public void createArticle() {
        port.createArticleSimple(Config.getXml().getString("testLibraryId"),"title test","String","<h1>A test</h1>");
    }

    @Restricted(roles = {"admin"}, verifyTextPresent = "CreateUserResult")
    public void createUser() {
        NewUser user = new NewUser();
        user.setEmail("test@test.com");
        user.setFirstname("bob");
        user.setLastname("bobster");
        user.setUsername("bobster");
        user.setGroupId(1);
        port.createUser(user);
    }

And of course we need to provide BDD-Security with the user credentials and role information in the config.xml file:

    <users>
        <user username="reader" password="tmreader">
            <role>reader</role>
        </user>
        <user username="editor" password="tmeditor">
             <role>editor</role>
        </user>
        <user username="admin" password="tmadmin">
            <role>admin</role>
        </user>
    </users>

And that’s it! BDD-Security is now all configured to run the authorisation story (in addition to the authentication and session management stories from last time).
The authorisation story defines 3 scenarios:

  • Scenario: Authorised users can view restricted resources – More of a configuration test than a security test, it just ensures that the users can access the methods as defined in the configuration and that the “verifyText” is present as expected.
  • Scenario: Users must not be able to view resources for which they are not authorised – The core access control tests
  • Scenario: Un-authenticated users should not be able to view restricted resources

Ready to run:

mvn exec:java

The result of the test can be seen here, and happily there are no access control failures 🙂
One of the advantages of BDD over TDD is the improved communication between business stake holders and developers- and security testing is no different. BDD-Security uses tables to define access control rules which are easily understandable to non-developers. Firstly an authorised access control matrix (who should access what):

method username password verifyString
listUsers admin tmadmin UserID
createArticle admin tmadmin CreateArticle_SimpleResult
createArticle editor tmeditor CreateArticle_SimpleResult
createUser admin tmadmin CreateUserResult

and secondly, a table of unauthorised access control (who should not see what):

method username password verifyString
listUsers reader tmreader UserID
listUsers editor tmeditor UserID
createArticle reader tmreader CreateArticle_SimpleResult
createUser reader tmreader CreateUserResult
createUser editor tmeditor CreateUserResult

It’s now a matter of expanding the tests by wrapping more TeamMentor WS functions and annotating them with the appropriate @Restricted values and we’ll have complete automated security regression tests for TeamMentor’s web services.

Next time, we’ll enable Burp scanning.

Advertisements
This entry was posted in UnitTests, WebServices. Bookmark the permalink.

One Response to Automated access control testing with BDD-Security

  1. Pingback: Automated Burp Security Scanning with BDD-Security | TeamMentor Development and Testing

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s