Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: implemented openid-connect plugin. #447

Merged
merged 12 commits into from
Aug 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions COPYRIGHT
Original file line number Diff line number Diff line change
Expand Up @@ -361,4 +361,68 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


%%%%%%%%%

lua-resty-http
https://github.com/ledgetech/lua-resty-http

BSD 2-Clause "Simplified" License

Copyright (c) 2013, James Hurst
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


%%%%%%%%%

lua-resty-openidc
https://github.com/zmartzone/lua-resty-openidc

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

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.


%%%%%%%%%
kong-oidc
https://github.com/nokia/kong-oidc

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

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.
5 changes: 5 additions & 0 deletions bin/apisix
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ http {
lua_shared_dict upstream-healthcheck 10m;
lua_shared_dict worker-events 10m;

# for openid-connect plugin
lua_shared_dict discovery 1m; # cache for discovery metadata documents
lua_shared_dict jwks 1m; # cache for JWKs
lua_shared_dict introspection 10m; # cache for JWT verification results

lua_ssl_verify_depth 5;
ssl_session_timeout 86400;

Expand Down
1 change: 1 addition & 0 deletions conf/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ plugins: # plugin list
- grpc-transcode
- serverless-pre-function
- serverless-post-function
- openid-connect
5 changes: 5 additions & 0 deletions conf/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ http {
lua_shared_dict upstream-healthcheck 10m;
lua_shared_dict worker-events 10m;

# for openid-connect plugin
lua_shared_dict discovery 1m; # cache for discovery metadata documents
lua_shared_dict jwks 1m; # cache for JWKs
lua_shared_dict introspection 10m; # cache for JWT verification results

lua_ssl_verify_depth 5;
ssl_session_timeout 86400;

Expand Down
152 changes: 152 additions & 0 deletions lua/apisix/plugins/openid-connect.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
local core = require("apisix.core")
local ngx_re = require("ngx.re")
local openidc = require("resty.openidc")
local ngx = ngx
local ngx_encode_base64 = ngx.encode_base64

local plugin_name = "openid-connect"


local schema = {
type = "object",
properties = {
client_id = {type = "string"},
client_secret = {type = "string"},
discovery = {type = "string"},
scope = {type = "string"},
ssl_verify = {type = "boolean"}, -- default is false
timeout = {type = "integer", minimum = 1}, --default is 3 seconds
introspection_endpoint = {type = "string"}, --default is nil
--default is client_secret_basic
introspection_endpoint_auth_method = {type = "string"},
bearer_only = {type = "boolean"}, -- default is false
realm = {type = "string"}, -- default is apisix
logout_path = {type = "string"}, -- default is /logout
redirect_uri = {type = "string"}, -- default is ngx.var.request_uri
},
required = {"client_id", "client_secret", "discovery"}
}


local _M = {
version = 0.1,
priority = 2599,
name = plugin_name,
schema = schema,
}

function _M.check_schema(conf)
local ok, err = core.schema.check(schema, conf)
if not ok then
return false, err
end

if not conf.scope then
conf.scope = "openid"
end
if not conf.ssl_verify then
conf.ssl_verify = "no"
end
if not conf.timeout then
conf.timeout = 3
end
conf.timeout = conf.timeout * 1000
if not conf.introspection_endpoint_auth_method then
conf.introspection_endpoint_auth_method = 'client_secret_basic'
end
if not conf.bearer_only then
conf.bearer_only = false
end
if not conf.realm then
conf.realm = 'apisix'
end
if not conf.logout_path then
conf.logout_path = '/logout'
end

return true
end


local function has_bearer_access_token(ctx)
local auth_header = core.request.header(ctx, "Authorization")
if not auth_header then
return false
end

local res, err = ngx_re.split(auth_header, " ", nil, nil, 2)
if not res then
return false, err
end

if res[1] == "bearer" then
return true
end

return false
end


local function introspect(ctx, conf)
if has_bearer_access_token(ctx) or conf.bearer_only then
local res, err = openidc.introspect(conf)
if res then
return res
end
if conf.bearer_only then
ngx.header["WWW-Authenticate"] = 'Bearer realm="' .. conf.realm .. '",error="' .. err .. '"'
return ngx.HTTP_UNAUTHORIZED, err
end
end

return nil
end


local function add_user_header(user)
local userinfo = core.json.encode(user)
ngx.req.set_header("X-Userinfo", ngx_encode_base64(userinfo))
end


function _M.access(conf, ctx)
if not conf.redirect_uri then
conf.redirect_uri = ctx.var.request_uri
end

local response, err
if conf.introspection_endpoint then
response, err = introspect(ctx, conf)
if err then
core.log.error("failed to introspect in openidc: ", err)
return response
end
if response then
add_user_header(response)
end
end

if not response then
local response, err = openidc.authenticate(conf)
if err then
core.log.error("failed to authenticate in openidc: ", err)
return 500
end

if response then
if response.user then
add_user_header(response.user)
end
if response.access_token then
ngx.req.set_header("X-Access-Token", response.access_token)
end
if response.id_token then
local token = core.json.encode(response.id_token)
ngx.req.set_header("X-ID-Token", ngx.encode_base64(token))
end
end
end
end


return _M
1 change: 1 addition & 0 deletions rockspec/apisix-dev-1.0-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dependencies = {
"lua-resty-radixtree = 0.5",
"lua-resty-iputils = 0.3.0-1",
"lua-protobuf = 0.3.1",
"lua-resty-openidc = 1.7.2-1",
}

build = {
Expand Down
2 changes: 1 addition & 1 deletion t/admin/plugins.t
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ __DATA__
--- request
GET /apisix/admin/plugins/list
--- response_body_like eval
qr/\["limit-req","limit-count","limit-conn","key-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function"\]/
qr/\["limit-req","limit-count","limit-conn","key-auth","prometheus","node-status","jwt-auth","zipkin","ip-restriction","grpc-transcode","serverless-pre-function","serverless-post-function","openid-connect"\]/
--- no_error_log
[error]
1 change: 1 addition & 0 deletions t/debug-mode.t
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ qr/loaded plugin and sort by priority: [-\d]+ name: [\w-]+/
--- grep_error_log_out
loaded plugin and sort by priority: 10000 name: serverless-pre-function
loaded plugin and sort by priority: 3000 name: ip-restriction
loaded plugin and sort by priority: 2599 name: openid-connect
loaded plugin and sort by priority: 2510 name: jwt-auth
loaded plugin and sort by priority: 2500 name: key-auth
loaded plugin and sort by priority: 1003 name: limit-conn
Expand Down
Loading