In Azure API Management, I'm trying to modify the CORS policy for a single route within the API. The problem I'm having is that I can't figure out how to modify the BASE policy. Azure seems to simply override it with the new policy.
Simple BASE policy:
<policies>
<inbound>
<cross-domain>
<cross-domain-policy>
<allow-http-request-headers-from domain="*" headers="*" />
</cross-domain-policy>
</cross-domain>
<cors>
<allowed-origins>
<origin>*</origin>
</allowed-origins>
<allowed-methods>
<method>*</method>
</allowed-methods>
<allowed-headers>
<header>*</header>
</allowed-headers>
</cors>
</inbound>
<backend>
<forward-request />
</backend>
<outbound>
</outbound>
</policies>
In the specific route, I want to modify the <cors> section to include one more policy, like this:
<policies>
<inbound>
<base />
<cors>
<expose-headers>
<header>Content-Disposition</header>
</expose-headers>
</cors>
</inbound>
</policies>
However, Azure wants to override the base CORS policy with this one. I can't find anything in the documentation about how to just modify/merge a policy rather than wholesale replacing it.
So, how would I inherit the base policy but just add this one additional <expose-headers> policy?
That is not possible at the moment. They way policies work is once request scope is defined (product, API and operation are matched) the policy is constructed by replacing all tags with a policy from the upper level. Resulting effective policy is just a flat list of statements that are executed one after another. In that sense you have no control over parent policy on lower level.
But you can always insert things before parent policy is executed. For that just place another fully specified CORS policy before tag and in resulting policy it will be executed first.
Having multiple CORS policies per effective policy is fine, they'll be executed one after another and first one that is capable of handling CORS call (origin, method, headers match) will take action.
Related
I am trying to achieve that, when I call an APIM Endpoint based on the request headers It should different endpoint. for e.g when user call https://test.azure-api.net/testsvc-dev/api/test APIM should be able to send the request to https://testappv1:80/test or https://testappv2:80. right now I can see in the serviceURL, I can add only one. Is there any policy that I can use to do these kind of operations.
little more context: I am trying to access two different version of API on a single call. Instead of caller choosing which one to call,I am trying to make the APIM to decide based on the user.
You are probably looking for the set-backend-service policy.
Here an example from the Microsoft docs that changes the backend service based on a query parameter:
<policies>
<inbound>
<choose>
<when condition="#(context.Request.Url.Query.GetValueOrDefault("version") == "2013-05")">
<set-backend-service base-url="http://contoso.com/api/8.2/" />
</when>
<when condition="#(context.Request.Url.Query.GetValueOrDefault("version") == "2014-03")">
<set-backend-service base-url="http://contoso.com/api/9.1/" />
</when>
</choose>
<base />
</inbound>
<outbound>
<base />
</outbound>
</policies>
Certainly, you could adopt the sample and query for the desired headers ;-)
In azure API Management how to setup the 405 (Method not allowed) policy. I am using azure API management APIs and adding different policies like jwt validation, IP filtering, rate limit and all. But I couldn't find a way for add the 405 method not allowed in APIM. I want to setup this for each of the methods. That means I want to block the incoming unrecognized method requests from APIM. (eg: Get instead of POST (Throws 405 method not allowed from APIM). Currently APIM passes the wrong method to backend and it returns the 404 from the application. Anyone know how we can block the wrong request from APIM side and returns 405 instead of passing it to backend and returns 404?.
You could use a Control Flow policy along with the Context Variable on the Inbound policy of each Method to intercept any requests that don't match the defined http method and then use a Set Status policy to return a 405. So for a GET method something along the lines of:
<policies>
<inbound>
<choose>
<when condition="#(context.Request.Method.ToString() != "GET")">
<return-response>
<set-status code="405" reason="No Content" />
</return-response>
</when>
</choose>
<base />
</inbound>
... rest of policies
</policies>
If you've got multiple methods with the same path you might need to apply this at the API level rather than the Method level and make the condition equals methods not in use rather than not equal to method in use
To set this at the API level and check against a collection of methods not in use create a policy along the lines of:
<policies>
<inbound>
<choose>
<when condition="#{
ICollection<string> disallowedMethods = new List<string>() { "POST", "PUT" };
return disallowedMethods.Contains(context.Request.Method.ToString());
}">
<return-response>
<set-status code="405" reason="No Content" />
</return-response>
</when>
</choose>
<base />
</inbound>
... rest of policies
</policies>
The http methods not in use in this example are POST and PUT but you can change the list to whatever applies in your use case.
I've create a API populated from a swagger.json file and verified it works in the Test UI. The test UI request succeeds showing the headers passed below.
POST https://apiforqubo.azure-api.net/api/Qubo HTTP/1.1
Host: apiforqubo.azure-api.net
Content-Type: application/json
Ocp-Apim-Subscription-Key: ••••••••••••••••••••••••••••••••
Ocp-Apim-Trace: true
I've added a CORS policy for all operations. This is now updated to reflect the answer below.
The updated policy is:
<policies>
<inbound>
<base />
<cors allow-credentials="true">
<allowed-origins>
<origin>https://apiforqubo.developer.azure-api.net</origin>
</allowed-origins>
<allowed-methods>
<method>POST</method>
<method>GET</method>
<method>PUT</method>
</allowed-methods>
</cors>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
When I try to execute the API from the web page that's generated for the API at: https://apiforqubo.developer.azure-api.net/api-detail, the request fails with the error:
Unable to complete the request
Since the browser initiates the request, it requires Cross-Origin Resource Sharing (CORS) enabled on the server.
What am I missing?
UPDATE: policy statement to reflect specific website as suggested by Vitaliy Kurokhtin in the comments.
Regards,
Rajesh
You've configured it to allow CORS requests only from https://azure-api.net, not from https://apiforqubo.developer.azure-api.net. Either use full URL or wildcard:
<origin>https://*.azure-api.net/</origin>
Please add allowed-headers policy element in your policy in APIM
Is it possible to create a policy that limites request rate over a period for all API instances?
Can the policy below be used for the requirement?
Please note I want the policy to be define in one place (global, that is, "All APIs"), not repeated for every API instance.
<policies>
<inbound>
<base />
<rate-limit calls="20" renewal-period="90" />
</inbound>
<outbound>
<base />
</outbound>
</policies>
Policy sections: inbound
Policy scopes: product
https://learn.microsoft.com/en-us/azure/api-management/api-management-access-restriction-policies#LimitCallRate
yes. You can add this policy inside "ALL APIS" policy section. It will get effect for all the APIs. Its's correct
Is it possible to forward requests to regional API based on a specific JWT claim?
The platform I'm working on has one API per region, and our customers are required to know it in order to build the base request URL - e.g.: https://{region}.service.com
Unfortunately, the only reliable way to try and figure out which regional api to call automatically from Azure APIM (e.g.: calling a single endpoint at https://api.service.com), in our scenario, would be by analyzing a claim that always comes with the bearer token (which we already do at the APIM level.)
Has anybody had the need to do it this way? Thanks in advance!
APIM policy expressions along with "choose" policy allow you to create arbitrary processing logic: https://learn.microsoft.com/en-us/azure/api-management/api-management-policy-expressions.
Access to JWT is available as
context.Request.Headers.GetValueOrDefault("Authorization").AsJwt()
It returns Jwt object (look for it's properties on the same page above).
All this combined with "set-backend-service" policy should be sufficient to do the job.
Vitaly's answer was the key to figuring this one out. Here is the complete answer, in case anybody is looking for the same thing.
<policies>
<inbound>
<!-- Extract Token from Authorization header parameter -->
<set-variable name="token" value="#(context.Request.Headers.GetValueOrDefault("Authorization",string.Empty).Split(' ').Last().AsJwt())" />
<choose>
<when condition="#(context.Variables["token"] != null)">
<set-variable name="api_uri" value="#(((Jwt)context.Variables["token"]).Claims.GetValueOrDefault("api_uri", string.Empty))" />
<choose>
<when condition="#(context.Variables["api_uri"] != string.Empty)">
<set-backend-service base-url="#((string)context.Variables["api_uri"])" />
</when>
<otherwise />
</choose>
</when>
<otherwise />
</choose>
<base />
</inbound>
</policies>