Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rax Roles Extension requires upper case in tenanted role parameter names. #388

Closed
wdschei opened this issue Feb 19, 2018 · 1 comment · Fixed by #389
Closed

Rax Roles Extension requires upper case in tenanted role parameter names. #388

wdschei opened this issue Feb 19, 2018 · 1 comment · Fixed by #389
Labels
Milestone

Comments

@wdschei
Copy link
Contributor

wdschei commented Feb 19, 2018

Given the WADL below:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<application xmlns="http://wadl.dev.java.net/2009/02"
             xmlns:rax="http://docs.rackspace.com/api"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <resources base="https://test.api.openstack.com">
        <resource path="/v1/resource" rax:roles="a:admin/{X-TENANT-ID}">
            <param name="X-OTHER"
                   style="header"
                   required="true"
                   type="xsd:string"
                   repeating="false"/>
            <method name="POST" rax:roles="a:creator/{x-tenant-id}">
                <request>
                    <param name="x-tenant-id"
                           style="header"
                           required="true"
                           type="xsd:int"
                           repeating="true"
                           rax:isTenant="true"/>
                    <param name="X-Tenant-Id"
                           style="header"
                           required="true"
                           type="xsd:boolean"
                           repeating="true"
                           rax:isTenant="true"/>
                </request>
            </method>
            <method name="GET" rax:roles="a:observer/{X-TENANT-ID}">
                <request>
                    <param name="x-tENANT-iD"
                           style="header"
                           required="true"
                           type="xsd:int"
                           repeating="true"
                           rax:isTenant="true"/>
                    <param name="X-TENANT-ID"
                           style="header"
                           required="true"
                           type="xsd:boolean"
                           repeating="true"
                           rax:isTenant="true"/>
                </request>
            </method>
            <method name="PUT" rax:roles="a:updater/{X-TENANT-ID}">
                <request>
                    <param name="x-tenant-id"
                           style="header"
                           required="true"
                           type="xsd:int"
                           repeating="true"
                           rax:isTenant="true"/>
                    <param name="X-TENANT-ID"
                           style="header"
                           required="true"
                           type="xsd:boolean"
                           repeating="true"
                           rax:isTenant="true"/>
                </request>
            </method>
            <method name="DELETE">
                <request>
                    <param name="X-Tenant-Id"
                           style="header"
                           required="true"
                           type="xsd:int"
                           repeating="true"
                           rax:isTenant="true"/>
                    <param name="x-tENANT-iD"
                           style="header"
                           required="true"
                           type="xsd:boolean"
                           repeating="true"
                           rax:isTenant="true"/>
                </request>
            </method>
            <resource path="other">
                <method name="POST" rax:roles="a:creator/{X-TENANT-ID}">
                    <request>
                        <param name="x-tenant-id"
                               style="header"
                               required="true"
                               type="xsd:int"
                               repeating="true"
                               rax:isTenant="true"/>
                        <param name="x-tENANT-iD"
                               style="header"
                               required="true"
                               type="xsd:boolean"
                               repeating="true"
                               rax:isTenant="true"/>
                    </request>
                </method>
                <method name="GET" rax:roles="#all">
                    <request>
                        <param name="X-Tenant-Id"
                               style="header"
                               required="true"
                               type="xsd:int"
                               repeating="true"
                               rax:isTenant="true"/>
                        <param name="X-TENANT-ID"
                               style="header"
                               required="true"
                               type="xsd:boolean"
                               repeating="true"
                               rax:isTenant="true"/>
                    </request>
                </method>
                <method name="PUT" rax:roles="a:updater/{X-TENANT-ID}">
                    <request>
                        <param name="X-TENANT-ID"
                               style="header"
                               required="true"
                               type="xsd:int"
                               repeating="true"
                               rax:isTenant="true"/>
                        <param name="X-TENANT-ID"
                               style="header"
                               required="true"
                               type="xsd:boolean"
                               repeating="true"
                               rax:isTenant="true"/>
                    </request>
                </method>
                <method name="DELETE">
                    <request>
                        <param name="X-TENANT-ID"
                               style="header"
                               required="true"
                               type="xsd:int"
                               repeating="true"
                               rax:isTenant="true"/>
                        <param name="X-TENANT-ID"
                               style="header"
                               required="true"
                               type="xsd:boolean"
                               repeating="true"
                               rax:isTenant="true"/>
                    </request>
                </method>
                <method name="PATCH" rax:roles="role&#xA0;with&#xA0;spaces/{X-TENANT-ID} a:patcher/{X-TENANT-ID}">
                    <request>
                        <param name="X-TENANT-ID"
                               style="header"
                               required="true"
                               type="xsd:int"
                               repeating="true"
                               rax:isTenant="true"/>
                        <param name="X-TENANT-ID"
                               style="header"
                               required="true"
                               type="xsd:boolean"
                               repeating="true"
                               rax:isTenant="true"/>
                    </request>
                </method>
            </resource>
        </resource>
    </resources>
</application>

This is the stacktrace received:

2018-02-19 17:07:47,415 18871 [Event Kernel Thread] ERROR com.rackspace.cloud.api.wadl.util.LogErrorListener - rax:roles match for role 'a:observer/{x-tenant-id}', but no defined param named 'x-tenant-id' in this case.
2018-02-19 17:07:47,417 18873 [Event Kernel Thread] ERROR com.rackspace.cloud.api.wadl.util.LogErrorListener - Processing terminated by xsl:message at line 423 in raxRolesTenants.xsl
2018-02-19 17:07:47,418 18874 [Event Kernel Thread] ERROR com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder - Processing terminated by xsl:message at line 423 in raxRolesTenants.xsl
2018-02-19 17:07:47,418 18874 [Event Kernel Thread] WARN  org.openrepose.filters.apivalidator.ValidatorInfo - Error loading validator for WADL: file:/home/bill7601/Projects/repose/repose-aggregator/tests/functional-tests/build/test-homes/features/filters/apivalidator/ApiValidatorMultiTenantTest/configs/headerAllAtMethodTenantExplicit.wadl.xml
com.rackspace.com.papi.components.checker.wadl.WADLException: WADL Processing Error: Processing terminated by xsl:message at line 423 in raxRolesTenants.xsl
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder.buildFromWADL(WADLCheckerBuilder.scala:749) ~[checker-core-2.6.1-SNAPSHOT.jar:2.6.1-SNAPSHOT]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder.build(WADLCheckerBuilder.scala:808) ~[checker-core-2.6.1-SNAPSHOT.jar:2.6.1-SNAPSHOT]
	at com.rackspace.com.papi.components.checker.wadl.StepBuilder.build(StepBuilder.scala:59) ~[checker-core-2.6.1-SNAPSHOT.jar:2.6.1-SNAPSHOT]
	at com.rackspace.com.papi.components.checker.Validator$.apply(Validator.scala:67) ~[checker-core-2.6.1-SNAPSHOT.jar:2.6.1-SNAPSHOT]
	at com.rackspace.com.papi.components.checker.Validator.apply(Validator.scala) ~[checker-core-2.6.1-SNAPSHOT.jar:2.6.1-SNAPSHOT]
	at org.openrepose.filters.apivalidator.ValidatorInfo.initValidator(ValidatorInfo.java:96) [api-validator-filter-8.8.1.0-SNAPSHOT.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.filters.apivalidator.ValidatorInfo.reinitValidator(ValidatorInfo.java:122) [api-validator-filter-8.8.1.0-SNAPSHOT.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.filters.apivalidator.ApiValidatorHandlerFactory$ApiValidatorWadlListener.configurationUpdated(ApiValidatorHandlerFactory.java:188) [api-validator-filter-8.8.1.0-SNAPSHOT.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.filters.apivalidator.ApiValidatorHandlerFactory$ApiValidatorWadlListener.configurationUpdated(ApiValidatorHandlerFactory.java:160) [api-validator-filter-8.8.1.0-SNAPSHOT.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.core.services.config.impl.ConfigurationServiceImpl.subscribeTo(ConfigurationServiceImpl.java:137) [repose-valve.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.core.services.config.impl.ConfigurationServiceImpl.subscribeTo(ConfigurationServiceImpl.java:128) [repose-valve.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.filters.apivalidator.ApiValidatorHandlerFactory.addWadlListener(ApiValidatorHandlerFactory.java:126) [api-validator-filter-8.8.1.0-SNAPSHOT.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.filters.apivalidator.ApiValidatorHandlerFactory.initialize(ApiValidatorHandlerFactory.java:113) [api-validator-filter-8.8.1.0-SNAPSHOT.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.filters.apivalidator.ApiValidatorHandlerFactory.configurationUpdated(ApiValidatorHandlerFactory.java:88) [api-validator-filter-8.8.1.0-SNAPSHOT.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.filters.apivalidator.ApiValidatorHandlerFactory.configurationUpdated(ApiValidatorHandlerFactory.java:45) [api-validator-filter-8.8.1.0-SNAPSHOT.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.core.services.config.impl.ConfigurationServiceImpl.subscribeTo(ConfigurationServiceImpl.java:137) [repose-valve.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.core.services.config.impl.ConfigurationServiceImpl.subscribeTo(ConfigurationServiceImpl.java:120) [repose-valve.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.filters.apivalidator.ApiValidatorFilter.init(ApiValidatorFilter.java:70) [api-validator-filter-8.8.1.0-SNAPSHOT.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.powerfilter.filtercontext.FilterContextFactory.loadFilterContext(FilterContextFactory.java:123) [repose-valve.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.powerfilter.filtercontext.FilterContextFactory.buildFilterContexts(FilterContextFactory.java:63) [repose-valve.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.powerfilter.PowerFilter.configurationHeartbeat(PowerFilter.java:225) [repose-valve.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.powerfilter.PowerFilter.access$600(PowerFilter.java:91) [repose-valve.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.powerfilter.PowerFilter$ApplicationDeploymentEventListener.onEvent(PowerFilter.java:479) [repose-valve.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.core.services.event.EventDispatcherImpl.dispatch(EventDispatcherImpl.java:43) [repose-valve.jar:8.8.1.0-SNAPSHOT]
	at org.openrepose.core.services.event.PowerProxyEventKernel.run(PowerProxyEventKernel.java:75) [repose-valve.jar:8.8.1.0-SNAPSHOT]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_152]
Caused by: net.sf.saxon.s9api.SaxonApiException: Processing terminated by xsl:message at line 423 in raxRolesTenants.xsl
	at net.sf.saxon.s9api.XsltTransformer.transform(XsltTransformer.java:606) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder.com$rackspace$com$papi$components$checker$wadl$WADLCheckerBuilder$$raxRolesTenants(WADLCheckerBuilder.scala:502) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder$$anonfun$buildFromWADL$1$$anonfun$7.apply(WADLCheckerBuilder.scala:736) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder$$anonfun$buildFromWADL$1$$anonfun$7.apply(WADLCheckerBuilder.scala:736) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.BuilderHelper$.applyBuildSteps(BuilderHelper.scala:129) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder$$anonfun$buildFromWADL$1.apply$mcV$sp(WADLCheckerBuilder.scala:744) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder$$anonfun$buildFromWADL$1.apply(WADLCheckerBuilder.scala:703) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder$$anonfun$buildFromWADL$1.apply(WADLCheckerBuilder.scala:703) ~[?:?]
	at com.rackspace.cloud.api.wadl.util.XSLErrorDispatcher$class.handleXSLException(xsl-error-dispatcher.scala:15) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder.handleXSLException(WADLCheckerBuilder.scala:233) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder.buildFromWADL(WADLCheckerBuilder.scala:703) ~[?:?]
	... 25 more
Caused by: net.sf.saxon.expr.instruct.TerminationException: Processing terminated by xsl:message at line 423 in raxRolesTenants.xsl
	at net.sf.saxon.expr.instruct.Message.processLeavingTail(Message.java:223) ~[?:?]
	at net.sf.saxon.expr.instruct.Instruction.process(Instruction.java:151) ~[?:?]
	at net.sf.saxon.expr.parser.ExpressionTool.evaluate(ExpressionTool.java:350) ~[?:?]
	at net.sf.saxon.expr.parser.ExpressionTool.eagerEvaluate(ExpressionTool.java:463) ~[?:?]
	at net.sf.saxon.expr.TryCatch.iterate(TryCatch.java:281) ~[?:?]
	at net.sf.saxon.expr.parser.ExpressionTool.evaluate(ExpressionTool.java:340) ~[?:?]
	at net.sf.saxon.expr.parser.ExpressionTool.eagerEvaluate(ExpressionTool.java:463) ~[?:?]
	at net.sf.saxon.expr.TryCatch.iterate(TryCatch.java:281) ~[?:?]
	at net.sf.saxon.expr.Expression.process(Expression.java:927) ~[?:?]
	at net.sf.saxon.expr.LetExpression.processLeavingTail(LetExpression.java:703) ~[?:?]
	at net.sf.saxon.expr.instruct.TemplateRule.applyLeavingTail(TemplateRule.java:347) ~[?:?]
	at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:502) ~[?:?]
	at net.sf.saxon.trans.TextOnlyCopyRuleSet.process(TextOnlyCopyRuleSet.java:69) ~[?:?]
	at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:478) ~[?:?]
	at net.sf.saxon.trans.TextOnlyCopyRuleSet.process(TextOnlyCopyRuleSet.java:69) ~[?:?]
	at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:478) ~[?:?]
	at net.sf.saxon.expr.instruct.ApplyTemplates.apply(ApplyTemplates.java:295) ~[?:?]
	at net.sf.saxon.expr.instruct.ApplyTemplates.process(ApplyTemplates.java:248) ~[?:?]
	at net.sf.saxon.expr.parser.ExpressionTool.getIteratorFromProcessMethod(ExpressionTool.java:799) ~[?:?]
	at net.sf.saxon.expr.instruct.Instruction.iterate(Instruction.java:379) ~[?:?]
	at net.sf.saxon.expr.ItemChecker.iterate(ItemChecker.java:227) ~[?:?]
	at com.saxonica.ee.bytecode.ByteCodeCandidate.iterate(ByteCodeCandidate.java:290) ~[?:?]
	at net.sf.saxon.value.Closure.iterate(Closure.java:156) ~[?:?]
	at net.sf.saxon.expr.UserFunctionCall.iterate(UserFunctionCall.java:487) ~[?:?]
	at net.sf.saxon.expr.parser.Evaluator$5.evaluate(Evaluator.java:101) ~[?:?]
	at net.sf.saxon.expr.SystemFunctionCall.evaluateArguments(SystemFunctionCall.java:448) ~[?:?]
	at net.sf.saxon.expr.FunctionCall.iterate(FunctionCall.java:545) ~[?:?]
	at net.sf.saxon.expr.parser.ExpressionTool.evaluate(ExpressionTool.java:340) ~[?:?]
	at net.sf.saxon.expr.LetExpression.eval(LetExpression.java:511) ~[?:?]
	at net.sf.saxon.expr.LetExpression.iterate(LetExpression.java:485) ~[?:?]
	at com.saxonica.ee.bytecode.ByteCodeCandidate.iterate(ByteCodeCandidate.java:290) ~[?:?]
	at net.sf.saxon.expr.parser.ExpressionTool.evaluate(ExpressionTool.java:340) ~[?:?]
	at net.sf.saxon.expr.instruct.UserFunction.call(UserFunction.java:616) ~[?:?]
	at net.sf.saxon.expr.UserFunctionCall.callFunction(UserFunctionCall.java:541) ~[?:?]
	at net.sf.saxon.expr.UserFunctionCall.evaluateItem(UserFunctionCall.java:477) ~[?:?]
	at net.sf.saxon.expr.parser.ExpressionTool.evaluate(ExpressionTool.java:328) ~[?:?]
	at net.sf.saxon.expr.LetExpression.eval(LetExpression.java:511) ~[?:?]
	at net.sf.saxon.expr.LetExpression.process(LetExpression.java:580) ~[?:?]
	at com.saxonica.ee.bytecode.ByteCodeCandidate.process(ByteCodeCandidate.java:141) ~[?:?]
	at net.sf.saxon.expr.instruct.NamedTemplate.expand(NamedTemplate.java:264) ~[?:?]
	at net.sf.saxon.expr.instruct.CallTemplate$CallTemplatePackage.processLeavingTail(CallTemplate.java:518) ~[?:?]
	at net.sf.saxon.Controller.transformDocument(Controller.java:2404) ~[?:?]
	at net.sf.saxon.Controller.transform(Controller.java:1970) ~[?:?]
	at net.sf.saxon.s9api.XsltTransformer.transform(XsltTransformer.java:596) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder.com$rackspace$com$papi$components$checker$wadl$WADLCheckerBuilder$$raxRolesTenants(WADLCheckerBuilder.scala:502) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder$$anonfun$buildFromWADL$1$$anonfun$7.apply(WADLCheckerBuilder.scala:736) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder$$anonfun$buildFromWADL$1$$anonfun$7.apply(WADLCheckerBuilder.scala:736) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.BuilderHelper$.applyBuildSteps(BuilderHelper.scala:129) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder$$anonfun$buildFromWADL$1.apply$mcV$sp(WADLCheckerBuilder.scala:744) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder$$anonfun$buildFromWADL$1.apply(WADLCheckerBuilder.scala:703) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder$$anonfun$buildFromWADL$1.apply(WADLCheckerBuilder.scala:703) ~[?:?]
	at com.rackspace.cloud.api.wadl.util.XSLErrorDispatcher$class.handleXSLException(xsl-error-dispatcher.scala:15) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder.handleXSLException(WADLCheckerBuilder.scala:233) ~[?:?]
	at com.rackspace.com.papi.components.checker.wadl.WADLCheckerBuilder.buildFromWADL(WADLCheckerBuilder.scala:703) ~[?:?]
	... 25 more

It is being caused by the value of the first method element's rax:roles attribute. Regardless of the case of the param element's name attribute, the corresponding value in the rax:roles attribute currently must upper case. Any other permutation of the value causes a similar stacktrace.

@RackerWilliams RackerWilliams added this to the 2.6.1 milestone Feb 20, 2018
@RackerWilliams
Copy link
Contributor

Reproduced the bug. Good job finding this, out of all the possible scenarios (there are 7) you found the one case where this happens: When setting multiple rules for the same repeating header: in the examples above you are saying you are saying the repeating (multi-value) header X-TENANT must be an int or a boolean. If the header were not repeating, or you stated the header was only one type (int for example), or the parameter wasn't a header, etc, you wouldn't hit this bug.

A fix is on its way.

Note that there's a bit of an ambiguity here because header names are not case sensitive. What should the parameter match if you specify the same header with a parameter written with two different cases??

<param name="x-tenant-id"
                               style="header"
                               required="true"
                               type="xsd:int"
                               repeating="true"
                               rax:isTenant="true"/>
<param name="x-tENANT-iD"
                               style="header"
                               required="true"
                               type="xsd:boolean"
                               repeating="true"
                               rax:isTenant="true"/>

Keep in mind that those two parameters actually turn into a single header check if optimizations are enabled -- which they are by default. Other than disabling all optimizations in order to treat x-tenant-id and `x-tENANT-iD' as separate headers -- which doesn't make sense: I'm making up the following rule:

In cases where header parameter names differ by case, api-checker will try to match parameters based on the first parameter it sees -- in this case it'll try to match x-tenant-id, however the behavior may vary based on how you configure the validator, so there's no guarantee that this will always work. In fact, if optimizations are disabled then the parameter name must match cases in all instances. The recommendation is that in these cases the parameter name always match case exactly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants