Skip to end of metadata
Go to start of metadata

Implement role-based access control (RBAC)

You can implement role-based access control with Repose with the Header Normalization, the Authorization, and the API Validator filters. This guide takes you through the process of setting up RBAC with Repose.

1. Configure the Header Normalization filter

To prevent users from submitting their own roles, you will need to blacklist headers using the Header Normalization filter. 

header-normalization.cfg.xml
<header-filters>
...
 <target>
   <blacklist id="ReposeHeaders">
     <header id="X-Authorization"/>
     <header id="X-Identity-Status"/>
     <header id="X-Impersonator-Id"/>
     <header id="X-Impersonator-Name"/>
     <header id="X-PP-Groups" />
     <header id="X-PP-User" />
     <header id="X-Roles"/>
     <header id="X-Tenant-Id"/>
     <header id="X-Tenant-Name"/>
     <header id="X-User-Id"/>
     <header id="X-User-Name"/>
   </blacklist>
 <target>
</header-filters>

For more information about the configuration options in the Header Normalization filter, see Header Normalization filter

2. Configure then Authentication filter

The Authentication filter will grab the user's roles from their authentication token and return those roles to Repose. 

For more information about the configuration options in the Keystone v2 filter, see Keystone v2 filter

3. Configure the RBAC filter

There are two mechanisms for doing the authorization side. If your API is minimal or your just getting started with it, then you might find the Simple RBAC filter most useful. It uses a very simple Domain Specific Language (DSL) that is similar to what other tools use for this basic mechanism. If on the other had your API is large and/or your authorizations are complex, then you will need the heavy lifting of the API Validation filter. Since the Simple way is very self explanatory, we will only dive into the more complex way here.

You will do most of your RBAC configuration here. 

  1. We recommend that you build a table similar to the example below that contains endpoints and the roles that you wish to allow access to those endpoints.
CapabilityRole
Method nameAPI actiona:creatora:observera:admin
Create New WidgetPOST /a/x
x
List WidgetsGET /a/
xx
Replace WidgetPUT /a/xxx

Delete Widget

DELETE /a/

x

2. In the API Validator filter, set the enable-rax-roles attribute to true.

When the enable-rax-roles attribute is set to true, the check-headers attribute will also be enabled regardless of your setting. 


3. In the WADL, include rax:roles with appropriate values to ensure access is controlled as expected.

    • When defining rax:roles at the resource level, be aware that all sub-resources and methods will inherit the roles allowed at the resource level. 
    • Multiple roles can be specified by separating the role names with a space. If multiple roles are authorized for a resource and method, the user must have one of the allowed roles but is not required to have all roles.

Example API Validator filter configuration for RBAC.

The following example shows a section of the API Validator filter and WADL that is configured for RBAC.

validator.cfg.xml
<?xml version="1.1" encoding="UTF-8"?>

<validators multi-role-match="true" xmlns='http://openrepose.org/repose/validator/v1.0' version="1">
   <validator 
      role="default"
      default="true"
      wadl="file://my/wadl/filewithraxroles.wadl" 
      dot-output="/tmp/default.dot"
      enable-rax-roles="true"/>
</validators>
api_with_roles.wadl
<application xmlns="http://wadl.dev.java.net/2009/02" xmlns:rax="http://docs.rackspace.com/api">
      <resources base="https://test.api.openstack.com">
        <resource path="/a" rax:roles="a:admin">
          <method name="POST" rax:roles="a:creator">
            <request>
              <representation mediaType="application/xml"/>
            </request>
          </method>
          <method name="GET" rax:roles="a:observer">
            <request>
              <representation mediaType="application/xml"/>
            </request>
          </method>
          <method name="PUT" rax:roles="a:observer a:creator">
            <request>
              <representation mediaType="application/xml"/>
            </request>
          </method>
          <method name="DELETE">
            <request>
              <representation mediaType="application/xml"/>
            </request>
          </method>
        </resource>
      </resources>
    </application>

With the above WADL and API Validator filter configuration, the following behavior will apply with a request with a user that has the a:observer role.

    • GET or PUT is allowed.
    • DELETE will return 403 Forbidden as the DELETE method inherits the a:admin role from its parent resource.
    • PATCH will return 405 MethodNotAllowed.
    • POST will return a 403 Forbidden, as the method is allowed for the resource but the user does not have the a:admin or the a:creator role.

For more information about the configuration options in the API Validator filter, see API Validation filter

Return codes and conditions

Response Code
Description
Returned When:
403ForbiddenA requested resource or method requires a specific X-Roles header and that header is not found.
405Method Not AllowedThe URI is valid, but the method is not appropriate for the URI.

The status codes returned by authorization failures, via rax:roles extensions (403), differs from the statuses returned when roles are defined directly in the validator.cfg.xml (404 and 405).

3 Comments

  1. Repose team,

    Is it correct to say these:

    • if you put rax:roles on a resource, it overrides parent's resource's rax:roles

    • if you put rax:roles on a method, it adds to parent's resource's rax:roles

    In other words, if I have this:

            <resource path="v2.0" id="version" rax:roles="role1 role2">
                <method name="GET" rax:roles="role3">
                </method>
                <resource path="{tenantId}" rax:roles="role4" id="tenantid">
                  <method name="GET"/>
                </resource>
            </resource>

    Then,

    • role1, role2, role3 should be able to GET /v2.0
    • only role4 can do GET /v2.0/{tenantId}

    Are those correct assumptions? If yes, then can we add this to the documentation here?

     

  2. Shinta Smith,

    Your assumptions are almost correct.

    TL;DR

    • role1, role2, & role3 will be able to GET /v2.0
    • role1, role2, & role4 will be able to GET /v2.0/{tenantId}

    All resources and methods inherit from their entire parental tree.

    There is currently no way to override this inheritance model.

    Full example:

    Given this WADL in an API-Validator filter:

    <?xml version="1.0" encoding="UTF-8"?>
    <application xmlns="http://wadl.dev.java.net/2009/02"
                 xmlns:xs="http://www.w3.org/2001/XMLSchema"
                 xmlns:rax="http://docs.rackspace.com/api">
        <resources>
            <resource path="v2.0" id="version" rax:roles="role1 role2">
                <method name="GET" rax:roles="role3"/>
                <resource path="{tenantId}" rax:roles="role4" id="tenantid">
                    <param style="template" type="xs:string" name="tenantId" rax:id=""/>
                    <method name="GET"/>
                </resource>
            </resource>
        </resources>
    </application>
    

    Here is the visualization of the WADL after expansion by API-Checker:

    Running this shell script:

    for ROLE in 1 2 3 4 ; do
        echo -e '\n================================================================================'
        echo -e "X-ROLES: role${ROLE}"
        echo -e '================================================================================'
        for RESOURCE in /v2.0 /v2.0/1234567890 ; do
            echo -e "Resource: ${RESOURCE}"
            echo -e '--------------------------------------------------------------------------------'
            curl -i -X GET http://127.0.0.1:8080${RESOURCE} \
                    -H "X-ROLES: role${ROLE}" \
                    -H 'Accept: application/json' \
                    -H 'X-Auth-Token: 1234567890-token'
            echo -e '\n--------------------------------------------------------------------------------'
        done
    done
    

    Will yield something like:

    ================================================================================
    X-ROLES: role1
    ================================================================================
    Resource: /v2.0
    --------------------------------------------------------------------------------
    HTTP/1.1 200 OK
    --------------------------------------------------------------------------------
    Resource: /v2.0/1234567890
    --------------------------------------------------------------------------------
    HTTP/1.1 200 OK
    --------------------------------------------------------------------------------
    
    ================================================================================
    X-ROLES: role2
    ================================================================================
    Resource: /v2.0
    --------------------------------------------------------------------------------
    HTTP/1.1 200 OK
    --------------------------------------------------------------------------------
    Resource: /v2.0/1234567890
    --------------------------------------------------------------------------------
    HTTP/1.1 200 OK
    --------------------------------------------------------------------------------
    
    ================================================================================
    X-ROLES: role3
    ================================================================================
    Resource: /v2.0
    --------------------------------------------------------------------------------
    HTTP/1.1 200 OK
    --------------------------------------------------------------------------------
    Resource: /v2.0/1234567890
    --------------------------------------------------------------------------------
    HTTP/1.1 403 Forbidden
    --------------------------------------------------------------------------------
    
    ================================================================================
    X-ROLES: role4
    ================================================================================
    Resource: /v2.0
    --------------------------------------------------------------------------------
    HTTP/1.1 403 Forbidden
    --------------------------------------------------------------------------------
    Resource: /v2.0/1234567890
    --------------------------------------------------------------------------------
    HTTP/1.1 200 OK
    --------------------------------------------------------------------------------