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(cas-auth): support logged-in user header #11445

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

lucasarnulphy
Copy link

@lucasarnulphy lucasarnulphy commented Jul 29, 2024

Description

The cas-auth plugin is great, but does not currently support retrieving the logged-in user from upstreams, making it really hard to do any kind of access control appart from "a user is logged-in".

This PR adds the set_user_header and user_header attributes that enables setting the logged-in user in a header, and allows for the header's name customization.

Some users have already asked for it.

As far as backward compatibility is concerned: The header is set by default, so one might experience issues if setting the header before reaching apisix... which would make little sense considering apisix handles the authentication.

Fixes #9524.

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)

@zhoujiexiong
Copy link
Contributor

@lucasarnulphy

Do we need to consider using a general method that can forward more info that returned from CAS to upstream, for extensibility purpose?

And test cases needed? :D

@lucasarnulphy
Copy link
Author

lucasarnulphy commented Jul 30, 2024

@zhoujiexiong

I think you might be right about returning more info, but I'm not sure it should be exclusive.

Many systems just read a single header with a username and then build all permissions on that. Returning a lot of information in a single header would make that harder to implement.

I do agree it would be great for the upstreams to have more information, maybe as a UserInfo header as it is done in the openid connect plugin, I'll probably implement that next.

As far as tests are concerned... it's only a few lines of codes to return a variable that was already stored and tested before, so I think we're in the clear... but I'll let you be the judge of that.

@@ -87,6 +89,9 @@ local function with_session_id(conf, ctx, session_id)
else
-- refresh the TTL
store:set(session_id, user, SESSION_LIFETIME)
if conf.set_user_header then
Copy link
Contributor

Choose a reason for hiding this comment

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

the set_user_header field is not needed, this feature can be implemented using the user_header field alone. Also please choose a better name to allow any header to be passed.

eg: field name: send_headers and the type of this field should be array, to allow multiple headers to be sent.

Copy link
Author

Choose a reason for hiding this comment

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

I'm fine with removing set_user_header, and having user_header empty by default.

As far as send_headers is concerned, I'm not sure I understand what you mean.
Do you mean allowing the plugin to put in a header any value from the cas response ? Because that would require a lot more work as currently only the user is stored.
Or do you mean having a general array which we can search in in the code when other headers are implemented ? because that would remove the ability to overwrite the headers names, which would make it painful to integrate with some apps.

Copy link
Contributor

Choose a reason for hiding this comment

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

What about the hash/mapping way as following:

{
    "XPATH_such_as: /auth/user/node": "X-Forwarded-User", // could be the default setting
    "other_xpath_node_to_extract_value": "X-Forwarded-Foo" 
}

Some related Lua libs:

Copy link
Contributor

Choose a reason for hiding this comment

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

Because that would require a lot more work as currently only the user is stored.

Why would it require a lot more work? I don't understand you. If any of the headers configured in send_headers is not present in the request then the plugin won't add it. Isn't this simple?

Copy link
Author

Choose a reason for hiding this comment

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

@shreemaan-abhishek I still don't understand what you mean.

For this part:

the set_user_header field is not needed, this feature can be implemented using the user_header field alone. Also please choose a better name to allow any header to be passed.

I agree.

But for this part:

Why would it require a lot more work? I don't understand you. If any of the headers configured in send_headers is not present in the request then the plugin won't add it. Isn't this simple?

I have no understanding of what you mean. If send_headers is not present in which request ? The CAS response ?

I feel like we're not talking about the same thing. The goal of this change is to allow an upstream service to retrieve a value already stored: the username of the authenticated user.

Yes it could be made more generic, by storing more values from the cas response body:

ngx_re_match(res.body, "cas:user(.*?)</cas:user>", "jo");

But it's currently an issue for many users, and it can be improved afterwards to allow for any value for the response.

Other authentication plugins on Apisix have a user_header parameter to pass the authenticated user to upstream services, why does this have to be different ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Other authentication plugins on Apisix have a user_header parameter to pass the authenticated user to upstream services, why does this have to be different ?

can you show an example?

Copy link
Contributor

Choose a reason for hiding this comment

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

never mind, I understood what you are trying to do.

I'm fine with removing set_user_header, and having user_header empty by default.

please push this change then we can resolve this conversation.

Copy link
Author

Choose a reason for hiding this comment

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

@zhoujiexiong
Copy link
Contributor

Ping @lucasarnulphy :D

@lucasarnulphy
Copy link
Author

Ping @lucasarnulphy :D

I'd be happy to implement that, but I'm waiting for @shreemaan-abhishek to confirm that it would be acceptable, as I have no intention to implement a change that would later be rejected again.

@zhoujiexiong
Copy link
Contributor

Ping @lucasarnulphy :D

I'd be happy to implement that, but I'm waiting for @shreemaan-abhishek to confirm that it would be acceptable, as I have no intention to implement a change that would later be rejected again.

@shreemaan-abhishek We need you. :-)

@dosubot dosubot bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Sep 5, 2024
Copy link
Contributor

@shreemaan-abhishek shreemaan-abhishek left a comment

Choose a reason for hiding this comment

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

could you please add test cases as well? Thanks for your cooperation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size:S This PR changes 10-29 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

help request: how can i get the user from cas-auth
3 participants