1. add the auth lua plugin and the driver lua plugin.
authorzhouruiyu <zhouruiyu@huawei.com>
Tue, 20 Sep 2016 03:31:05 +0000 (11:31 +0800)
committerzhouruiyu <zhouruiyu@huawei.com>
Tue, 20 Sep 2016 03:31:05 +0000 (11:31 +0800)
Change-Id: Id446447dbd904092f7dd2d1326d3c51c4876713b
Signed-off-by: zhouruiyu <zhouruiyu@huawei.com>
msb-core/openresty-ext/src/assembly/resources/openresty/lualib/resty/http.lua [new file with mode: 0644]
msb-core/openresty-ext/src/assembly/resources/openresty/lualib/resty/http_headers.lua [new file with mode: 0644]
msb-core/openresty-ext/src/assembly/resources/openresty/nginx/luaext/plugins/auth.lua
msb-core/openresty-ext/src/assembly/resources/openresty/nginx/luaext/plugins/driver_manager.lua

diff --git a/msb-core/openresty-ext/src/assembly/resources/openresty/lualib/resty/http.lua b/msb-core/openresty-ext/src/assembly/resources/openresty/lualib/resty/http.lua
new file mode 100644 (file)
index 0000000..94f9813
--- /dev/null
@@ -0,0 +1,850 @@
+local http_headers = require "resty.http_headers"
+
+local ngx_socket_tcp = ngx.socket.tcp
+local ngx_req = ngx.req
+local ngx_req_socket = ngx_req.socket
+local ngx_req_get_headers = ngx_req.get_headers
+local ngx_req_get_method = ngx_req.get_method
+local str_gmatch = string.gmatch
+local str_lower = string.lower
+local str_upper = string.upper
+local str_find = string.find
+local str_sub = string.sub
+local str_gsub = string.gsub
+local tbl_concat = table.concat
+local tbl_insert = table.insert
+local ngx_encode_args = ngx.encode_args
+local ngx_re_match = ngx.re.match
+local ngx_re_gsub = ngx.re.gsub
+local ngx_log = ngx.log
+local ngx_DEBUG = ngx.DEBUG
+local ngx_ERR = ngx.ERR
+local ngx_NOTICE = ngx.NOTICE
+local ngx_var = ngx.var
+local co_yield = coroutine.yield
+local co_create = coroutine.create
+local co_status = coroutine.status
+local co_resume = coroutine.resume
+
+
+-- http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
+local HOP_BY_HOP_HEADERS = {
+    ["connection"]          = true,
+    ["keep-alive"]          = true,
+    ["proxy-authenticate"]  = true,
+    ["proxy-authorization"] = true,
+    ["te"]                  = true,
+    ["trailers"]            = true,
+    ["transfer-encoding"]   = true,
+    ["upgrade"]             = true,
+    ["content-length"]      = true, -- Not strictly hop-by-hop, but Nginx will deal
+                                    -- with this (may send chunked for example).
+}
+
+
+-- Reimplemented coroutine.wrap, returning "nil, err" if the coroutine cannot
+-- be resumed. This protects user code from inifite loops when doing things like
+-- repeat
+--   local chunk, err = res.body_reader()
+--   if chunk then -- <-- This could be a string msg in the core wrap function.
+--     ...
+--   end
+-- until not chunk
+local co_wrap = function(func)
+    local co = co_create(func)
+    if not co then
+        return nil, "could not create coroutine"
+    else
+        return function(...)
+            if co_status(co) == "suspended" then
+                return select(2, co_resume(co, ...))
+            else
+                return nil, "can't resume a " .. co_status(co) .. " coroutine"
+            end
+        end
+    end
+end
+
+
+local _M = {
+    _VERSION = '0.09',
+}
+_M._USER_AGENT = "lua-resty-http/" .. _M._VERSION .. " (Lua) ngx_lua/" .. ngx.config.ngx_lua_version
+
+local mt = { __index = _M }
+
+
+local HTTP = {
+    [1.0] = " HTTP/1.0\r\n",
+    [1.1] = " HTTP/1.1\r\n",
+}
+
+local DEFAULT_PARAMS = {
+    method = "GET",
+    path = "/",
+    version = 1.1,
+}
+
+
+function _M.new(self)
+    local sock, err = ngx_socket_tcp()
+    if not sock then
+        return nil, err
+    end
+    return setmetatable({ sock = sock, keepalive = true }, mt)
+end
+
+
+function _M.set_timeout(self, timeout)
+    local sock = self.sock
+    if not sock then
+        return nil, "not initialized"
+    end
+
+    return sock:settimeout(timeout)
+end
+
+
+function _M.ssl_handshake(self, ...)
+    local sock = self.sock
+    if not sock then
+        return nil, "not initialized"
+    end
+
+    self.ssl = true
+
+    return sock:sslhandshake(...)
+end
+
+
+function _M.connect(self, ...)
+    local sock = self.sock
+    if not sock then
+        return nil, "not initialized"
+    end
+
+    self.host = select(1, ...)
+    self.port = select(2, ...)
+
+    -- If port is not a number, this is likely a unix domain socket connection.
+    if type(self.port) ~= "number" then
+        self.port = nil
+    end
+
+    self.keepalive = true
+
+    return sock:connect(...)
+end
+
+
+function _M.set_keepalive(self, ...)
+    local sock = self.sock
+    if not sock then
+        return nil, "not initialized"
+    end
+
+    if self.keepalive == true then
+        return sock:setkeepalive(...)
+    else
+        -- The server said we must close the connection, so we cannot setkeepalive.
+        -- If close() succeeds we return 2 instead of 1, to differentiate between
+        -- a normal setkeepalive() failure and an intentional close().
+        local res, err = sock:close()
+        if res then
+            return 2, "connection must be closed"
+        else
+            return res, err
+        end
+    end
+end
+
+
+function _M.get_reused_times(self)
+    local sock = self.sock
+    if not sock then
+        return nil, "not initialized"
+    end
+
+    return sock:getreusedtimes()
+end
+
+
+function _M.close(self)
+    local sock = self.sock
+    if not sock then
+        return nil, "not initialized"
+    end
+
+    return sock:close()
+end
+
+
+local function _should_receive_body(method, code)
+    if method == "HEAD" then return nil end
+    if code == 204 or code == 304 then return nil end
+    if code >= 100 and code < 200 then return nil end
+    return true
+end
+
+
+function _M.parse_uri(self, uri)
+    local m, err = ngx_re_match(uri, [[^(http[s]?)://([^:/]+)(?::(\d+))?(.*)]],
+        "jo")
+
+    if not m then
+        if err then
+            return nil, "failed to match the uri: " .. uri .. ", " .. err
+        end
+
+        return nil, "bad uri: " .. uri
+    else
+        if m[3] then
+            m[3] = tonumber(m[3])
+        else
+            if m[1] == "https" then
+                m[3] = 443
+            else
+                m[3] = 80
+            end
+        end
+        if not m[4] or "" == m[4] then m[4] = "/" end
+        return m, nil
+    end
+end
+
+
+local function _format_request(params)
+    local version = params.version
+    local headers = params.headers or {}
+
+    local query = params.query or ""
+    if query then
+        if type(query) == "table" then
+            query = "?" .. ngx_encode_args(query)
+        end
+    end
+
+    -- Initialize request
+    local req = {
+        str_upper(params.method),
+        " ",
+        params.path,
+        query,
+        HTTP[version],
+        -- Pre-allocate slots for minimum headers and carriage return.
+        true,
+        true,
+        true,
+    }
+    local c = 6 -- req table index it's faster to do this inline vs table.insert
+
+    -- Append headers
+    for key, values in pairs(headers) do
+        if type(values) ~= "table" then
+            values = {values}
+        end
+
+        key = tostring(key)
+        for _, value in pairs(values) do
+            req[c] = key .. ": " .. tostring(value) .. "\r\n"
+            c = c + 1
+        end
+    end
+
+    -- Close headers
+    req[c] = "\r\n"
+
+    return tbl_concat(req)
+end
+
+
+local function _receive_status(sock)
+    local line, err = sock:receive("*l")
+    if not line then
+        return nil, nil, nil, err
+    end
+
+    return tonumber(str_sub(line, 10, 12)), tonumber(str_sub(line, 6, 8)), str_sub(line, 14)
+end
+
+
+
+local function _receive_headers(sock)
+    local headers = http_headers.new()
+
+    repeat
+        local line, err = sock:receive("*l")
+        if not line then
+            return nil, err
+        end
+
+        for key, val in str_gmatch(line, "([^:%s]+):%s*(.+)") do
+            if headers[key] then
+                if type(headers[key]) ~= "table" then
+                    headers[key] = { headers[key] }
+                end
+                tbl_insert(headers[key], tostring(val))
+            else
+                headers[key] = tostring(val)
+            end
+        end
+    until str_find(line, "^%s*$")
+
+    return headers, nil
+end
+
+
+local function _chunked_body_reader(sock, default_chunk_size)
+    return co_wrap(function(max_chunk_size)
+        local max_chunk_size = max_chunk_size or default_chunk_size
+        local remaining = 0
+        local length
+
+        repeat
+            -- If we still have data on this chunk
+            if max_chunk_size and remaining > 0 then
+
+                if remaining > max_chunk_size then
+                    -- Consume up to max_chunk_size
+                    length = max_chunk_size
+                    remaining = remaining - max_chunk_size
+                else
+                    -- Consume all remaining
+                    length = remaining
+                    remaining = 0
+                end
+            else -- This is a fresh chunk
+
+                -- Receive the chunk size
+                local str, err = sock:receive("*l")
+                if not str then
+                    co_yield(nil, err)
+                end
+
+                length = tonumber(str, 16)
+
+                if not length then
+                    co_yield(nil, "unable to read chunksize")
+                end
+
+                if max_chunk_size and length > max_chunk_size then
+                    -- Consume up to max_chunk_size
+                    remaining = length - max_chunk_size
+                    length = max_chunk_size
+                end
+            end
+
+            if length > 0 then
+                local str, err = sock:receive(length)
+                if not str then
+                    co_yield(nil, err)
+                end
+
+                max_chunk_size = co_yield(str) or default_chunk_size
+
+                -- If we're finished with this chunk, read the carriage return.
+                if remaining == 0 then
+                    sock:receive(2) -- read \r\n
+                end
+            else
+                -- Read the last (zero length) chunk's carriage return
+                sock:receive(2) -- read \r\n
+            end
+
+        until length == 0
+    end)
+end
+
+
+local function _body_reader(sock, content_length, default_chunk_size)
+    return co_wrap(function(max_chunk_size)
+        local max_chunk_size = max_chunk_size or default_chunk_size
+
+        if not content_length and max_chunk_size then
+            -- We have no length, but wish to stream.
+            -- HTTP 1.0 with no length will close connection, so read chunks to the end.
+            repeat
+                local str, err, partial = sock:receive(max_chunk_size)
+                if not str and err == "closed" then
+                    max_chunk_size = tonumber(co_yield(partial, err) or default_chunk_size)
+                end
+
+                max_chunk_size = tonumber(co_yield(str) or default_chunk_size)
+                if max_chunk_size and max_chunk_size < 0 then max_chunk_size = nil end
+
+                if not max_chunk_size then
+                    ngx_log(ngx_ERR, "Buffer size not specified, bailing")
+                    break
+                end
+            until not str
+
+        elseif not content_length then
+            -- We have no length but don't wish to stream.
+            -- HTTP 1.0 with no length will close connection, so read to the end.
+            co_yield(sock:receive("*a"))
+
+        elseif not max_chunk_size then
+            -- We have a length and potentially keep-alive, but want everything.
+            co_yield(sock:receive(content_length))
+
+        else
+            -- We have a length and potentially a keep-alive, and wish to stream
+            -- the response.
+            local received = 0
+            repeat
+                local length = max_chunk_size
+                if received + length > content_length then
+                    length = content_length - received
+                end
+
+                if length > 0 then
+                    local str, err = sock:receive(length)
+                    if not str then
+                        max_chunk_size = tonumber(co_yield(nil, err) or default_chunk_size)
+                    end
+                    received = received + length
+
+                    max_chunk_size = tonumber(co_yield(str) or default_chunk_size)
+                    if max_chunk_size and max_chunk_size < 0 then max_chunk_size = nil end
+
+                    if not max_chunk_size then
+                        ngx_log(ngx_ERR, "Buffer size not specified, bailing")
+                        break
+                    end
+                end
+
+            until length == 0
+        end
+    end)
+end
+
+
+local function _no_body_reader()
+    return nil
+end
+
+
+local function _read_body(res)
+    local reader = res.body_reader
+
+    if not reader then
+        -- Most likely HEAD or 304 etc.
+        return nil, "no body to be read"
+    end
+
+    local chunks = {}
+    local c = 1
+
+    local chunk, err
+    repeat
+        chunk, err = reader()
+
+        if err then
+            return nil, err, tbl_concat(chunks) -- Return any data so far.
+        end
+        if chunk then
+            chunks[c] = chunk
+            c = c + 1
+        end
+    until not chunk
+
+    return tbl_concat(chunks)
+end
+
+
+local function _trailer_reader(sock)
+    return co_wrap(function()
+        co_yield(_receive_headers(sock))
+    end)
+end
+
+
+local function _read_trailers(res)
+    local reader = res.trailer_reader
+    if not reader then
+        return nil, "no trailers"
+    end
+
+    local trailers = reader()
+    setmetatable(res.headers, { __index = trailers })
+end
+
+
+local function _send_body(sock, body)
+    if type(body) == 'function' then
+        repeat
+            local chunk, err, partial = body()
+
+            if chunk then
+                local ok,err = sock:send(chunk)
+
+                if not ok then
+                    return nil, err
+                end
+            elseif err ~= nil then
+                return nil, err, partial
+            end
+
+        until chunk == nil
+    elseif body ~= nil then
+        local bytes, err = sock:send(body)
+
+        if not bytes then
+            return nil, err
+        end
+    end
+    return true, nil
+end
+
+
+local function _handle_continue(sock, body)
+    local status, version, reason, err = _receive_status(sock)
+    if not status then
+        return nil, nil, err
+    end
+
+    -- Only send body if we receive a 100 Continue
+    if status == 100 then
+        local ok, err = sock:receive("*l") -- Read carriage return
+        if not ok then
+            return nil, nil, err
+        end
+        _send_body(sock, body)
+    end
+    return status, version, err
+end
+
+
+function _M.send_request(self, params)
+    -- Apply defaults
+    setmetatable(params, { __index = DEFAULT_PARAMS })
+
+    local sock = self.sock
+    local body = params.body
+    local headers = http_headers.new()
+
+    local params_headers = params.headers
+    if params_headers then
+        -- We assign one by one so that the metatable can handle case insensitivity
+        -- for us. You can blame the spec for this inefficiency.
+        for k,v in pairs(params_headers) do
+            headers[k] = v
+        end
+    end
+
+    -- Ensure minimal headers are set
+    if type(body) == 'string' and not headers["Content-Length"] then
+        headers["Content-Length"] = #body
+    end
+    if not headers["Host"] then
+        if (str_sub(self.host, 1, 5) == "unix:") then
+            return nil, "Unable to generate a useful Host header for a unix domain socket. Please provide one."
+        end
+        -- If we have a port (i.e. not connected to a unix domain socket), and this
+        -- port is non-standard, append it to the Host heaer.
+        if self.port then
+            if self.ssl and self.port ~= 443 then
+                headers["Host"] = self.host .. ":" .. self.port
+            elseif not self.ssl and self.port ~= 80 then
+                headers["Host"] = self.host .. ":" .. self.port
+            else
+                headers["Host"] = self.host
+            end
+        else
+            headers["Host"] = self.host
+        end
+    end
+    if not headers["User-Agent"] then
+        headers["User-Agent"] = _M._USER_AGENT
+    end
+    if params.version == 1.0 and not headers["Connection"] then
+        headers["Connection"] = "Keep-Alive"
+    end
+
+    params.headers = headers
+
+    -- Format and send request
+    local req = _format_request(params)
+    ngx_log(ngx_DEBUG, "\n", req)
+    local bytes, err = sock:send(req)
+
+    if not bytes then
+        return nil, err
+    end
+
+    -- Send the request body, unless we expect: continue, in which case
+    -- we handle this as part of reading the response.
+    if headers["Expect"] ~= "100-continue" then
+        local ok, err, partial = _send_body(sock, body)
+        if not ok then
+            return nil, err, partial
+        end
+    end
+
+    return true
+end
+
+
+function _M.read_response(self, params)
+    local sock = self.sock
+
+    local status, version, reason, err
+
+    -- If we expect: continue, we need to handle this, sending the body if allowed.
+    -- If we don't get 100 back, then status is the actual status.
+    if params.headers["Expect"] == "100-continue" then
+        local _status, _version, _err = _handle_continue(sock, params.body)
+        if not _status then
+            return nil, _err
+        elseif _status ~= 100 then
+            status, version, err = _status, _version, _err
+        end
+    end
+
+    -- Just read the status as normal.
+    if not status then
+        status, version, reason, err = _receive_status(sock)
+        if not status then
+            return nil, err
+        end
+    end
+
+
+    local res_headers, err = _receive_headers(sock)
+    if not res_headers then
+        return nil, err
+    end
+
+    -- keepalive is true by default. Determine if this is correct or not.
+    local ok, connection = pcall(str_lower, res_headers["Connection"])
+    if ok then
+        if  (version == 1.1 and connection == "close") or
+            (version == 1.0 and connection ~= "keep-alive") then
+            self.keepalive = false
+        end
+    else
+        -- no connection header
+        if version == 1.0 then
+            self.keepalive = false
+        end
+    end
+
+    local body_reader = _no_body_reader
+    local trailer_reader, err = nil, nil
+    local has_body = false
+
+    -- Receive the body_reader
+    if _should_receive_body(params.method, status) then
+        local ok, encoding = pcall(str_lower, res_headers["Transfer-Encoding"])
+        if ok and version == 1.1 and encoding == "chunked" then
+            body_reader, err = _chunked_body_reader(sock)
+            has_body = true
+        else
+
+            local ok, length = pcall(tonumber, res_headers["Content-Length"])
+            if ok then
+                body_reader, err = _body_reader(sock, length)
+                has_body = true
+            end
+        end
+    end
+
+    if res_headers["Trailer"] then
+        trailer_reader, err = _trailer_reader(sock)
+    end
+
+    if err then
+        return nil, err
+    else
+        return {
+            status = status,
+            reason = reason,
+            headers = res_headers,
+            has_body = has_body,
+            body_reader = body_reader,
+            read_body = _read_body,
+            trailer_reader = trailer_reader,
+            read_trailers = _read_trailers,
+        }
+    end
+end
+
+
+function _M.request(self, params)
+    local res, err = self:send_request(params)
+    if not res then
+        return res, err
+    else
+        return self:read_response(params)
+    end
+end
+
+
+function _M.request_pipeline(self, requests)
+    for i, params in ipairs(requests) do
+        if params.headers and params.headers["Expect"] == "100-continue" then
+            return nil, "Cannot pipeline request specifying Expect: 100-continue"
+        end
+
+        local res, err = self:send_request(params)
+        if not res then
+            return res, err
+        end
+    end
+
+    local responses = {}
+    for i, params in ipairs(requests) do
+        responses[i] = setmetatable({
+            params = params,
+            response_read = false,
+        }, {
+            -- Read each actual response lazily, at the point the user tries
+            -- to access any of the fields.
+            __index = function(t, k)
+                local res, err
+                if t.response_read == false then
+                    res, err = _M.read_response(self, t.params)
+                    t.response_read = true
+
+                    if not res then
+                        ngx_log(ngx_ERR, err)
+                    else
+                        for rk, rv in pairs(res) do
+                            t[rk] = rv
+                        end
+                    end
+                end
+                return rawget(t, k)
+            end,
+        })
+    end
+    return responses
+end
+
+
+function _M.request_uri(self, uri, params)
+    if not params then params = {} end
+
+    local parsed_uri, err = self:parse_uri(uri)
+    if not parsed_uri then
+        return nil, err
+    end
+
+    local scheme, host, port, path = unpack(parsed_uri)
+    if not params.path then params.path = path end
+
+    local c, err = self:connect(host, port)
+    if not c then
+        return nil, err
+    end
+
+    if scheme == "https" then
+        local verify = true
+        if params.ssl_verify == false then
+            verify = false
+        end
+        local ok, err = self:ssl_handshake(nil, host, verify)
+        if not ok then
+            return nil, err
+        end
+    end
+
+    local res, err = self:request(params)
+    if not res then
+        return nil, err
+    end
+
+    local body, err = res:read_body()
+    if not body then
+        return nil, err
+    end
+
+    res.body = body
+
+    local ok, err = self:set_keepalive()
+    if not ok then
+        ngx_log(ngx_ERR, err)
+    end
+
+    return res, nil
+end
+
+
+function _M.get_client_body_reader(self, chunksize, sock)
+    local chunksize = chunksize or 65536
+    if not sock then
+        local ok, err
+        ok, sock, err = pcall(ngx_req_socket)
+
+        if not ok then
+            return nil, sock -- pcall err
+        end
+
+        if not sock then
+            if err == "no body" then
+                return nil
+            else
+                return nil, err
+            end
+        end
+    end
+
+    local headers = ngx_req_get_headers()
+    local length = headers.content_length
+    local encoding = headers.transfer_encoding
+    if length then
+        return _body_reader(sock, tonumber(length), chunksize)
+    elseif encoding and str_lower(encoding) == 'chunked' then
+        -- Not yet supported by ngx_lua but should just work...
+        return _chunked_body_reader(sock, chunksize)
+    else
+       return nil
+    end
+end
+
+
+function _M.proxy_request(self, chunksize)
+    return self:request{
+        method = ngx_req_get_method(),
+        path = ngx_re_gsub(ngx_var.uri, "\\s", "%20", "jo") .. ngx_var.is_args .. (ngx_var.query_string or ""),
+        body = self:get_client_body_reader(chunksize),
+        headers = ngx_req_get_headers(),
+    }
+end
+
+
+function _M.proxy_response(self, response, chunksize)
+    if not response then
+        ngx_log(ngx_ERR, "no response provided")
+        return
+    end
+
+    ngx.status = response.status
+
+    -- Filter out hop-by-hop headeres
+    for k,v in pairs(response.headers) do
+        if not HOP_BY_HOP_HEADERS[str_lower(k)] then
+            ngx.header[k] = v
+        end
+    end
+
+    local reader = response.body_reader
+    repeat
+        local chunk, err = reader(chunksize)
+        if err then
+            ngx_log(ngx_ERR, err)
+            break
+        end
+
+        if chunk then
+            local res, err = ngx.print(chunk)
+            if not res then
+                ngx_log(ngx_ERR, err)
+                break
+            end
+        end
+    until not chunk
+end
+
+
+return _M
diff --git a/msb-core/openresty-ext/src/assembly/resources/openresty/lualib/resty/http_headers.lua b/msb-core/openresty-ext/src/assembly/resources/openresty/lualib/resty/http_headers.lua
new file mode 100644 (file)
index 0000000..24b53b5
--- /dev/null
@@ -0,0 +1,62 @@
+local   rawget, rawset, setmetatable =
+        rawget, rawset, setmetatable
+
+local str_gsub = string.gsub
+local str_lower = string.lower
+
+
+local _M = {
+    _VERSION = '0.01',
+}
+
+
+-- Returns an empty headers table with internalised case normalisation.
+-- Supports the same cases as in ngx_lua:
+--
+-- headers.content_length
+-- headers["content-length"]
+-- headers["Content-Length"]
+function _M.new(self)
+    local mt = { 
+        normalised = {},
+    }
+
+
+    mt.__index = function(t, k)
+        local k_hyphened = str_gsub(k, "_", "-")
+        local matched = rawget(t, k)
+        if matched then
+            return matched
+        else
+            local k_normalised = str_lower(k_hyphened)
+            return rawget(t, mt.normalised[k_normalised])
+        end
+    end
+
+
+    -- First check the normalised table. If there's no match (first time) add an entry for
+    -- our current case in the normalised table. This is to preserve the human (prettier) case
+    -- instead of outputting lowercased header names.
+    --
+    -- If there's a match, we're being updated, just with a different case for the key. We use
+    -- the normalised table to give us the original key, and perorm a rawset().
+    mt.__newindex = function(t, k, v)
+        -- we support underscore syntax, so always hyphenate.
+        local k_hyphened = str_gsub(k, "_", "-")
+
+        -- lowercase hyphenated is "normalised"
+        local k_normalised = str_lower(k_hyphened)
+
+        if not mt.normalised[k_normalised] then
+            mt.normalised[k_normalised] = k_hyphened
+            rawset(t, k_hyphened, v)
+        else
+            rawset(t, mt.normalised[k_normalised], v)
+        end
+    end
+
+    return setmetatable({}, mt)
+end
+
+
+return _M
index a1fecf2..101679d 100644 (file)
---[[
+-- Copyright 2016 Huawei Technologies Co., Ltd.
 
-    Copyright 2016 2015-2016 ZTE, Inc. and others. All rights reserved.
+-- Licensed 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
 
-    Licensed 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
 
-        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.
+auth_url = '/openoapi/auth/v1';
+auth_token_url = auth_url..'/tokens';
+auth_token_key = "X-Auth-Token";
+redirect_url = "/openoui/auth/v1/login/html/login.html"
 
-    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.
+white_list= {
+  auth_token_url,
+  redirect_url,
+  '/openoui/auth/v1/login/'
+};
 
-        Author: Zhaoxing Meng
-        email: meng.zhaoxing1@zte.com.cn
+function verify_value(value)
+  if (nil == value or 0 == #value)
+  then
+    return false;
+  else
+    return true;
+  end
+end
+
+--[[checks str2 starts with str1]]--
+function starts_with(str1, str2)
+  return string.sub(str2, 1, string.len(str1)) == str1;
+end
+
+--  Check and ignore the request if it is from auth module.--
+function is_white_list(url)
+  for i, value in ipairs(white_list)
+  do
+    if (starts_with(value, url))
+      then
+        return true;
+      end
+  end
+  return false;
+end
+
+-- Check and ignore the request if it is from auth module.
+-- function is_auth_request(url)
+  
+--   return string.sub(url, 1, string.len(auth_url)) == auth_url;
+-- end
+
+function set_header(tokens)
+  for key,value in pairs(tokens)
+  do
+    ngx.log (ngx.ERR, "Headers: ", key, value);
+    ngx.req.set_header(key, value);
+  end
+
+end
+--[[ validates the token with auth ]]--
+function validate_token(tokens)
+  -- auth expects the token in header.
+  set_header(tokens);
+  -- call auth token check url to validate.
+  local res = ngx.location.capture(auth_token_url, { method = ngx.HTTP_HEAD});
+  ngx.log (ngx.ERR, "Auth Result:", res.status);
+  if (nil == res)
+  then
+    return false;
+  end
+  return (ngx.HTTP_OK == res.status);
+end
+
+--[[ get auth token from cookies ]]--
+function get_cookies()
+  local cookie_name = "cookie_"..auth_token_key;
+  local auth_token = ngx.var[cookie_name];
+  local tokens = {};
+  -- verify whether its empty or null.
+  if (verify_value(auth_token))
+  then
+  ngx.log(ngx.ERR, "token : ", auth_token );
+    tokens[auth_token_key] = auth_token;
+  end
+  return tokens;
+end
+
+function get_service_url()
+  -- get host.
+  local host = ngx.var.host;
+  --get port
+  local port = ":"..ngx.var.server_port;
+  local proto = "";
+  --get protocol
+  if (ngx.var.https == "on")
+  then
+    proto = "https://";
+  else
+    proto = "http://";
+  end
+  --get url
+  local uri = ngx.var.rui;
+  --form complete service url.
+  --local complete_url = proto..host..port..url
+  local complete_url = uri;
+  local service = "?service="
+  --add arguments if any.
+  if ngx.var.args ~= nil
+  then
+    complete_url = complete_url.."?"..ngx.var.args;
+  end
+  ngx.log(ngx.ERR, "service url : ", complete_url);
+  return service..ngx.escape_uri(complete_url);
+end
 
-]]
-local _M = {}
-_M._VERSION = '1.0.0'
+function redirect(url)
+  local service = get_service_url();
+  ngx.log(ngx.ERR, "redirect: ", url..service);
+  ngx.redirect(url..service);
+end
+
+ngx.log(ngx.ERR, "==============start check token===============: ");
+local url = ngx.var.uri;
+ngx.log(ngx.ERR, "Url : ", url);
 
-function _M.access()
-       --add your own code here
-       ngx.log(ngx.INFO, "running auth plugin")
+-- ignore token validation if auth request.
+if (is_white_list(url))
+then
+  return;
 end
 
-return _M
\ No newline at end of file
+
+
+-- get auth token from cookies.
+local auth_tokens = get_cookies();
+
+-- check if auth token is empty,
+-- redirect it to login page in that case.
+if (nil == next(auth_tokens))
+then
+  ngx.log(ngx.ERR, "Token Invalidate, redirect to ", redirect_url);
+  redirect(redirect_url);
+  return;
+end
+
+-- validate the token with auth module.
+-- continue if success, else redirect to login page.
+if(validate_token(auth_tokens))
+then
+  ngx.log(ngx.ERR, "Token Validate.");
+  return;
+else
+  redirect(redirect_url);
+end
index a53ec21..1a30ff6 100644 (file)
---[[
+-- Copyright 2016 Huawei Technologies Co., Ltd.
 
-    Copyright 2016 2015-2016 ZTE, Inc. and others. All rights reserved.
+-- Licensed 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
 
-    Licensed 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
 
-        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 _HEADER = "X-Driver-Parameter"
 
-    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.
+--extract driver header if present in request
+function get_driver_header()
+  local header = ""
+  local driver_header = ngx.req.get_headers()[_HEADER]  
+  if (driver_header ~= nil)
+  then
+    header = driver_header
+  end
+  return header
+end
 
-        Author: Zhaoxing Meng
-        email: meng.zhaoxing1@zte.com.cn
+-- generate query url
+function get_query_url(x_driver_header)
+  local drivermgr_uri = '/openoapi/drivermgr/v1/drivers'
+  local url = drivermgr_uri.."?".._HEADER.."="..tostring(ngx.escape_uri(x_driver_header)).."&service_url="..ngx.var.uri
+  return url
+end
 
-]]
-local _M = {}
-_M._VERSION = '1.0.0'
+-- generate driver url
+function get_driver_url(driver_header)
+  local cjson = require "cjson"
+  local query_url = get_query_url(driver_header)
+  local res = ngx.location.capture(query_url, { method = ngx.HTTP_GET})
+  ngx.log (ngx.ERR, "Driver manager resp url : ", tostring(res.body))
+  if (res.status == 200 and res.body ~= nil and res.body ~= '')
+  then
+    return tostring(cjson.new().decode(res.body).url)
+  else
+    return ''
+  end
+end
 
-function _M.access()
-       ngx.log(ngx.INFO, "running driver_manager plugin")
-       --add your own code here
-       --choose the right backend server,and then tell nginx, e.g. ngx.var.backend = XX.XX.XX.XX:8888
+-- get headers
+function get_headers()
+  local headers = {}
+  local h = ngx.req.get_headers()
+  for k, value in pairs(h)
+  do
+     headers[k] = value
+  end
+  return headers
 end
 
-return _M
\ No newline at end of file
+function get_body_params()
+  ngx.req.read_body()
+  local actual_body = ""  
+  local body_param = ngx.req.get_body_data()
+  if(body_param ~= nil)
+  then
+    actual_body = tostring(body_param)
+  end
+  return actual_body
+end
+
+
+
+ngx.log(ngx.INFO, "DRIVER MANAGER LUA", "***********************")
+
+-- extract X-Driver-Parameter header param
+local driver_header = get_driver_header()
+ngx.log(ngx.ERR, "X-Driver-Parameter: ", driver_header)
+
+
+-- ignore driver redirection if not driver manager request.
+if (driver_header ~= "")
+then 
+  
+  local driver_url = get_driver_url(driver_header)
+  ngx.log (ngx.ERR, "Driver manager URl:: ", driver_url)
+  local http = require "resty.http"
+  local actual_headers = get_headers()
+  local actual_body = get_body_params()
+
+  ngx.log(ngx.ERR, "HTTP request to driver... ", " Request to driver manager")
+  local res, err = http.new():request_uri(driver_url, {
+        method = ngx.req.get_method(),
+        body = actual_body,
+        headers = actual_headers
+      })
+
+      if not res then
+        ngx.say("Request to driver failed : ", err)
+        return
+      end
+ ngx.log(ngx.ERR, "Response from driver : ", tostring(res.body))
+ ngx.say(res.body)
+
+else
+  ngx.log(ngx.ERR, "X-Driver-Parameter not present", " Redirect to same url")
+end
\ No newline at end of file