Skip to content

Pourquoi ma ressource proxy API Gateway dotée d'un mécanisme d’autorisation Lambda dont la mise en cache est activée renvoie-t-elle des erreurs HTTP 403 « User is not authorized to access this resource » ?

Lecture de 6 minute(s)
0

Ma ressource proxy Amazon API Gateway dotée d'un mécanisme d’autorisation AWS Lambda dont la mise en cache est activée renvoie le message d'erreur HTTP 403 suivant : « User is not authorized to access this resource ».

Brève description

Remarque : API Gateway peut renvoyer des erreurs 403 User is not authorized to access this resource pour diverses raisons. Cet article traite des erreurs 403 liées aux ressources proxy d'API Gateway avec un mécanisme d’autorisation Lambda dont la mise en cache est activée uniquement. Pour en savoir plus sur la résolution des autres types d’erreurs 403, consultez la section Comment puis-je résoudre les erreurs HTTP 403 renvoyées par API Gateway ?

La sortie du mécanisme d’autorisation Lambda renvoie une stratégie AWS Identity and Access Management (IAM) à API Gateway. La stratégie IAM inclut un élément « ressource » d'API API Gateway explicite au format suivant :

"arn:aws:execute-api:<region>:<account>:<API_id>/<stage>/<http-method>/[<resource-path-name>/[<child-resources-path>]"

Lorsque la mise en cache des autorisations est activée sur un mécanisme d’autorisation Lambda, la stratégie IAM renvoyée est mise en cache. La stratégie IAM mise en cache est ensuite appliquée à toutes les requêtes d'API supplémentaires effectuées pendant la période de durée de vie (TTL) spécifiée du cache.

Si l'API utilise une ressource proxy avec une variable de chemin Greedy de {proxy+}, la première autorisation aboutit. Toutes les requêtes d'API supplémentaires effectuées vers un chemin différent pendant la période TTL du cache échouent et renvoient l'erreur suivante :

« message » : « User is not authorized to access this resource »

Les requêtes supplémentaires échouent, car les chemins ne correspondent pas à l'élément « Ressource » de l'API API Gateway explicite défini dans la stratégie IAM mise en cache.

Pour résoudre le problème, vous pouvez modifier le code de la fonction d'autorisation Lambda pour renvoyer une ressource générique (*/*) dans la sortie à la place. Pour plus d'informations, consultez la section Ressources et conditions relatives aux actions Lambda.

Remarque : Pour activer la mise en cache du mécanisme d’autorisation, celui-ci doit renvoyer une stratégie applicable à toutes les méthodes d'une passerelle API. Le code de la fonction du mécanisme d'autorisation Lambda doit renvoyer une ressource générique (*/*) dans la sortie pour autoriser toutes les ressources. La stratégie de cache prévoit que le même chemin de ressources est mis en cache, sauf si vous avez présenté la même requête à deux reprises sur le même chemin de ressources.

Résolution

Remarque : Modifiez les extraits de code du mécanisme d’autorisation Lambda présentés dans cet article en fonction de votre cas d'utilisation.

Dans les exemples de configuration suivants, les fonctions Lambda extraient la valeur ID de la passerelle API à partir de l'Amazon Resource Name (ARN) de la méthode (« event.methodArn »). Ensuite, les fonctions définissent une variable « Ressource » générique en combinant les chemins de l'ARN de la méthode avec la valeur ID de l'API et un caractère générique ( */*).

Exemple de code de fonction du mécanisme d'autorisation Lambda basé sur des jetons qui renvoie une variable « Ressource » générique

exports.handler =  function(event, context, callback) {
    var token = event.authorizationToken;
    var tmp = event.methodArn.split(':');
    var apiGatewayArnTmp = tmp[5].split('/');

    // Create wildcard resource
    var resource = tmp[0] + ":" + tmp[1] + ":" + tmp[2] + ":" + tmp[3] + ":" + tmp[4] + ":" + apiGatewayArnTmp[0] + '/*/*';
    switch (token) {
        case 'allow':
            callback(null, generatePolicy('user', 'Allow', resource));
            break;
        case 'deny':
            callback(null, generatePolicy('user', 'Deny', resource));
            break;
        case 'unauthorized':
            callback("Unauthorized");   // Return a 401 Unauthorized response
            break;
        default:
            callback("Error: Invalid token"); // Return a 500 Invalid token response
    }
};
// Help function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
    var authResponse = {};

    authResponse.principalId = principalId;
    if (effect && resource) {
        var policyDocument = {};
        policyDocument.Version = '2012-10-17';
        policyDocument.Statement = [];
        var statementOne = {};
        statementOne.Action = 'execute-api:Invoke';
        statementOne.Effect = effect;
        statementOne.Resource = resource;
        policyDocument.Statement[0] = statementOne;
        authResponse.policyDocument = policyDocument;
    }

    // Optional output with custom properties of the String, Number or Boolean type.
    authResponse.context = {
        "stringKey": "stringval",
        "numberKey": 123,
        "booleanKey": true
    };
    return authResponse;
}

Exemple de code de fonction du mécanisme d'autorisation Lambda basé sur des paramètres de requête qui renvoie une variable « Ressource » générique

exports.handler = function(event, context, callback) {        

    // Retrieve request parameters from the Lambda function input:
    var headers = event.headers;
    var queryStringParameters = event.queryStringParameters;
    var pathParameters = event.pathParameters;
    var stageVariables = event.stageVariables;

    // Parse the input for the parameter values
    var tmp = event.methodArn.split(':');
    var apiGatewayArnTmp = tmp[5].split('/');

    // Create wildcard resource
    var resource = tmp[0] + ":" + tmp[1] + ":" + tmp[2] + ":" + tmp[3] + ":" + tmp[4] + ":" + apiGatewayArnTmp[0] + '/*/*';
    console.log("resource: " + resource);
    // if (apiGatewayArnTmp[3]) {
    //     resource += apiGatewayArnTmp[3];
    // }

    // Perform authorization to return the Allow policy for correct parameters and
    // the 'Unauthorized' error, otherwise.
    var authResponse = {};
    var condition = {};
    condition.IpAddress = {};


    if (headers.headerauth1 === "headerValue1"
        && queryStringParameters.QueryString1 === "queryValue1"
        && stageVariables.StageVar1 === "stageValue1") {
        callback(null, generateAllow('me', resource));
    }  else {
        callback("Unauthorized");
    }
}

// Help function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
    // Required output:
    console.log("Resource in generatePolicy(): " + resource);
    var authResponse = {};
    authResponse.principalId = principalId;
    if (effect && resource) {
        var policyDocument = {};
        policyDocument.Version = '2012-10-17'; // default version
        policyDocument.Statement = [];
        var statementOne = {};
        statementOne.Action = 'execute-api:Invoke'; // default action
        statementOne.Effect = effect;
        statementOne.Resource = resource;
        console.log("***Resource*** " + resource);
        policyDocument.Statement[0] = statementOne;
        console.log("***Generated Policy*** ");
        console.log(policyDocument);
        authResponse.policyDocument = policyDocument;
    }
    // Optional output with custom properties of the String, Number or Boolean type.
    authResponse.context = {
        "stringKey": "stringval",
        "numberKey": 123,
        "booleanKey": true
    };

    return authResponse;
}

var generateAllow = function(principalId, resource) {
    return generatePolicy(principalId, 'Allow', resource);
}

var generateDeny = function(principalId, resource) {
    return generatePolicy(principalId, 'Deny', resource);
}

Pour plus d'informations sur la procédure de modification du code de fonction Lambda, consultez la section Déploiement de fonctions Lambda définies comme des archives de fichier .zip.

Informations connexes

Test des fonctions Lambda dans la console