Ignore case Request HTTP Query Parameters - apigee

We wanted to be able to ignore case in our http parameter name for apikey--i.e., we want to accept ApiKey, APIKEY, and Apikey (and all other permutations) to be accepted...but it seems that request.queryparam.apikey will only accept "apikey" as HTTP parameter.
We thought of using ExtractVariable policy with ignoreCase attribute (then assign it to another variable qp.api_key) but it doesn't seem to work (or we don't fully understand what #ignoreCase does)..i.e., qp.api_key is only assigned if we pass apikey param (and not ApiKey, apiKey, etc).
<QueryParam name="apikey">
<Pattern ignoreCase="true">{api_key}</Pattern>
<VariablePrefix>qp</VariablePrefix>
</QueryParam>
how do we achieve case-insensitivity for the apikey HTTP get param?

The ignoreCase attribute applies to the Pattern - not the name.
Your pattern does not include anything other than the variable you are receiving, so in your case it does nothing.
But, a pattern can contain surrounding characters that comprise a pattern that you expect, as in:
<QueryParam name="apikey">
<Pattern ignoreCase="true">abc{api_key}</Pattern>
<VariablePrefix>qp</VariablePrefix>
</QueryParam>
In this case, when your API proxy is invoked with ?apikey=abc123 or ?apikey=aBc123, apikey will be set to 123.

If API Key is the only parameter in the querystring - following would work
<ExtractVariables async="false" continueOnError="false" enabled="true" name="extractapikey">
<DisplayName>ExtractApiKey</DisplayName>
<Variable name="request.querystring">
<Pattern ignoreCase="true">apikey={api_key}</Pattern>
</Variable>
</ExtractVariables>

+1 for Randy's suggestion to choose the reasonable spellings of apikey and putting all of those in a single ExtractVariables policy:
apikey
APIkey
apiKey
ApiKey
APIKey
APIKEY
If you really wanted to handle all possible spellings, another solution would be to use a JavaScript callout. You can access the variable message.queryparam.names, which is a collection of all query parameter names, or message.querystring, which is the query string itself. Loop through the names or parse the query string and once you find a parameter name that is a case-insensitive match, grab the corresponding message.queryparam.{queryparam_name} variable. See the Apigee docs for the possible variables you can access.

I created a Python Script Policy:
import re
qs = flow.getVariable('request.querystring')
p = re.compile(r".*apikey=(\w+).*", re.IGNORECASE)
m = p.match(qs)
if m is not None:
flow.setVariable('qp.api_key', m.group(1))
in this case, it gets assigned to qp.api_key and use that ref for the VerifyApiKey policy.
i think this should be a standard option to extract flow variables (i.e., case-insensitive param names) instead of going through extra policies to do the same relatively basic thing.
thanks for the quick response and ideas, guys.

I'd suggest lowercasing all parameters, so code can use a single standard naming convention. Code below can be executed within JavaScript policy to set variables that can be used later on in any subsequent policies. These variables will then become the variables to be referenced from any other places.
function setLowerCaseQueryParams(){
var qpnames = request.queryParams;
for(var key in qpnames){
context.setVariable("queryparams." + key.toLowerCase(), request.queryParams[key]);
}
}
setLowerCaseQueryParams();
With this function you can always send any combination of characters. e.g AbCdEFGHijKl=value, abcdEfghijkl=value or ABCDEFGHIJKL=value and it will always be accessed as:
var queryparamval = context.getVariable('queryparams.abcdefghijkl')

Related

BizTalk WCF-WebHttp URI mapping problem with escaped variable

I am trying to use BizTak WCF-WebHttp adapter to send to Service Desk Plus CMDB API using Variable Mapping.
When trying using the browser, it works fine. Service Desk Plus CMDB API requires an URI like (strictly shortened for readability):
http://host.com/api/cmdb/ci?OPERATION_NAME=read&TECHNICIAN_KEY=Mykey&format=XML&INPUT_DATA=<?xml version='1.0'?>
<API>
<name>email#host.com</name>
</API>
I have used the URI http://host.com/api/cmdb/ci and URL Mapping.
<BtsHttpUrlMapping>
<Operation Url="?OPERATION_NAME=read&TECHNICIAN_KEY=MyKey&format=XML&INPUT_DATA=<?xml version=&apos;1.0&apos;?>
<API>
<name>email#host.com</name>
</API>"/>
</BtsHttpUrlMapping>
This works fine, but I need a more dynamic approach. I tried using Variable Mapping, so I replaced the hard coded email address with a variable.
<BtsHttpUrlMapping>
<Operation Url="?OPERATION_NAME=read&TECHNICIAN_KEY=MyKey&format=XML&INPUT_DATA=<?xml version=&apos;1.0&apos;?>
<API>
<name>{email}</name>
</API>"/>
</BtsHttpUrlMapping>
Trying to save the URL Mapping with the variable I get an error.
WCF-WebHttp Transport Properties
Error saving properties.
(System.InvalidOperationException) The UriTemplate
?OPERATION_NAME=read&TECHNICIAN_KEY=MyKey&format=XML&INPUT_DATA=<?xml version='1.0'?><API><name>{email}</name></API>
is not valid; each portion of the query string must be of the form 'name=value', when value cannot be a compound segment. See the documentation for UriTemplate for more details.
If I try a variable that is not within the escaped XML string, like with the key, then it works fine.
<BtsHttpUrlMapping>
<Operation Url="?OPERATION_NAME=read&TECHNICIAN_KEY={key}&format=XML&INPUT_DATA=<?xml version=&apos;1.0&apos;?>
<API>
<value>email#host.com</value>
</API>"/>
</BtsHttpUrlMapping>
My intention is to be able to use a variable within the escaped XML string. If that is not possible; I will have to turn to a dynamic adapter and Create the URI and URL mapping in an orchestration.
Did u understand why it said each portion of the query string must be of the form 'name=value? There are just a few ways to make UriTemplates work.
See how a UriTemplate works here. Here is an example that is valid:
weather/{state}/{city}?forecast={day}
So in your case you should make everything after INPUT_DATA= a variable. Which means the whole escaped XML string you were talking about.

Servlet stripping parameter values because of # character

My URL is http://175.24.2.166/download?a=TOP#0;ONE=1;TWO2.
How should I encode the parameter so that when I print the parameter in the Servlet, I get the value in its entirety? Currently when I print the value by using request.getParameter("a") I get the output as TOP instead of TOP#0;ONE=1;TWO2.
You should encode it like this http://175.24.2.166/download?a=TOP%230%3BONE%3D1%3BTWO2 . There are a lot of the encoders in Java, you can try to use URLEncoder or some online encoders for experements
This is known as the "fragment identifier".
as mentioned in wiki
The fragment identifier introduced by a hash mark # is the optional last part of a URL for a document. It is typically used to identify a portion of that document.
the part after the # is info for the client. Put everything your client needs here.
you need to encode your query string.
you can use encodeURIComponent() function in JavaScript encodes a URI component.This function encodes special characters.

ClientId on GenerateAccessToken not working and no definition for ClientSecret

I'm trying to define specific ClientId and ClientSecret variables for policy OauthV2 for GenerateAccessToken but the ClientId it doesn't seem to take effect and the ClientSecret doesnt seem to event exist as a possibility. what are my configuration options in here?
Optional Answer
extract the variables and then reassign them in the right place expected by the policy.
Your optional answer is mostly correct. After extracting the variables, you could store them in a Key-Value Map and then look up the info from the Map and use it.
By default the OAuthV2 policy expects to see the client ID and client secret separated by a colon and encoded as a base64 string in the Authorization header, as in:
Authorization: Basic
Alternately you can specify those values anywhere in your request (headers, query params, payload) and provide them to the OAuthV2 policy by creating an Authorization header using the BasicAuthentication policy (http://apigee.com/docs/api-services/reference/basic-authentication-policy) and associating it with the request prior to invoking the OAuthV2 policy. In the BasicAuthentication policy specify the client ID in the "User" element and the client secret in the "Password" element.

URL parameters and backbone routing

Backbone.js maintains routing information in a URL after the hash mark, e.g.:
http://localhost:3000#page/hardware/table/?action=details&actionTargetId=5&actionTargetName=10.3.177.185&actionTarget=host
Even though the routing information is in the format ?p1=v1&p2=v2&p3=v3, this portion is not technically part of the url query string since it comes after the hash mark.
My question is if I add an actual query string to our app's urls like this:
http://localhost:3000?newparam=newvalue#page/hardware/table/?action=details&actionTargetId=5&actionTargetName=10.3.177.185&actionTarget=host
is there any possibility of the "newparam" url parameter interfering with the backbone portion?
the problem is your not actually creating a legit query string. your mixing your route with your parameters.
your example is formatted as:
domain ? param # route ? other params
as soon as a questionmark appears in a url everything after it is interpreted as a query string. (in this case) even your route.
personally i suggest using the html5 pushstate.
Backbone.history.start({pushState: true})
this will give you clean(er) urls
http://localhost:3000/page/hardware/table/?newparam=newvalue&action=details&actionTargetId=5&actionTargetName=10.3.177.185&actionTarget=host
that will help your routes to not interfere with your parameters.

How do we send data via GET method?

I am creating a HTTPS connection and setting the request property as GET:
_httpsConnection = (HttpsConnection) Connector.open(URL, Connector.READ_WRITE);
_httpsConnection.setRequestMethod(HttpsConnection.GET);
But how do I send the GET parameters?
Do I set the request property like this:
_httpsConnection.setRequestProperty("method", "session.getToken");
_httpsConnection.setRequestProperty("developerKey", "value");
_httpsConnection.setRequestProperty("clientID", "value");
or do I have to write to the output stream of the connection?
or do I need to send the Parameter/Values by appending it to the url?
Calling Connection.setRequestProperty() will set the request header, which probably isn't what you want to do in this case (if you ask me I think calling it setRequestHeader would have been a better choice). Some proxies may strip off or rewrite the name of non-standard headers, so you're better off sticking to the convention of passing data in the GET URL via URL parameters.
The best way to do this on a BlackBerry is to use the URLEncodedPostData class to properly encode your URL parameters:
URLEncodedPostData data = new URLEncodedPostData("UTF-8", false);
data.append("method", "session.getToken");
data.append("developerKey", "value");
data.append("clientID", "value");
url = url + "?" + data.toString();
HTTP GET send data parameters as key/value pairs encoded within URL, just like:
GET /example.html // without parameters
GET /example.html?Id= 1 // with one basic parameter
GET /example.html?Id=1&Name=John%20Doo // with two parameters, second encoded
Note follow rules for character separators:
? - split URL in two pieces: adddress to left and paremeters to right
& - must be used to separate on parameter from another
You must know your platform specific native string encode function. Javascript uses escape, C# uses HttpUtility.UrlEncode
Yep, headers and properties are pretty much all you can send in a GET. Also, you're limited to a certain number of characters, which is browser dependent - I seem to recall about 1024 or 2000, typically.

Resources