I have an api gateway v1 foo.
This api gateway has a stage bar
I am trying to setup a domain name baz.com to access this stage.
When I create a new domain name with API mapping to foo (stage and path empty), I am able to access my api with https://baz.com/bar/user/get.
However, when I try to access my api with API mapping to foo, stage to bar and path empty, querying https://baz.com/user/get doesn't work (I am getting Could not find matching action for /get and method POST). Even weirder, setting path mapping to a, I am able to query my api : https://baz.com/a/user/get.
I do not understand what I am doing wrong. I tried to set path mapping to / but I get an error : API Gateway V1 doesn't support the slash character (/) in base path mappings. To create a multi-level base path mapping, use API Gateway V2.
With path set to a :
With empty path :
I am completly lost, it turns out my lambda do get call and return a 200 :
Yet it ends up being a 404
The issue was not related to API Gateway but to the library I used, aws-lambda-routing.
There was a bug regarding the use of custom domain name that is documented in the following issue : https://github.com/spring-media/aws-lambda-router/issues/27
A PR was made a year ago and the solution is now to set removeBasePath to false
Related
This is all done using CDK.
I created a REST API and custom domain associated with it via a base path mapping (domain.addBasePathMapping()). That worked fine.
Due to some requirement, I also need to redirect a particular path from another custom domain (I'll call this the old domain) to this api. In theory this should be straightforward - just create a base path mapping from the old domain to the new API.
This is how I tried doing it:
const domain = DomainName.fromDomainNameAttributes(this, 'oldDomain', {
domainName: 'the old custom domain name',
domainNameAliasTarget: 'the "API Gateway domain name" value from the console for that domain',
domainNameAliasHostedZoneId: 'the "Hosted zone ID" value from the console for that domain',
});
new BasePathMapping(this, 'myMapping', {
domainName: domain,
restApi: this.api,
basePath: 'foo',
});
First I created a DomainName object by looking up the old domain, then created a mapping to my new API with some path. Note that I cannot call addBasePathMapping() on the domain name created, as that method returns an IDomainName which doesn't have that method.
When I ran this, it created the base path mapping in the old custom domain, pointing to my new api, correct stage, specified path. Great!
Except it didn't work. Invoking [old domain]/foo/bar (where bar is the resource path in the new API) returned 404.
The strange thing is that when I create that mapping manually via the console, it works perfectly.
Another weird thing is that if I create it via CDK, and then edit it in the console, it starts working. If I then delete it (manually or via CDK) and then create it again via CDK, it continues to work. But of course this isn't a proper solution.
I can only assume that creating it manually performs some extra operation not done via the CDK construct, but as the docs don't say what else may need to be done, I have no idea what.
The solution is to use the CfnApiMapping construct from aws-cdk-lib/aws-apigatewayv2. In fact this is a lot easier as you don't need to get the hosted zone id etc, just pass it some readily available information and it creates a base path mapping that actually works:
new CfnApiMapping(this, 'myMapping', {
apiId: this.api.restApiId,
domainName: 'old custom domain'
stage: this.api.deploymentStage.stageName,
apiMappingKey: 'foo',
});
I should warn that this comes with strange behaviour.
First an overview of my setup:
The old api has the following path on it: [old api]/foo/bar. The old custom domain is mapped straight to the old api with no path, so the old endpoint url is [old custom domain]/foo/bar. The new endpoint is [new custom domain]/bar. In order for the old URL to map to the new api, I need a base path mapping for foo on the old custom domain to point to the new api, so that [old custom domain]/foo/bar will be directed to [new api]/bar. (Note there are no other resources on foo and nothing new will be added, so this is fine.)
So currently calling [old custom domain]/foo/bar invokes the /foo/bar path on the old api. Once I deploy the CfnApiMapping resource, calling that same URL invokes the correct path on the new api.
Weird behaviour 1: If I delete that base path mapping, I would expect it to go back to the original api. Instead I get a 403 error. If I create it again, it resolves to the new API again, and deleting it again gives the 403 error again.
Weird behaviour 2: If instead of deleting it, I change the path value so it no longer maps "foo", the /foo/bar path works with the old endpoint again. I can then delete the mapping and everything keeps working fine.
Weird behaviour 3: I am unable to recreate this as I can't remember which sequence of steps I took, but it happened a couple of times where I deleted the base path mapping and it continued to work as if the mapping was still there. There was no mapping visible in the console, and I gave it plenty of time for the change to take effect, but it continued to work.
All this is done with the CDK, not manually. Doing this manually or via regular cloudformation works with no issues.
I have a fully functioning API Gateway custom domain name setup:
An API Gateway API with routes / (ANY) and /{proxy+} (ANY) both integrated to a lambda function, connected to a custom domain name (with wildcard subdomains ex. *.example.com) with an API mapping using the default HTTP API and $default stage and an empty path and default endpoint enabled. I've also added the corresponding A record to route traffic to the particular API in route 53. It invocates the lambda function that it's supposed to do when I go to the URL (ex. sub1.example.com), and I've verified that this works.
However, I'm looking to be able to handle wildcard paths with the same API, so I've added * as the path in the API mapping (it was blank previously). Now, it returns {"message": "Forbidden"} when I go to the URL (ex. sub1.example.com) and the URL with any path (ex. sub1.example.com/examplepath), and the header status code == 403 and x-amzn-errortype == ForbiddenException in the response headers. What am I doing wrong?
Is there a way to get the resource id given partial url using rest admin api?
Below is the endpoint I call - http://localhost:8180/auth/realms/quickstart-serv-springboot/authz/protection/resource_set?uri=/wb/customer to fetch the resource id.
I want to know if I can pass wild characters in the query string of uri so that it returns the resource id. e.g. - http://localhost:8180/auth/realms/quickstart-serv-springboot/authz/protection/resource_set?uri=/wb/customer/* or http://localhost:8180/auth/realms/quickstart-serv-springboot/authz/protection/resource_set?uri=/wb/cust* or provide a regex pattern to fetch matching resource ids.
Thx
From source code it seems to work next way:
First Keycloak tries to find an exact match
Then if no match is found and there is parameter "matchingUri=true" it will try to find resources by pattern matching.
I didn't check but would recommend adding "matchingUri=true" to your query and try again.
Also pay attention that complex patterns are not supported. Keycloak Documentation says:
Currently a very basic logic for path matching is supported. Examples of valid paths are:
Wildcards: /*
Suffix: /*.html
Sub-paths: /path/*
Path parameters: /resource/{id}
Exact match: /resource
Patterns: /{version}/resource, /api/{version}/resource, /api/{version}/resource/*
I'm using Azure Service Fabric with stateless services. I have a list of services deployed under an application, and there's a naming convention used with those service names. I'd like to get a list of services that match a filter expression.
Here is a link to a screenshot of my service fabric explorer. I don't have the reputation points to post an image.
Service Fabric Explorer screenshot
In this example, the name of my application is SFApp1, and the name of my service is HelloWorldStateless. I'd like to query the service fabric cluster to locate all services with the name "HelloWorldSt*" (under the SFApp1 application of course).
I know I can query to find all services with the application name "fabric:/SFApp1", and it'll return all services under that application. This overload of GetServiceListAsync takes just an application URI.
FabricClient client = new FabricClient();
ServiceList serviceList = client.QueryManager.GetServiceListAsync(new Uri("fabric:/SFApp1")).Result;
I also know I can query to find a specific service. This overload takes an application URI AND a service URI and will return a single-item list.
FabricClient client = new FabricClient();
ServiceList serviceList = client.QueryManager.GetServiceListAsync(new Uri("fabric:/SFApp1"), new Uri("fabric:/SFApp1/HelloWorldStateless")).Result;
What I'm trying to find out is if there's any way to do something like a wildcard search.
FabricClient client = new FabricClient();
ServiceList serviceList = client.QueryManager.GetServiceListAsync(new Uri("fabric:/SFApp1"), new Uri("fabric:/SFApp1/HelloWorldSt*")).Result;
The name of the parameter where the service name is specified is serviceNameFilter, and the method returns a list. I'm wondering why they would return a list for this overload if the result was always going to be a single-item list. Also, the parameter name "serviceNameFilter" suggests (to me at least) that there's the ability to supply some kind of expression to narrow down your list.
Here's what I've tried already. I've tried the code above, where I chop off a few characters and put an asterisk. I've tried without the asterisk to see if it was a substring match. I've tried SQL-style, with a percent symbol. I've tried a question mark. All of those attempts returned an empty list.
My current workaround is just to ask for all services under that application, and I'll filter them on the client code end with a linq expression. That'll work, but I worry about performance if my list of services gets really big.
Would be nice if I could inspect the source code to answer this myself.
Is there a way to do what I'm trying to do, or am I just misinterpreting what "serviceNameFilter" means, and it just means you have to put the entire service URI that you're looking for?
Thanks for any help you can provide!
Unfortunately that API parameter is terribly named. It's not really a filter at all, it's just the name of the service (since there's no other query that just returns one service, this is how you "filter" from all the services in an application down to just one in particular).
The nearest thing to what you're looking for is EnumerateSubnames. It's not a wildcard search, but you can get all the names that exist "underneath" a given name (for example, all of the service names that exist within an application, or all names with some specific prefix). Depending on the structure of how you create your service names this could work for you.
// System.Fabric.FabricClient.PropertyManagementClient
public Task<NameEnumerationResult> EnumerateSubNamesAsync(Uri name, NameEnumerationResult previousResult, bool recursive)
For example: Presume the following names exist in the cluster:
fabric:/SomeApplication/Zone1/Service1
fabric:/SomeApplication/Zone1/Service2
fabric:/SomeApplication/Zone2/Service1
Note that in this case the application would have been created with the name "fabric:/SomeApplication" and then the services with the detailed names above incorporating the "Zone" segment.
If you now EnumerateSubnames("fabric:/SomeApplication/Zone1", null, true) you'd get back a result that gave you the full names that matched (1 & 2 above).
When I create a resource/method in AWS API Gateway API I can create one of the following methods: DELETE, GET, HEAD, OPTIONS, PATCH or POST.
If I choose GET then API Gateway doesn't pass authentication details; but for POST it does.
For GET should I be adding the cognito credentials to the URL of my GET? or just never use GET and use POST for all authenticated calls?
My set-up in API Gateway/Lambda:
I created a Resource and two methods: GET and POST
Under Authorization Settings I set Authorization to AWS_AIM
For this example there is no Request Model
Under Method Execution I set Integration type to Lambda Function and I check Invoke with caller credentials (I also set Lambda Region and Lambda Function)
I leave Credentials cache unchecked.
For Body Mapping Templates, I set Content-Type to `application/json' and the Mapping Template to
{ "identity" : "$input.params('identity')"}
In my Python Lambda function:
def lambda_handler(event, context):
print context.identity
print context.identity.cognito_identity_id
return True
Running the Python function:
For the GET context.identity is None
For the POST context.identity has a value and context.identity.cognito_identity_id has the correct value.
As mentioned in comments: all HTTP methods support authentication. If the method is configured to require authentication, authentication results should be included in the context for you to access via mapping templates to pass down stream as contextual information.
If this is not working for you, please update your question to reflect:
How your API methods are configured.
What your mapping template is.
What results you see in testing.
UPDATE
The code in your lambda function is checking the context of the Lambda function, not the value from API Gateway. To access the value passed in from API Gateway, you would need to use event.identity not context.identity.
This would only half solve your problem as you are not using the correct value to access the identity in API gateway. That would be $context.identity.cognitoIdentityId (assuming you are using Amazon Cognito auth). Please see the mapping template reference for a full guide of supported variables.
Finally, you may want to consider using the template referenced in this question.