Is there a way to dynamically set the endpoints in WSO2 API Manager to something other than the configured production and sandbox URLs? In my case, I want to route based on an incoming header value; resulting in something like:
https://my_dynamically_determined_subdomain.my_static_domain.com
I tried doing this with a custom handler class that writes my desired URL to the "To" header, but that doesn't seem to affect the routing.
Is there another way to accomplish this?
Your approach seems to be good. You can set "To" header dynamically. But you have to use a Default Endpoint, instead of a HTTP Endpoint. Default Endpoint will send the message to the URL found in "To" header. Please modify your inSequence of the API Configuration (found in $AM_HOME/repository/deployment/server/synapse-configs/default/api/your-api.xml) to replace the HTTP endpoint with a Default endpoint, as shown below.
If you want to do this to all of your APIs, then you can edit velocity_templates.xml so that all the APIs will be published with default endpoints automatically. Please refer this doc for more details on this. It is worth to have a look at this blog post which is discussing a similar pattern what you are trying to do.
Related
I'm using AWS API Gateway to create an api.
I have the following path for an API: /users/{id}
Is there a way to validate the existence of id in the API request made and maybe its type in API Gateway before it reaches the Lambda integration? I understand API Gateway supports validating request body, query params and headers, but I can't see any option for path parameters, does API Gateway not support that?
I'm going through the documentation and I can't seem to find something clear on that.
API Gateway can check if a path parameter exists or not. It can check if path includes any "id", but it cannot for example check what is it’s regex pattern. Such validation should be made on a client side. Either the API Gateway path follows the defined pattern, in which case it can route you to an appropriate resource, or not. It can however ensure that request parameters are present and non-blank.
The AWS documentation states that API Gateway can perform the basic validation:
API Gateway can perform the basic validation. This enables you, the
API developer, to focus on app-specific deep validation in the
backend. For the basic validation, API Gateway verifies either or both of the following conditions:
The required request parameters in the URI, query string, and headers of an incoming request are included and non-blank.
The applicable request payload adheres to the configured JSON schema request model of the method.
To enable basic validation, you specify validation rules in a request validator, add the validator to the API's map of request validators, and assign the validator to individual API methods.
Note that comparison with JSON schema request model refers to the request payload, and not to request parameters. In the documentation you can find guidance on how to enable request validation in API Gateway:
by importing OpenAPI
definition
using the API Gateway REST
API
using AWS
console
Also, follow this blog post which explains how to set up request parameters validation. Mind however, that the basic validation ensures that the request parameters are present and non-blank. More advanced validation, like checking regex pattern or type, is not possible to my knowledge.
Can I add multiple endpoints to 1 API in WSO2 Api Manager?
As far as I know I have to create a context and a version. The background is that I just want to make a request like https://api.manager.com/rest/1.0/userList or https://api.manager.com/rest/1.0/tasks.
The userList REST-Controller is implemented on backend A and tasks REST-Controller is implemented in backend B. (A and B are separate web applications)
As far as I know I have to create in my API Manager two APIs with different context values.
The API Manager application would simply subscribe both APIs.
But this would mean that I have to change my requests on the javascript side. This is in my opinion not good because I dont want my javascript application to care about the context. I want that the API Manager delegates to the correct backend automatically. Is this possible? What is best practise?
You can have multiple endpoints per API using Dynamic Endpoint Feature. When creating the API you need to set the Endpoint Type as "Dynamic Endpoint" and upload a mediation in-sequence that sets the "To" header. Within the sequence you can specify your logic to route to the correct endpoint (setting the correct "To" header) according to the request path. Please read [1] for more information.
[1] http://blog.lakmali.com/2016/08/dynamic-endpoints-in-wso2-api-manager.html
I have created an API Key and added it to my functions. I have then deployed the api and tested it but still get:
"message": "Forbidden"
How do I pass the api key with my JSON request as I have been using "x-api-key": "theKey"?
The x-api-key parameter is passed as a HTTP header parameter (i.e. it is not added to the JSON body). How you pass HTTP headers depend on the HTTP client you use.
For example, if you use curl and assuming that you POST the JSON payload, a request would look something like (where you replace [api-id] with the actual id and [region] with the AWS region of your API):
$ curl -X POST -H "x-api-key: theKey" -H "Content-Type: application/json" -d '{"key":"val"}' https://[api-id].execute-api.[region].amazonaws.com
I had to add an API Usage plan, and then link the plan to the API stage.
Seems like this is the only way to link the key to the API, not sure if this is a recent change on AWS.
If you set 'API Key Required' option to true, please check below.
you have to pass 'x-api-key' HTTP Header Parameter to API Gateway.
The API Key had to be created.
In addition, you need to check a Usage Plan for the API Key on API Gateway Console.
If you set 'API' key required to true, you need to pass the api key as header.
API Key is passed as header field 'x-api-key'. Even after adding this field in header, this issue may occur. In that case, please validate below points
Do you have a Usage Plan? if not need to create one.
Link you API with Usage Plan. For that add a stage, it will link your API
Do you have API Key? if not you need to create an API Key and enable it.
Add the Usage Plan which is linked with your API to this API Key. For that, add Usage Plan.
I hope you are not missing to link the API key with the API
I was able to get a successful response from Lambda using below configuration in Postman native app -
Under authorization tab (For some reason this didn't work when i passed the same parameters under header)
Key : x-api-key
Value : your-api-key-value
Add to : Header
I don't have enough reputation to set this as a comment, But I was finally able to find the document specifying that 'x-api-key' belongs in the header for API Gateway calls that come from outside clients (like postman, swagger, etc.) in the AWS Documentation.
The relevant part:
To use header-sourced API keys:
Create an API with desired API methods. And deploy the API to a
stage.
Create a new usage plan or choose an existing one. Add the deployed
API stage to the usage plan. Attach an API key to the usage plan or
choose an existing API key in the plan. Note the chosen API key
value.
Set up API methods to require an API key.
Redeploy the API to the same stage. If you deploy the API to a new
stage, make sure to update the usage plan to attach the new API
stage.
The client can now call the API methods while supplying the x-api-key
header with the chosen API key as the header value.
Choose an API key source
For Private API Gateways accessed through public DNS, we need to pass additional header of 'x-apigw-api-id' with the api id along with 'x-api-key' if configured.
curl -v https://{vpce-id}.execute-api.{region}.vpce.amazonaws.com/test -H 'x-apigw-api-id:{api-id}'
Its documented below,
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-api-test-invoke-url.html#w20aac13c16c28c11
Here a good resource explaining different reasons why we could be getting a Forbidden. The two most important are the request URL and the x-api-key header:
https://{api_id}.execute-api.{region}.amazonaws.com/{stage_name}/{resource_name}
Missing stage name will give you 403 for ex. Maybe for security reasons the response is not revealing an issue with the stage name, and thus you get a generic Forbidden.
I faced the same problem today. I had already mapped the API key to the usage plan (which was linked to the api gateway stage). I was also passing the api key in header correctly.
When none of these solutions work, do remember to check if your API is linked to WAF policy with only a certain ip-addresses permitted. Apparently, my IP address had changed today. So, WAF was blocking me. That can be an additional reason to get {"message": "Forbidden"} error.
We're implementing WSO2-AM to handle access to some internal APIs from our Moodle LMS we wish to expose to the internet.
I am configuring the access to this LMS via WSO2 but I've run into an issue I can't resolve.
I realise WSO2 documentation is extensive, but I'be not been able to actually find a specific instance of this configuration.
Background: Moodle itself has implemented its APIs in a very non-standard manner. They call them REST, but they are not truly restful. Some of the parameters, such as a users token, are passed in the URL query string rather than using headers in the body of the query itself.
To start with, I have two APIs configured in WSO2, one to request a user token from Moodle (Moodle requires this to permit access to the API for a specific user) and another to get the users enrolled course list.
The first request to get the user token from Moodle via WSO2 proceeds as expected. I pass in the username/password/service parameters via the header as you would expect (so that they are encrypted over HTTPS) to WSO2, which it pushes to Moodle, as a POST. The response from Moodle via WSO2 is as expected, a JSON payload containing a token which my client then parses to use in subsequent requests.
The next request is then calling a more useful service in Moodle, to get a users enrolled courses. There are two issues noted here which I'm unsure how to resolve.
The problems: Moodle expects GET or POST parameters for the call to the web-service. When I'm using GET, which is handy for testing, the parameters passed from the client to WSO2 are either wrong (in the case of the 'userid') or missing (in the case of the wstoken field, which is in the post body).
In API publisher I have the API in WSO2 configured for POST with a URL pattern of {version}/courses/{userid}
The API definition is configured as below:
API Endpoint configuration is:
URL: http://(moodleurl)/webservice/rest/server.php?wstoken={uri.var.wstoken}&wsfunction=core_enrol_get_users_courses&moodlewsrestformat=json&userid={uri.var.userid}
GET URL as received by Apache hosting Moodle is:
xx.xx.xx.xx - - [09/Aug/2016:10:36:03 +0930] "POST /webservice/rest/server.php?wstoken=&wsfunction=core_enrol_get_users_courses&moodlewsrestformat=json&userid=6/6 HTTP/1.1" 200 270
So, the two issues are the missing 'wstoken' parameter (which is in the post body provided to WSO2, and the 'userid' being doubled up with a slash between the items.
I have run the client via a proxy and the data appears to be sent correctly to WSO2:
So I'm wondering what I can do about these problems:
Is there a different URL parameter I can use to correctly include a posted body param in the URL out to the service API address?
Is there some specific configuration problem I've made that's causing the userid parameter to break in this manner?
The posted parameters from the client do appear to be included in the post to Moodle by WSO2; so it is likely they can be stripped from the URL and simply included in the post body to Moodle by WSO2, meaning that it's likely only the issue with the userid parameter that needs to be resolved to allow this to work - unfortunately I'm not sure how to place a proxy between WSO2 and Moodle itself to validate the parameters that are posted to the API, short of using Wireshark.
The 'userid' being doubled up with a slash between the items because the URI template of the API's resource is automatically appended to the end of the HTTP endpoint at runtime. For an example in your case you defined the endpoint url as:
http://(moodleurl)/webservice/rest/server.php?wstoken={uri.var.wstoken}&wsfunction=core_enrol_get_users_courses&moodlewsrestformat=json&userid={uri.var.userid}
Then url pattern (/{userid}) appends to the endpoint url by default. To overcome this issue you can use the following mediator setting to remove the URL postfix from the backend endpoint:
<property name="REST_URL_POSTFIX" scope="axis2" action="remove"/>
For more on this please refer the link given in [1].
You can read the variables in the resources (urls) during mediation runtime using property values with the "uri.var." prefix. For example, in your case HTTP endpoint gets the wstoken and userid as the uri variables. But wstoken contains in the body section of the request. Therefore you cannot add it by introducing wstoken={uri.var.wstoken} as a query paramter to the endpoint. One way that you can overcome this issue is by defining wstoken as a query parameter by changing the parameter Type to query. The other way is you can define it in the header of the incoming request.
[1]. https://docs.wso2.com/display/AM190/Map+the+Parameters+of+your+Backend+URLs+with+the+API+Publisher+URLs
Pretty self explanatory title. I'm using API Gateway in AWS, requiring an API key to access a backend written in Django (not using lambda). I need to know how to access the API key used in the request to keep track of who did what at the app level.
You can use mapping templates and get the API Key from the $context variable, it’s the apiKey property inside the identity object: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference
Create a mapping template for your requests and include the property in it. For example, if you wanted to include the entire request body + the API Key you would do this:
{
"body": $input.json('$'),
"apiKey": "$context.identity.apiKey"
}
Depending on how your backend application is built, you could send the API key to your application in a HTTP parameter (path, query string, or header) or in the request body. Please have a read through the docs on how to move data between the two systems.
Thanks,
Ryan
Here is how I finally made it work. At the top or bottom of the template, include this line.
#set($context.requestOverride.header.x-api-key = $context.identity.apiKey)
When your backend receives this request, the api key will be in the header x-api-key.
Here is a basic mapping template that just forwards the (json) body and the header.
$input.json("$")
#set($context.requestOverride.header.x-api-key = $context.identity.apiKey)
API Gateway uses the X-API-Key header, so I like for my backend to also use that. That way I can use the same testing commands with only the URL being different.