Forum Discussion

JKelsey's avatar
JKelsey
Occasional Contributor
14 years ago

[Res] How to set Authorization header value dynamically

I'm testing a REST web service. I have a soapUI project with hundreds of test steps and dozens of test cases. We're about to add support for authentication. Once that is in, each of my REST requests needs to send an Authorization header where the value is calculated based on a string made up of the URI of the request and a timestamp that is then encrypted.

I'm looking for ideas on how I can add the authorization header with the least amount of pain.

I suspect I need to modify each of the test steps with a REST request to at least add the Authorization header.

Once each test step has the Authorization header, how do I populate it with the correct value each time the test step runs?

I thought about having a DataGen step at the start of each testcase, with a script property in READ mode that calculates the header value and encrypts it. Then I can use property expansion in each REST request test step that reads the header value. Will that work? If so, how does the DataGen script get the URI for the test step that is trying to read the header value?

In pseudo code I thought my DataGen script would look something like this
step = figure out which step is running (how??)
uri = get the request uri for the test step (how?? what about steps that don't have a uri, like property transfers??)
timestamp = now
rawHeader = uri + now // concatenate the uri and the timestamp together
authorization = encrypt (rawHeader)


Even better would be if I could have a global script somewhere that can be called by each REST test step to get the authorization value for that request. I'm not sure if that is possible.

Thanks.
  • SmartBear_Suppo's avatar
    SmartBear_Suppo
    SmartBear Alumni (Retired)
    Hi!

    you could define a script in the script library to calculate the header, and then set the header value to

    ${=your.package.HeaderCalculator.calcHeader(context)}

    the context will be the TestRunContext for the containing TestCase, which gives access to anything you might need, check the javadoc or ask for specifics..

    Does that help?

    regards!

    /Ole
    eviware.com
  • JKelsey's avatar
    JKelsey
    Occasional Contributor
    Thanks, that sounds promising. I tried doing what you suggested, using code copied from various samples I found, but I'm getting an error when the script runs.

    Here is what I tried, just to see if I could get a value back from my script library class.

    * created a file AuthorizationHeader.groovy in the bin/scripts/soapui/utils folder

    package soapui.utils

    import com.eviware.soapui.model.testsuite.TestRunner
    import com.eviware.soapui.model.testsuite.TestRunContext


    public class AuthorizationHeader
    {
    public calcHeader( TestRunContext runContext )
    {
    def testStep = testRunner.testCase.testSteps[testStepName]
    result = testStep
    }
    }


    * created a header called "Test" in one of my REST request test steps, with value of:
    ${=soapui.utils.AuthorizationHeader.calcHeader(context)}

    When I run the test step, I get this error:
    Thu Mar 03 12:12:07 PST 2011:ERROR:Error evaluating script
    groovy.lang.MissingMethodException: No signature of method: static soapui.utils.AuthorizationHeader.calcHeader() is applicable for argument types: (com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext) values: [[requestUri:http://webserver, postMethod:com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedGetMethod@14fc5ad, #HTTP_STATE:[ | | ], httpMethod:com.eviware.soapui.impl.wsdl.submit.transports.http.support.methods.ExtendedGetMethod@14fc5ad, httpClient:org.apache.commons.httpclient.HttpClient@9c7d4, requestTransport:com.eviware.soapui.impl.wsdl.submit.transports.http.HttpClientRequestTransport@1e64a8, RunCount:0, wsdlRequest:com.eviware.soapui.impl.wsdl.teststeps.RestTestRequest@1627fd1, httpResponseProperties:[page:, search:Id lt 10, orderby:Id desc, size:], hostConfiguration:HostConfiguration[], ThreadIndex:0, requestContent:]]
    Possible solutions: calcHeader(com.eviware.soapui.model.testsuite.TestRunContext)
    at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1357)
    at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1343)
    at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:50)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:124)
    at Script6.run(Script6.groovy:1)
    at com.eviware.soapui.support.scripting.groovy.SoapUIGroovyScriptEngine.run(SoapUIGroovyScriptEngine.java:96)
    at com.eviware.soapui.support.scripting.groovy.SoapUIProGroovyScriptEngineFactory$SoapUIProGroovyScriptEngine.run(SourceFile:88)
    at com.eviware.soapui.model.propertyexpansion.resolvers.EvalPropertyResolver.doEval(EvalPropertyResolver.java:186)
    at com.eviware.soapui.model.propertyexpansion.resolvers.EvalPropertyResolver.resolveProperty(EvalPropertyResolver.java:165)
    at com.eviware.soapui.model.propertyexpansion.PropertyExpander.expand(PropertyExpander.java:166)
    at com.eviware.soapui.model.propertyexpansion.PropertyExpander.expandProperties(PropertyExpander.java:94)
    at com.eviware.soapui.impl.wsdl.submit.transports.http.HttpClientRequestTransport.sendRequest(HttpClientRequestTransport.java:154)
    at com.eviware.soapui.impl.wsdl.WsdlSubmit.run(WsdlSubmit.java:123)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)


    Question #1:
    How do I fix the error?

    I copied code from a SOAP sample, but my request is a REST request. I suspect I'm importing the wrong thing and/or referring to it incorrectly in the line that defines calcHeader.

    I tried taking the suggestion in the "Possible solutions" message by changing my test step header value to pass com.eviware.soapui.model.testsuite.TestRunContext instead of context, but that resulted in multiple compliation errors. The beginning of the error looked like this:
    General error during conversion: startup failed:
    soapui.utils.AuthorizationHeader: 9: unexpected token: ) @ line 9, column 71.
    odel.testsuite.TestRunContext )



    Question #2:
    The error seems to show what is in the context that I can use. Unfortunately, I don't see what I need. What I need is the full URI to the REST resource, including any parameters. In the RAW request tab, it's on this line:
    GET http://webserver/virtualdirectory/Order.svc/?search=Id%20lt%2010&orderby=Id%20desc HTTP/1.1


    I need this part:
    http://webserver/virtualdirectory/Order.svc/?search=Id%20lt%2010&orderby=Id%20desc


    How to I get what I need from the test context once I figure out how to set up my class correctly?

    Thanks.
  • SmartBear_Suppo's avatar
    SmartBear_Suppo
    SmartBear Alumni (Retired)
    Hi,

    hmm.. I think you will need to make the method static to be able to call it without first instantiating its containing class.

    But that won't help you in 2, which isn't possible at this level of processing, you will have to create a custom RequestFilter.filterRequest handler instead from which you can get this information and update the header accordingly;

    1) Open the project window and go to the Events tab
    2) Add a handler for the RequestFilter.filterRequest event, and set its content to something in the line of:

    // get method so we can get the complete URI
    def method = context.getProperty( "httpMethod" )

    // log the complete URI
    log.info( method.URI.toString() )

    // set an HTTP header
    method.setRequestHeader( "test", "some value" )


    Does that help?

    regards,

    /Ole
    eviware.com
  • JKelsey's avatar
    JKelsey
    Occasional Contributor
    Thank you! The filter handler is now adding the headers. That's exactly what I wanted.