How to provide custom data from API gateway endpoint to lambda authorizer












0















The API Gateway endpoints we are using shall be restricted via permissions to a specific audience.



The idea is to use the lambda authorizer to fetch the permissions from an external service and then create the policy to allow or deny access to the endpoint.



For the matching of the permissions to the API endpoint the endpoint would need to provide the permissions it needs to the authorizer.



My question is now how can I enrich the endpoint data with its own required permissions and use them in the authorizer lambda(probably via the event) for further validation.



Example:




  • User1 is forwarded to the first endpoint GET/petstore/pets(this endpoint needs the permission -> View:Pets)

  • Lambda authorizer requests the user permissions from the external service

  • The service returns: [View:Pets , View:Somethingelse, etc.]

  • The lambda authorizer matches the user permissions against the required endpoint permission and creates the Allow policy on a match

  • User2 does the same but does not have the permission for viewing pets, no match -> Deny


Here is my code for the lambda:



import {Callback, Context} from 'aws-lambda';
import {Authorizer} from './authorizer';

export class App {

constructor(private authorizer: Authorizer = new Authorizer()) {
}

public handleEvent(event, callback: Callback): Promise<void> {
return this.authorizer.checkAuthorization(event, callback)
.then((policy) => callback(null, policy))
.catch((error) => callback(error, null));
}

}

const app: App = new App();

module.exports.lambda_handler = async (event) => {
return await app.handleEvent(event);
};


Code for the checkAuthorization method:



export class Authorizer {


public resourceAuthorizer: ResourceAuthorizer = new ResourceAuthorizer();
public authenticationChecker: AuthenticationChecker = new AuthenticationChecker();

public checkAuthorization(event, callback): Promise<object> {

const endpointPermissions = event.endpointPermissions; // <== this is what I need, a custom field in the event which
// is provided from the api endpoint in some way
// in my example this whould contain a string or json
// with 'View:Pets' and 'View:Somethingelse'

return this.authenticationChecker.check(event)
.then((decodedJwt) => {
const principalId: string = decodedJwt.payload.sub;

return Promise.resolve(decodedJwt)
.then((jwt) => this.resourceAuthorizer.check(jwt, event.endpointPermissions))
.then((payload) => callback(null,
getAuthorizationPolicy(principalId, 'Allow', event.endpointPermissions, payload)))
.catch((payload) => callback(null,
getAuthorizationPolicy(principalId, 'Deny', event.endpointPermissions, payload)));
}).catch((error) => {
console.log(error);
callback('Unauthorized');
});
}
}


The event.endpointPermissions is basically what I am looking for. Depending on the API endpoint this should be filled with the permissions neccessary for that endpoint. The resourceAuthorizer then fetches the users Permissions from the external service and compares them to the endpointPermissions and then creates the Allow or Deny policies.



So where can I enter the endpointPermissions in my API Endpoint to provide them to the Authorizer?










share|improve this question

























  • It would help if you had some code (even if it was part pseudo) to demonstrate what you are trying to achieve and what language you are using.

    – K Mo
    Nov 16 '18 at 10:56











  • I updated the question with code snippets.

    – StV
    Nov 16 '18 at 11:55
















0















The API Gateway endpoints we are using shall be restricted via permissions to a specific audience.



The idea is to use the lambda authorizer to fetch the permissions from an external service and then create the policy to allow or deny access to the endpoint.



For the matching of the permissions to the API endpoint the endpoint would need to provide the permissions it needs to the authorizer.



My question is now how can I enrich the endpoint data with its own required permissions and use them in the authorizer lambda(probably via the event) for further validation.



Example:




  • User1 is forwarded to the first endpoint GET/petstore/pets(this endpoint needs the permission -> View:Pets)

  • Lambda authorizer requests the user permissions from the external service

  • The service returns: [View:Pets , View:Somethingelse, etc.]

  • The lambda authorizer matches the user permissions against the required endpoint permission and creates the Allow policy on a match

  • User2 does the same but does not have the permission for viewing pets, no match -> Deny


Here is my code for the lambda:



import {Callback, Context} from 'aws-lambda';
import {Authorizer} from './authorizer';

export class App {

constructor(private authorizer: Authorizer = new Authorizer()) {
}

public handleEvent(event, callback: Callback): Promise<void> {
return this.authorizer.checkAuthorization(event, callback)
.then((policy) => callback(null, policy))
.catch((error) => callback(error, null));
}

}

const app: App = new App();

module.exports.lambda_handler = async (event) => {
return await app.handleEvent(event);
};


Code for the checkAuthorization method:



export class Authorizer {


public resourceAuthorizer: ResourceAuthorizer = new ResourceAuthorizer();
public authenticationChecker: AuthenticationChecker = new AuthenticationChecker();

public checkAuthorization(event, callback): Promise<object> {

const endpointPermissions = event.endpointPermissions; // <== this is what I need, a custom field in the event which
// is provided from the api endpoint in some way
// in my example this whould contain a string or json
// with 'View:Pets' and 'View:Somethingelse'

return this.authenticationChecker.check(event)
.then((decodedJwt) => {
const principalId: string = decodedJwt.payload.sub;

return Promise.resolve(decodedJwt)
.then((jwt) => this.resourceAuthorizer.check(jwt, event.endpointPermissions))
.then((payload) => callback(null,
getAuthorizationPolicy(principalId, 'Allow', event.endpointPermissions, payload)))
.catch((payload) => callback(null,
getAuthorizationPolicy(principalId, 'Deny', event.endpointPermissions, payload)));
}).catch((error) => {
console.log(error);
callback('Unauthorized');
});
}
}


The event.endpointPermissions is basically what I am looking for. Depending on the API endpoint this should be filled with the permissions neccessary for that endpoint. The resourceAuthorizer then fetches the users Permissions from the external service and compares them to the endpointPermissions and then creates the Allow or Deny policies.



So where can I enter the endpointPermissions in my API Endpoint to provide them to the Authorizer?










share|improve this question

























  • It would help if you had some code (even if it was part pseudo) to demonstrate what you are trying to achieve and what language you are using.

    – K Mo
    Nov 16 '18 at 10:56











  • I updated the question with code snippets.

    – StV
    Nov 16 '18 at 11:55














0












0








0








The API Gateway endpoints we are using shall be restricted via permissions to a specific audience.



The idea is to use the lambda authorizer to fetch the permissions from an external service and then create the policy to allow or deny access to the endpoint.



For the matching of the permissions to the API endpoint the endpoint would need to provide the permissions it needs to the authorizer.



My question is now how can I enrich the endpoint data with its own required permissions and use them in the authorizer lambda(probably via the event) for further validation.



Example:




  • User1 is forwarded to the first endpoint GET/petstore/pets(this endpoint needs the permission -> View:Pets)

  • Lambda authorizer requests the user permissions from the external service

  • The service returns: [View:Pets , View:Somethingelse, etc.]

  • The lambda authorizer matches the user permissions against the required endpoint permission and creates the Allow policy on a match

  • User2 does the same but does not have the permission for viewing pets, no match -> Deny


Here is my code for the lambda:



import {Callback, Context} from 'aws-lambda';
import {Authorizer} from './authorizer';

export class App {

constructor(private authorizer: Authorizer = new Authorizer()) {
}

public handleEvent(event, callback: Callback): Promise<void> {
return this.authorizer.checkAuthorization(event, callback)
.then((policy) => callback(null, policy))
.catch((error) => callback(error, null));
}

}

const app: App = new App();

module.exports.lambda_handler = async (event) => {
return await app.handleEvent(event);
};


Code for the checkAuthorization method:



export class Authorizer {


public resourceAuthorizer: ResourceAuthorizer = new ResourceAuthorizer();
public authenticationChecker: AuthenticationChecker = new AuthenticationChecker();

public checkAuthorization(event, callback): Promise<object> {

const endpointPermissions = event.endpointPermissions; // <== this is what I need, a custom field in the event which
// is provided from the api endpoint in some way
// in my example this whould contain a string or json
// with 'View:Pets' and 'View:Somethingelse'

return this.authenticationChecker.check(event)
.then((decodedJwt) => {
const principalId: string = decodedJwt.payload.sub;

return Promise.resolve(decodedJwt)
.then((jwt) => this.resourceAuthorizer.check(jwt, event.endpointPermissions))
.then((payload) => callback(null,
getAuthorizationPolicy(principalId, 'Allow', event.endpointPermissions, payload)))
.catch((payload) => callback(null,
getAuthorizationPolicy(principalId, 'Deny', event.endpointPermissions, payload)));
}).catch((error) => {
console.log(error);
callback('Unauthorized');
});
}
}


The event.endpointPermissions is basically what I am looking for. Depending on the API endpoint this should be filled with the permissions neccessary for that endpoint. The resourceAuthorizer then fetches the users Permissions from the external service and compares them to the endpointPermissions and then creates the Allow or Deny policies.



So where can I enter the endpointPermissions in my API Endpoint to provide them to the Authorizer?










share|improve this question
















The API Gateway endpoints we are using shall be restricted via permissions to a specific audience.



The idea is to use the lambda authorizer to fetch the permissions from an external service and then create the policy to allow or deny access to the endpoint.



For the matching of the permissions to the API endpoint the endpoint would need to provide the permissions it needs to the authorizer.



My question is now how can I enrich the endpoint data with its own required permissions and use them in the authorizer lambda(probably via the event) for further validation.



Example:




  • User1 is forwarded to the first endpoint GET/petstore/pets(this endpoint needs the permission -> View:Pets)

  • Lambda authorizer requests the user permissions from the external service

  • The service returns: [View:Pets , View:Somethingelse, etc.]

  • The lambda authorizer matches the user permissions against the required endpoint permission and creates the Allow policy on a match

  • User2 does the same but does not have the permission for viewing pets, no match -> Deny


Here is my code for the lambda:



import {Callback, Context} from 'aws-lambda';
import {Authorizer} from './authorizer';

export class App {

constructor(private authorizer: Authorizer = new Authorizer()) {
}

public handleEvent(event, callback: Callback): Promise<void> {
return this.authorizer.checkAuthorization(event, callback)
.then((policy) => callback(null, policy))
.catch((error) => callback(error, null));
}

}

const app: App = new App();

module.exports.lambda_handler = async (event) => {
return await app.handleEvent(event);
};


Code for the checkAuthorization method:



export class Authorizer {


public resourceAuthorizer: ResourceAuthorizer = new ResourceAuthorizer();
public authenticationChecker: AuthenticationChecker = new AuthenticationChecker();

public checkAuthorization(event, callback): Promise<object> {

const endpointPermissions = event.endpointPermissions; // <== this is what I need, a custom field in the event which
// is provided from the api endpoint in some way
// in my example this whould contain a string or json
// with 'View:Pets' and 'View:Somethingelse'

return this.authenticationChecker.check(event)
.then((decodedJwt) => {
const principalId: string = decodedJwt.payload.sub;

return Promise.resolve(decodedJwt)
.then((jwt) => this.resourceAuthorizer.check(jwt, event.endpointPermissions))
.then((payload) => callback(null,
getAuthorizationPolicy(principalId, 'Allow', event.endpointPermissions, payload)))
.catch((payload) => callback(null,
getAuthorizationPolicy(principalId, 'Deny', event.endpointPermissions, payload)));
}).catch((error) => {
console.log(error);
callback('Unauthorized');
});
}
}


The event.endpointPermissions is basically what I am looking for. Depending on the API endpoint this should be filled with the permissions neccessary for that endpoint. The resourceAuthorizer then fetches the users Permissions from the external service and compares them to the endpointPermissions and then creates the Allow or Deny policies.



So where can I enter the endpointPermissions in my API Endpoint to provide them to the Authorizer?







amazon-web-services aws-lambda authorization aws-api-gateway lambda-authorizer






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 16 '18 at 11:53







StV

















asked Nov 16 '18 at 9:20









StVStV

847




847













  • It would help if you had some code (even if it was part pseudo) to demonstrate what you are trying to achieve and what language you are using.

    – K Mo
    Nov 16 '18 at 10:56











  • I updated the question with code snippets.

    – StV
    Nov 16 '18 at 11:55



















  • It would help if you had some code (even if it was part pseudo) to demonstrate what you are trying to achieve and what language you are using.

    – K Mo
    Nov 16 '18 at 10:56











  • I updated the question with code snippets.

    – StV
    Nov 16 '18 at 11:55

















It would help if you had some code (even if it was part pseudo) to demonstrate what you are trying to achieve and what language you are using.

– K Mo
Nov 16 '18 at 10:56





It would help if you had some code (even if it was part pseudo) to demonstrate what you are trying to achieve and what language you are using.

– K Mo
Nov 16 '18 at 10:56













I updated the question with code snippets.

– StV
Nov 16 '18 at 11:55





I updated the question with code snippets.

– StV
Nov 16 '18 at 11:55












2 Answers
2






active

oldest

votes


















1














The event being passed to the Authorizer contains a methodArn, which is in the format:



arn:aws:execute-api:<Region id>:<Account id>:<API id>/<Stage>/<Method>/<Resource path>


This would give you the Method and Resource Path that you need. It also would give you an identifier of the API, but not the name of the API itself.



The API id, can be used to get the API name by using the AWS SDK. See here.



This should give you everything you need to construct your endpointPermissions value.






share|improve this answer
























  • Thank you for your proposal. I already tried this solution and it has the drawback that you have to create a seperate mapping from endpoint arn to a list of permissions which I wanted to avoid.

    – StV
    Nov 16 '18 at 13:50











  • I accept this as the right answer since it's absolutely feasible although not what I was looking for.

    – StV
    Nov 21 '18 at 6:57



















0














I got a solution to my problem without having to parse the ARN, but it's pretty unconventional:




  1. In the method request of a resource create URL query string parameters with the permission names and set the checkbox for 'required'


method request URL query string parameters




  1. When the request is called from the client(Postman) these mandatory parameters have to be provided as keys, they are endpoint-specific. The values do not matter because only the keys will be used at evaluation.


postman request parameters





  1. The event received by the authorizer now contains the queryStringParameters which can be evaluated for further use.



    queryStringParameters in cloudwatch








share|improve this answer
























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53334793%2fhow-to-provide-custom-data-from-api-gateway-endpoint-to-lambda-authorizer%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    The event being passed to the Authorizer contains a methodArn, which is in the format:



    arn:aws:execute-api:<Region id>:<Account id>:<API id>/<Stage>/<Method>/<Resource path>


    This would give you the Method and Resource Path that you need. It also would give you an identifier of the API, but not the name of the API itself.



    The API id, can be used to get the API name by using the AWS SDK. See here.



    This should give you everything you need to construct your endpointPermissions value.






    share|improve this answer
























    • Thank you for your proposal. I already tried this solution and it has the drawback that you have to create a seperate mapping from endpoint arn to a list of permissions which I wanted to avoid.

      – StV
      Nov 16 '18 at 13:50











    • I accept this as the right answer since it's absolutely feasible although not what I was looking for.

      – StV
      Nov 21 '18 at 6:57
















    1














    The event being passed to the Authorizer contains a methodArn, which is in the format:



    arn:aws:execute-api:<Region id>:<Account id>:<API id>/<Stage>/<Method>/<Resource path>


    This would give you the Method and Resource Path that you need. It also would give you an identifier of the API, but not the name of the API itself.



    The API id, can be used to get the API name by using the AWS SDK. See here.



    This should give you everything you need to construct your endpointPermissions value.






    share|improve this answer
























    • Thank you for your proposal. I already tried this solution and it has the drawback that you have to create a seperate mapping from endpoint arn to a list of permissions which I wanted to avoid.

      – StV
      Nov 16 '18 at 13:50











    • I accept this as the right answer since it's absolutely feasible although not what I was looking for.

      – StV
      Nov 21 '18 at 6:57














    1












    1








    1







    The event being passed to the Authorizer contains a methodArn, which is in the format:



    arn:aws:execute-api:<Region id>:<Account id>:<API id>/<Stage>/<Method>/<Resource path>


    This would give you the Method and Resource Path that you need. It also would give you an identifier of the API, but not the name of the API itself.



    The API id, can be used to get the API name by using the AWS SDK. See here.



    This should give you everything you need to construct your endpointPermissions value.






    share|improve this answer













    The event being passed to the Authorizer contains a methodArn, which is in the format:



    arn:aws:execute-api:<Region id>:<Account id>:<API id>/<Stage>/<Method>/<Resource path>


    This would give you the Method and Resource Path that you need. It also would give you an identifier of the API, but not the name of the API itself.



    The API id, can be used to get the API name by using the AWS SDK. See here.



    This should give you everything you need to construct your endpointPermissions value.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 16 '18 at 13:30









    K MoK Mo

    934411




    934411













    • Thank you for your proposal. I already tried this solution and it has the drawback that you have to create a seperate mapping from endpoint arn to a list of permissions which I wanted to avoid.

      – StV
      Nov 16 '18 at 13:50











    • I accept this as the right answer since it's absolutely feasible although not what I was looking for.

      – StV
      Nov 21 '18 at 6:57



















    • Thank you for your proposal. I already tried this solution and it has the drawback that you have to create a seperate mapping from endpoint arn to a list of permissions which I wanted to avoid.

      – StV
      Nov 16 '18 at 13:50











    • I accept this as the right answer since it's absolutely feasible although not what I was looking for.

      – StV
      Nov 21 '18 at 6:57

















    Thank you for your proposal. I already tried this solution and it has the drawback that you have to create a seperate mapping from endpoint arn to a list of permissions which I wanted to avoid.

    – StV
    Nov 16 '18 at 13:50





    Thank you for your proposal. I already tried this solution and it has the drawback that you have to create a seperate mapping from endpoint arn to a list of permissions which I wanted to avoid.

    – StV
    Nov 16 '18 at 13:50













    I accept this as the right answer since it's absolutely feasible although not what I was looking for.

    – StV
    Nov 21 '18 at 6:57





    I accept this as the right answer since it's absolutely feasible although not what I was looking for.

    – StV
    Nov 21 '18 at 6:57













    0














    I got a solution to my problem without having to parse the ARN, but it's pretty unconventional:




    1. In the method request of a resource create URL query string parameters with the permission names and set the checkbox for 'required'


    method request URL query string parameters




    1. When the request is called from the client(Postman) these mandatory parameters have to be provided as keys, they are endpoint-specific. The values do not matter because only the keys will be used at evaluation.


    postman request parameters





    1. The event received by the authorizer now contains the queryStringParameters which can be evaluated for further use.



      queryStringParameters in cloudwatch








    share|improve this answer




























      0














      I got a solution to my problem without having to parse the ARN, but it's pretty unconventional:




      1. In the method request of a resource create URL query string parameters with the permission names and set the checkbox for 'required'


      method request URL query string parameters




      1. When the request is called from the client(Postman) these mandatory parameters have to be provided as keys, they are endpoint-specific. The values do not matter because only the keys will be used at evaluation.


      postman request parameters





      1. The event received by the authorizer now contains the queryStringParameters which can be evaluated for further use.



        queryStringParameters in cloudwatch








      share|improve this answer


























        0












        0








        0







        I got a solution to my problem without having to parse the ARN, but it's pretty unconventional:




        1. In the method request of a resource create URL query string parameters with the permission names and set the checkbox for 'required'


        method request URL query string parameters




        1. When the request is called from the client(Postman) these mandatory parameters have to be provided as keys, they are endpoint-specific. The values do not matter because only the keys will be used at evaluation.


        postman request parameters





        1. The event received by the authorizer now contains the queryStringParameters which can be evaluated for further use.



          queryStringParameters in cloudwatch








        share|improve this answer













        I got a solution to my problem without having to parse the ARN, but it's pretty unconventional:




        1. In the method request of a resource create URL query string parameters with the permission names and set the checkbox for 'required'


        method request URL query string parameters




        1. When the request is called from the client(Postman) these mandatory parameters have to be provided as keys, they are endpoint-specific. The values do not matter because only the keys will be used at evaluation.


        postman request parameters





        1. The event received by the authorizer now contains the queryStringParameters which can be evaluated for further use.



          queryStringParameters in cloudwatch









        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 22 '18 at 11:31









        StVStV

        847




        847






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53334793%2fhow-to-provide-custom-data-from-api-gateway-endpoint-to-lambda-authorizer%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Florida Star v. B. J. F.

            Danny Elfman

            Lugert, Oklahoma