scripts/lua/oauth/app-id.lua (59 lines of code) (raw):

-- -- Licensed to the Apache Software Foundation (ASF) under one or more -- contributor license agreements. See the NOTICE file distributed with -- this work for additional information regarding copyright ownership. -- The ASF licenses this file to You under the Apache License, Version 2.0 -- (the "License"); you may not use this file except in compliance with -- the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- local request = require 'lib/request' local cjson = require 'cjson' local utils = require 'lib/utils' local APPID_PKURL = os.getenv("APPID_PKURL") local _M = {} local http = require 'resty.http' local cjose = require 'resty.cjose' local function inject_req_headers(token_obj) ngx.header['X-OIDC-Email'] = token_obj['email'] ngx.header['X-OIDC-Sub'] = token_obj['sub'] end local function fetchJWKs(tenantId) local httpc = http.new() local keyUrl = utils.concatStrings({APPID_PKURL, tenantId, '/publickeys'}) local request_options = { headers = { ["Accept"] = "application/json" }, ssl_verify = true } return httpc:request_uri(keyUrl, request_options) end function _M.process(dataStore, token, securityObj) local cache_key = 'appid_' .. securityObj.tenantId local result = dataStore:getOAuthToken(cache_key, token) local token_obj -- Was the token in the cache? if result ~= ngx.null then token_obj = cjson.decode(result) inject_req_headers(token_obj) return token_obj end -- Cache miss. Proceed to validate the token local res, err = fetchJWKs(securityObj.tenantId) if err ~= nil or not res or res.status ~= 200 then request.err(500, 'An error occurred while fetching the App ID JWK configuration: ' .. err or res.body) return nil end local key local keys = cjson.decode(res.body).keys for _, v in ipairs(keys) do key = v end result = cjose.validateJWS(token, cjson.encode(key)) if not result then request.err(401, 'The token signature did not match any known JWK.') return nil end token_obj = cjson.decode(cjose.getJWSInfo(token)) local expireTime = token_obj['exp'] if expireTime < os.time() then request.err(401, 'The access token has expired.') return nil end -- Add token metadata to the request headers inject_req_headers(token_obj) -- keep token in cache until it expires local ttl = expireTime - os.time() local encodedToken = cjson.encode(token_obj) dataStore:saveOAuthToken(cache_key, token, encodedToken, ttl) return token_obj end return _M