ClientId on GenerateAccessToken not working and no definition for ClientSecret - apigee

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.

Related

Ignore case Request HTTP Query Parameters

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')

as for a flex http request, how to set the header attributes when special characters are contained

My task is to call some api in flex, and I use HTTPService to send a request to the server. It must be authenticated if I want to retrieve any data from the server. The authentication information are put in the headers of a request. Now the problem is if the attribute contains some special characters (a colon for instance), then the request won't work, which means the authentication failed. Actually this attribute is then neglected. Is some encoding needed when setting those attributes?
// this attribute will be negelected, for colons are contained in it.
http.headers["X-wsse"] = "Created=\"2013-01-02T11:29:13+01:00\"";
Colon isn't special in HTTP header field values.
You may want to check the documentation of "X-wsse" (whatever that is).

Parsing a HTTP Basic authentication with an email containing a colon character ( ':' )

I'm using the Authorization header with the Basic type for authentication.
I'm following the HTTP Basic authentication specifications which states that the credentials should follow this form -> userIdentifier:password encoded in base64
We are using an email as the user identifier and according to the email format specification, the colon(':') character is permitted.
The colon(':') is also a valid character in the password.
Knowing this, I'm looking for a creative way to parse the credentials part of the header that uses a colon(':') as the separator between userID and password.
In this case it's simple -> francis#gmail.com:myPassword
This is where it gets complicated -> francis#gmail.com:80:myPasswordWith:Inside
francis#gmail.com:80 is a valid email according to the email format specification even though this is not used very often. So where do I know where to split ?
We have made the decision not to accept an email containing a ':'. But we want to notify the user that his email is not valid, how can we ensure that we are splitting the string at the right place ?
Hope I asked my question in a clear manner, don't hesitate to ask for more details
Thank you
Don’t notify the user that the email is invalid. Split according to the RFC 2617 rules (everything after the first colon is the password), then try to authenticate, fail, and return a generic “authentication failure” message.
A situation where john#example.org:80 has password secret and john#example.org has password 80:secret at the same time, seems unrealistic.
If you require your users to register, you probably do it with some other mechanism (forms?) where you can easily separate the username and tell that it is invalid.

Custom HTTP Authorization Header

I was wondering if it's acceptable to put custom data in an HTTP authorization header. We're designing a RESTful API and we may need a way to specify a custom method of authorization. As an example, let's call it FIRE-TOKEN authentication.
Would something like this be valid and allowed according to the spec: Authorization: FIRE-TOKEN 0PN5J17HBGZHT7JJ3X82:frJIUN8DYpKDtOLCwo//yllqDzg=
The first part of the second string (before the ':') is the API key, the second part is a hash of query string.
The format defined in RFC2617 is credentials = auth-scheme #auth-param. So, in agreeing with fumanchu, I think the corrected authorization scheme would look like
Authorization: FIRE-TOKEN apikey="0PN5J17HBGZHT7JJ3X82", hash="frJIUN8DYpKDtOLCwo//yllqDzg="
Where FIRE-TOKEN is the scheme and the two key-value pairs are the auth parameters. Though I believe the quotes are optional (from Apendix B of p7-auth-19)...
auth-param = token BWS "=" BWS ( token / quoted-string )
I believe this fits the latest standards, is already in use (see below), and provides a key-value format for simple extension (if you need additional parameters).
Some examples of this auth-param syntax can be seen here...
https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-p7-auth-19#section-4.4
https://developers.google.com/youtube/2.0/developers_guide_protocol_clientlogin
https://developers.google.com/accounts/docs/AuthSub#WorkingAuthSub
Put it in a separate, custom header.
Overloading the standard HTTP headers is probably going to cause more confusion than it's worth, and will violate the principle of least surprise. It might also lead to interoperability problems for your API client programmers who want to use off-the-shelf tool kits that can only deal with the standard form of typical HTTP headers (such as Authorization).
No, that is not a valid production according to the "credentials" definition in RFC 2617. You give a valid auth-scheme, but auth-param values must be of the form token "=" ( token | quoted-string ) (see section 1.2), and your example doesn't use "=" that way.
Old question I know, but for the curious:
Believe it or not, this issue was solved ~2 decades ago with HTTP BASIC, which passes the value as base64 encoded username:password. (See http://en.wikipedia.org/wiki/Basic_access_authentication#Client_side)
You could do the same, so that the example above would become:
Authorization: FIRE-TOKEN MFBONUoxN0hCR1pIVDdKSjNYODI6ZnJKSVVOOERZcEtEdE9MQ3dvLy95bGxxRHpnPQ==

How to set the userAgent in a functional Test?

I could not find any matching method in sfTestFunctional or sfBrowser to set the UserAgent string. Maybe it's not possible because it goes through php-cli?
$browser->setHttpHeader('User-Agent', 'some custom string')->get('your url')
This sets the user agent for the next request, so maybe you want to extend the sfBrowser object to provide the HTTP headers on every request

Resources