Skip to end of metadata
Go to start of metadata

Contents

Purpose

The API Validation filter validates all requests based on an XSD and WADL. For example, if a request to the authentication service is missing the username in the URI, but the authentication service requires the username in the URI, then the request will be rejected before it reaches the authentication service.

Recommended Reading

To use the API Validation, you should understand the XML Schema Definition (XSD) used for generating a Web Application Description Language (WADL) file. A good tutorial on XSD 1.1, including a comparison of XSD 1.1 and XSD 1.0, is at http://www.xfront.com/xml-schema-1-1/.

Some of the ideas we've implemented here are described in "Using XProc, XSLT 2.0, and XSD 1.1 to validate RESTful services" at http://www.balisage.net/Proceedings/vol8/html/Williams01/BalisageVol8-Williams01.html.

The API validation filter uses validation code from https://github.com/InABlender/api-checker.

General filter information

Filter name: api-validator

Filter configuration: validator.cfg.xml

Released: version 2.1.6

Prerequisites

Required headers: The API Validation filter has no required request headers.

Required preceding filters: The API Validation filter has no required preceding filters.

Standard filter order:  If you are using other filters in your system model configuration, refer to the standard filter order table to determine where to place the API Validation filter.

Basic configuration

The validator.cfg.xml contains a list of validator elements.  A validator element specifies the WADL to be used in order to validate a request for a user of a given role or group.  A validator can be marked as a default validator. Requests which do not have group information available or for which the group does not match any of the specified roles, will be validated against the first default validator. Each validator can reference an external WADL using an absolute path or relative path via the wadl attribute or using a WADL embedded inside the validator element.

Deprecation Warning

Support for multiple validators and embedded WADLs is deprecated in Repose 8 and will be removed in Repose 9.  If necessary, you can always configure multiple instances of the API Validation filter configured for different URLs in your system model.

Configure the API Validation filter by editing the validator.cfg.xml file.

1. Set Up Repose 
Configure Repose using either a cluster or a single instance configuration.

2. Add the API Validation filter 
Add to Repose by including <filter name="api-validator"/> to your filter chain in the system-model.cfg.xml and include the validator.cfg.xml in your Repose configuration directory.

3. Configure the API Validation filter 

Within the validator element:

  • Configure the role attribute to match requests according to the x-roles header with the highest quality value.
  • Configure the wadl attribute to specify a relative path to Repose's configuration root directory such as wadl.wadl or subfolder/wadl.
    • NOTE: In v7.0.1.1 and newer, the wadl attribute can also specify an an absolute path such as /path/to/wadl.wadl, but is NOT a URL. No matter what, it must be a path on the filesystem.
    • NOTE: In v7.0.1.0 and older, if the path is not relative, then the value is assumed to be a URL.

Configuration options

Delegating mode

In some cases, you may want to delegate the validation of a request down the chain to either another filter or to the origin service. Delegation prevents the API Validator filter from failing the request by forwarding the request with the X-Delegated header that is set with a value which indicates how the filter would have failed if not in delegating mode. 

To place the filter in delegating mode, add the delegating element to the filter configuration with a quality that determines the delegation priority.

The format for the X-Delegated header value is “status_code={status-code}`component={filter-name}`message={failure message};q={delegating-quality}”

Configurable parameters

XML schema definition

Example configuration

The validator.cfg.xml will contain a list of validator elements.  A validator element will specify the WADL to be used in order to validate a request for a user of a given role/group.  A validator can be marked as a default validator.  Requests which do not have group information available or for which the group does not match any of the specified roles, will be validated against the first default validator.

Each validator can either reference an external wadl via the wadl attribute or wadl embedded inside the validator element.

Xerces Vs Saxon

If you receive the error "Unable to find resource: saxon-license.lic" then consider changing the xsd-engine attribute to xerces, which does not require a license.

Xerces should work for most customer's needs. Saxon XSLT Processing Engine requires a license. If you use complicated transformations, or need to support XSLT 3.0, consider Saxon.

ElementAttribute

Required/

Optional

DescriptionVersion
<validators>
-RequiredTag that contains all of the validators.
multi-role-matchOptional

If set to true, it matches validators to header x-roles and all matches are validated until one of them is valid. In the event that all matches are invalid, the response returned will be that of the last matched validator.  If set to false or not set, it will match validators to header x-roles and only the first match is validated. Default value is false.

Warning: This attribute is deprecated in version 8 and will be removed in version 9.


<validator>

-

Required

Creates new validator.

Warning: Supporting multiple validators is deprecated in version 8 and will be removed in version 9. Repose 9 will require a single WADL to describe your endpoint. If necessary, you can always configure multiple instances of the API Validation filter configured for different URLs in your system model.


role

Required

Lists roles that are applied on single validator. Will match this validator to requests according to header x-roles with highest quality value.

Warning: This attribute is deprecated in version 8 and will be removed in version 9. Roles will have to be specified using rax:roles in the WADL.


enable-api-coverageOptionalIf set to true, this validator will record, via JMX, the number of times each state in the generated state machine (the mechanism underlying API validation) is accessed. These values may be used to determine API usage and coverage. Default value is false.
defaultOptional

When set to true, matches the default validator. When not set or set to false, requests that do not specifically match any validators will result in 403s.

Warning: This attribute is deprecated in version 8 and will be removed in version 9.

You need to set default to true in order to match the validator, even if you have only one validator.


wadl

Required only if a WADL is not embedded.

The WADL/Checker Document location can be specified as an absolute path or as a relative path to Repose's configuration root directory. The path is not a URL; it is a path on the filesystem.

Versions prior to 7.0.1.0 do not support absolute paths to load a WADL or loading a pre-compiled Checker Document

Warning: This will become a required attribute in version 9. Support for embedded WADLs is deprecated in version 8 and will be removed in version 9.


dot-outputOptionalDot output file for this validator.
check-well-formedOptionalChecks that the request body is well-formed XML or JSON that conforms to the XML or JSON syntax rules. Default value is false.
check-xsd-grammarOptional

If set to true and the WADL references an XSD grammar, it checks that the incoming request body is validated against the XSD grammar. Default value is false.

Warning: This attribute is deprecated. Please use the check-grammars attribute instead.


check-grammarsOptionalIf set to true and the WADL references an XSD or JSON grammar, then it checks the incoming request body will validated against the grammar. Default value is false.7.2.0.0
check-elementsOptionalIf set to true and the WADL request representation contains an element, the filter will check the root element of a request. Default value is false.
check-plain-paramsOptionalIf set to true and the WADL has plain parameters defined, the filter will check the plain parameters. Default value is false.
do-xsd-grammar-transformOptionalAllows XSD grammar transform. Transforms the XML after validation. Default value is false.
enable-pre-process-extensionOptionalIf set to true, allows the filter to perform a transform before XSD validation takes place. The transformation rules can be defined in the WADL via the Rackspace WADL rax:preprocess extension. Default value is true.
remove-dups

Optional

Analyzes the state machine generated from the WADL to determine if any duplicate nodes are in the machine. Default is true.
xpath-versionOptional

XPath version used in the WADL.  Can be 1 or 2. If 1 is set, the Xalan implementation will be used, if 2 is set, then Saxon will be used. Default is 1.

XPath 2 with schema awareness requires a Saxon license.


xsl-engineOptional

The XSL 1.0 engine to use. Possible choices are Xalan, XalanC, SaxonHE, or SaxonEE. Default is XalanC.

  • Xalan - standard Java XSL engine
  • XalanC - an efficient 1.0 engine that compiles XSL into byte code
  • SaxonHE - Implements v2.0 of the XSL language, but gives a license error when attempting a transform
  • SaxonEE - Implements v2.0 of the XSL language, and allows transforms

Saxon is an XSL 2.0 engine, but most 1.0 XSLs should work fine.


xsd-engineOptional

The XSD engine to use for validation. This means that in cases where XSD validation needs to be done a user may choose to use the Saxon XSD validator instead of the default Xerces validator. Possible choices are Xerces or SaxonEE. Default is Xerces.

Xerces should work for most customers' needs. Saxon XSLT Processing Engine requires a license. If you use complicated transformations, or need to support XSLT 3.0, consider Saxon.


mask-rax-roles-403OptionalMask rax-roles with 404 and 405 errors. By default rax-roles responds with a 403 if there is a role mismatch. If mask-rax-roles is set to true, the response will be a 404 if no methods are accessible or a 405 if some methods are available. Default is false.
enable-ignore-xsd-extensionOptionalEnables the use of the rax:ignoreXSD extension in WADL files to exclude some representations from validation against the XSD.  Default value is true if not specified.
validator-nameOptionalSets the name for this validator item. The name is used as the MBean name when connecting to Repose via JMX.
validate-checkerOptional

If set to true, it checks the validity of the generated state machine (e.g. no dead-end paths, there is a single start state, no non-connected nodes, etc.)

If set to false, it does nothing.

Default value is true.


join-xpath-checksOptionalAn optimization that merges the well formed check and multiple XPath checks into a single check. Default is true.
check-headersOptionalIf set to true and the WADL defines required headers, then the filter will check that those required headers are present. Default is false.
enable-rax-rolesOptional

Enables the use of rax:roles in WADL files to determine resource access. 

If set to true, rax:roles defined in the supplied WADL files will be used to determine resource access and check-headers will also be enabled regardless of your setting. 

If set to false, rax:roles defined in WADL files are not used to determine resource access. Default is false.


As of Repose v7.2.2.0, roles defined in a rax:roles attribute support role names that contain spaces. This is accomplished in this filter through the use of nonbreaking spaces. Simply input a non-breaking space, in the place where the role name should have a space. The easiest way to do this is to use the entity &#xA0;, but you can also input non-breaking spaces directly into the WADL. See the following for more information: https://en.wikipedia.org/wiki/Non-breaking_space#Keyboard_entry_methods


<delegating>-Optional

If present, the filter will not send a failing response when an invalid state is reached. Instead, a validator will add the data relating to the failure to a header and forward the request to be handled by a different filter or service. 

If not present, a validator will send a failing response when an invalid state is reached.


qualityOptionalThe quality, a double between 0 and 1, assigned to the delegation header on delegation. This value will be used to order delegation based on priority when multiple delegations are present. Default is 0.3.
component-nameOptional

The component name used in the delegation header. This is particularly useful when multiple instances of an API-Checker based filter are used in the same filter chain.


Default up to and including v7.1.7.0 is "api-checker", but was changed in v7.2.0.0 to "api-validator".


Return codes and conditions

Response CodeDescriptionReturned When:
401UnauthorizedA requested resource or method requires a specific X-Authenticated-By header, and that header is not found.
403ForbiddenA requested resource or method requires a specific X-Roles header, and that header is not found.
404Not Found

The filter determined that the URI is invalid.

When mask-rax-roles-403 is enabled, this could also indicate the supplied X-Roles did not have access to the URI.

405Method Not Allowed

The URI is valid, but the Method is not appropriate for the URI.

When mask-rax-roles-403 is enabled, this could also indicate the supplied X-Roles had access to the URI but not the requested Method.

Request headers created

The API Validation filter does not create any request headers.

Optional configurations


Role-based access control (RBAC) via WADL template


To implement Role Based Access Control, you will need more than the Validation Filter. Please read Role-based access control (RBAC) with Repose


With Repose 2.12.0, a feature was added to support role based access control using a custom rax:roles extension defined in the WADL.


Response Messaging service

If a request fails validation, then an appropriate response code will be returned.  For example, if the validator determines that the URI is invalid, a 404 will be returned.  If the URI is valid, but the method is not appropriate for the URI, then a 405 will be returned.  However, in order to display an appropriate error message, then response messaging service will need to be configured. See here for more information about the Response Messaging service.

Sample Response Messaging configuration

response-messaging.cfg.xml
<response-messaging xmlns="http://docs.openrepose.org/repose/response-messaging/v1.0">
  <status-code id="404" code-regex="4.." overwrite="ALWAYS">
    <message media-type="*/*">Error Message: %M</message>
    <message media-type="application/xml"><![CDATA[<error-message>%M</error-message>]]></message>
    <message media-type="application/json"><![CDATA[{"error-message": "%M"}]]> </message>
  </status-code>
</response-messaging> 



Disable media types for a web resource

If you want to disable media types for a web resource, the following steps will guide you through the process.

  1. In the validator.cfg.xml file configure check-headers to true.
  2. Under the request element of the WADL, configure the Accept header that you want to disable with the media type that is accepted.
  3. Configure the Accept header to return a 406 error code and an error message stating that the accept type is not supported.

In the following example, the only Accept headers that are accepted are application/xml or application/atom+xml. Anything else will return a 406 error message that says, “I don’t support that accept type”.

Disable media type for a web resource
<wadl:request>
     <wadl:param name=”ACCEPT”  fixed=”application/xml” style="header" rax:code="406" rax:message=”I don’t support that accept type" type=”xsd:string” repeating=”true"         
      required="true”>
  
     <wadl:param name=”ACCEPT” fixed=”application/atom+xml” style="header" rax:code="406" rax:message=”I don’t support that accept type" type=”xsd:string” repeating=”true"
      required="true”>  
</wadl:request>



Limit by Authentication Method

If you want to limit access to a resource and/or method by how the client was authenticated (e.g. PASSWORD, RSAKEY, etc.), you can add a rax:authenticatedBy attribute with a space delimited list of authentication methods that are allowed to access the specified resource, child resources, and/or method in your WADL.  When accessing one of these resource methods, requests must have an X-Authenticated-By header containing one of the required values; otherwise, the request will be rejected with a 401.

For example, if a method requires an X-Authenticated-By value of 'RSAKEY', a request with the header value of 'RSAKEY', 'RSAKEY,PASSWORD', or 'FEDERATED,RSAKEY' would not be rejected by this feature.  If the request had the header value 'PASSWORD', 'FEDERATED,PASSCODE', or 'IMPERSONATION,APIKEY', the request would be rejected for not containing 'RSAKEY'.

This feature does not bypass any other request limiting/rejecting feature.  For example, if a resource method has both a rax:roles and a rax:authenticatedBy applied to it, both must be satisfied for processing of the request to continue.

The rax:authenticatedBy attribute can be applied to WADL resource and method elements and has the same behavior as rax:roles in how it's applied.  The example below covers the various conditions.

sample-auth-by.wadl
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="wadl.xsl"?>
<application xmlns="http://wadl.dev.java.net/2009/02" xmlns:rax="http://docs.rackspace.com/api">
    <resources base="http://localhost:${targetPort}">
        <resource path="v0">
            <resource path="safe" rax:authenticatedBy="PASSWORD">
                <!-- Access to these two methods require an X-Authenticated-By header with the value 'PASSWORD' -->
                <method name="POST"/>
                <method name="GET"/>
            </resource>
            <resource path="parent" rax:authenticatedBy="APIKEY">
                <resource path="inherited">
                    <!-- Acceptable value inherited from parent resource: 'APIKEY' -->
                    <method name="POST"/>
                    <method name="GET"/>
                </resource>
                <resource path="child" rax:authenticatedBy="RSAKEY">
                    <!-- Acceptable values: 'APIKEY', 'RSAKEY', or 'IMPERSONATION' -->
                    <method name="POST" rax:authenticatedBy="IMPERSONATION"/>
                    <method name="GET" rax:authenticatedBy="IMPERSONATION"/>
                </resource>
                <resource path="open" rax:authenticatedBy="#all">
                    <!-- #all makes all values valid (including no value) despite inherited restriction -->
                    <method name="POST"/>
                    <method name="GET"/>
                </resource>
            </resource>
            <resource path="none">
                <!-- All values are valid (including no value) -->
                <method name="POST"/>
                <method name="GET"/>
            </resource>
            <resource path="vary">
                <!-- Valid values set at method level.
                     POST accepts 'PASSWORD' or 'FEDERATED'.
                     GET and PATCH accept any value (including no value).
                     PUT only allows value 'PASSCODE'.
                     DELETE only allows value 'OTPPASSCODE'. -->
                <method name="POST" rax:authenticatedBy="PASSWORD FEDERATED"/>
                <method name="GET"/>
                <method name="PUT" rax:authenticatedBy="PASSCODE"/>
                <method name="PATCH" rax:authenticatedBy="#all"/>
                <method name="DELETE" rax:authenticatedBy="OTPPASSCODE"/>
            </resource>
        </resource>
    </resources>
</application>





API coverage documentation

Implemented in version 6.0.2.

If you want to enable API coverage documentation so that you can monitor your application states, the following steps will guide you through the process.

Step-by-step guide

  1. Install Graphviz or a similar visualization tool that can be used to draw graphs that are specified in dot.
  2. Add the validator.cfg.xml file to your system model configuration.
  3. In the validator.cfg.xml file, add the attribute enable-api-coverage="true".
validator.cfg.xml example
<?xml version="1.1"
encoding="UTF-8"?>
<validators multi-role-match="false" xmlns='http://docs.openrepose.org/repose/validator/v1.0'>
    <validator
        role="default"
        default="true"
        wadl="client-service-user.wadl"
        dot-output="default.dot"  
        enable-rax-roles="true"
        enable-api-coverage="true"/>
</validators>

     4. Run your visualization tool using the file name default.dot. You will find this file under com.rackspace.com.papi.components.checker.handler in JMX.


Understanding the state machine

URI state          method state        fail state

--------------

U: URI                                     

U (v1): URI /v1

M: method

H: header

---------------

H(X: y) : If header X matches regular expression y

H(X: a:t) if header X is valid with XML schema type a:t

U(y) : If uri path component matches regular expression y

U(a:t) : if uri path component is valid according to XML schema type a:t

M(y) : if method name matches regular expression y 

 

U!(y) : If uri path component DOES NOT match regular expression y

U!(a:t) : if uri path component is NOT valid according to XML schema type a:t

M!(y) : if method name DOES NOT match regular expression y

 

 

Each value will have a counter and will map to the number of times that state gets hit.

 

 

 

Change history

Version 7.0.1.0: The WADL location can be specified as an absolute path or as a relative path to Repose's configuration root directory. 

Version 8.0.0.0: Added deprecation warnings for configuration that supported multiple validators.

  • No labels

8 Comments

  1. Btw, the configuration that uses file://, I have not been able to make it work! Is it really supported?

    file://my/wadl/filewithraxroles.wadl

    I have Repose 6.1.1.1

  2. Hi Shinta, 

    Our ninja is looking in to this and will get back with you.

  3. Also, what is the default value of xsl-engine, if one is not specified?

  4. Shinta Smith: The default of xsl-engine is XalanC. 

     

    Renee Rendon: Perhaps we should include the default value for optional nodes? 

  5. Shinta Smith: Just played around with the API Validator a bit. It seems that we try and load the wadl using the Repose configuration root directory as the base directory. Any path provided in the "wadl" attribute gets appended to the configuration root. I've created a story to address this issue at:  REP-1435 - Getting issue details... STATUS

  6. Thanks for investigating and taking care of this! We can work around the REP-1435 by specifying ../../../ and stuff. Ugly, but I suspect it will work ok.

    -shinta

  7. Damien Johnson  Yes, that needs to be done. I will put it on my list. Thanks!

  8. The default values have been added.