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

feat: add cas-auth plugin #7932

Merged
merged 12 commits into from
Sep 22, 2022
Merged

feat: add cas-auth plugin #7932

merged 12 commits into from
Sep 22, 2022

Conversation

kingluo
Copy link
Contributor

@kingluo kingluo commented Sep 16, 2022

Description

Implement cas-auth plugin

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible (If not, please discuss on the APISIX mailing list first)
@spacewander
Copy link
Member

Please make the CI pass, thanks!

@@ -97,6 +97,10 @@ jobs:
rm -rf $(ls -1 --ignore=*.tgz --ignore=ci --ignore=t --ignore=utils --ignore=.github)
tar zxvf ${{ steps.branch_env.outputs.fullname }}

- name: download keycloak cas provider
run: |
sudo wget https://github.com/jacekkow/keycloak-protocol-cas/releases/download/18.0.2/keycloak-protocol-cas-18.0.2.jar -O /opt/keycloak-protocol-cas-18.0.2.jar
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@spacewander No, that scirpt runs after docker compose, but this download file must be set as volume in docker compose file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kingluo
What about moving it into Start CI env (PLUGIN_TEST)?

end

local function uri_without_ticket(conf)
return ngx.var.scheme .. "://" .. ngx.var.host .. ":" ..
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use ctx.var instead of ngx.var?

store:delete(session_id)
set_our_cookie(COOKIE_NAME, "deleted; Max-Age=0")

ngx.redirect(conf.idp_uri .. "/logout")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ngx.redirect works like ngx.exit. As we avoid ngx.exit, we prefer to do it by ourselves, see

core.response.set_header("Location", new_uri)

end

local function set_cookie(cookie_str)
local h = to_table(ngx.header['Set-Cookie'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use core.response.add_header if we don't check if the same cookie exists?

local function first_access(conf)
local login_uri = conf.idp_uri .. "/login?" ..
ngx.encode_args({ service = uri_without_ticket(conf) })
ngx.log(ngx.INFO, "first access: ", login_uri,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use core.log

"/serviceValidate", { query = { ticket = ticket, service = uri_without_ticket(conf) } })

if res and res.status == ngx.HTTP_OK and res.body ~= nil then
if string.find(res.body, "<cas:authenticationSuccess>") then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use core.string

return m[1]
end
else
ngx.log(ngx.INFO, "CAS serviceValidate failed: " .. res.body)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"CAS serviceValidate failed: ", res.body is enough

end

function _M.access(conf, ctx)
local method = ngx.req.get_method()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
local method = ngx.req.get_method()
local method = core.request.get_method()
Comment on lines 162 to 164
if method == "GET" and uri == conf.logout_uri then
return logout(conf, ctx)
elseif method == "POST" and uri == conf.cas_callback_uri then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if method == "GET" and uri == conf.logout_uri then
return logout(conf, ctx)
elseif method == "POST" and uri == conf.cas_callback_uri then
if method == "GET" and uri == conf.logout_uri then
return logout(conf, ctx)
end
if method == "POST" and uri == conf.cas_callback_uri then

is ok?

Comment on lines 165 to 166
ngx.req.read_body()
local data = ngx.req.get_body_data()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use core.request.get_body()

Comment on lines 99 to 106
if err == "no memory" then
core.log.emerg("CAS cookie store is out of memory")
elseif err == "exists" then
core.log.error("Same CAS ticket validated twice, this should never happen!")
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log the origin err?

}
}
}'
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add the process of how to start and configure IdP, as well as show some key images.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that should be left to blog. I would link the blog into the doc later.


if res and res.status == ngx.HTTP_OK and res.body ~= nil then
if core.string.find(res.body, "<cas:authenticationSuccess>") then
local m = ngx_re_match(res.body, "<cas:user>(.*?)</cas:user>");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing jo in the re match?

core.log.info("CAS serviceValidate failed: ", res.body)
end
else
core.log.error("validate ticket failed: res=", res, ", err=", err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may cause an error if res.status ~= ngx.HTTP_OK?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only if res and res.status == ngx.HTTP_OK and res.body ~= nil, the validate process is successful. Otherwise, log the res and err.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kingluo
Yes, but if res is not nil, will it raise an error when logging a table directly?

tzssangglass
tzssangglass previously approved these changes Sep 20, 2022
@spacewander
Copy link
Member

Please address #7932 (comment)

@spacewander
Copy link
Member

Before we can merge it, what is your idea about #7932 (comment)?

tzssangglass
tzssangglass previously approved these changes Sep 22, 2022
@spacewander spacewander merged commit 987f7be into apache:master Sep 22, 2022
Liu-Junlin pushed a commit to Liu-Junlin/apisix that referenced this pull request Nov 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
3 participants