-
Notifications
You must be signed in to change notification settings - Fork 25.6k
[Kerberos] Add support for list of auth challenge #31594
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
[Kerberos] Add support for list of auth challenge #31594
Conversation
Till now we had support for 'Basic', 'Bearer' auth schemes and this was sufficient for us to reply `WWW-Authenticate` header with one value either for `Basic` or `Bearer` for unauthorized access. After introducing Kerberos we will be supporting `Negotiate` scheme. As per [RFC7235](https://tools.ietf.org/html/rfc7235#section-4.1), we may respond with the list of challenges. This list is of auth schemes supported by the server. We can also have custom Realms defining their own response header value for 'WWW-Authenticate' header. This commit introduces a `getWWWAuthenticateHeaderValue` in `Realm` to identify the scheme which it wants to use. By default it uses 'Basic' auth scheme. This can be overriden by realms like KerberosRealm to specify 'Negotiate' scheme or OAuth to specify 'Bearer' or custom realms added by security extensions to specify their own scheme. SAML specifications do not specify anything related to the header but unofficially many have used 'SAML' as auth scheme or used 'Bearer' auth scheme for passing SAML tokens. But most of the realms would use the existing schemes like 'Basic', 'Digest', 'Bearer', 'Negotiate' etc. At the startup, `Security#createComponents` will take care of creating `DefaultAuthenticationFailureHandler` with default response header values for 'WWW-Authenticate' as a list of configured and enabled auth schemes.
|
Pinging @elastic/es-security |
| * @deprecated @see {@link #DefaultAuthenticationFailureHandler(List)} | ||
| */ | ||
| @Deprecated | ||
| public DefaultAuthenticationFailureHandler() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This deprecated default constructor is added to not break security extensions.
As Realms can return empty list due to license restriction adding default 'Basic' scheme to the authentication failure handler header value. Refactoring to create authentication failure handler in extracted method.
| * | ||
| * @return value to be returned in 'WWW-Authenticate' response header. | ||
| */ | ||
| public String getWWWAuthenticateHeaderValue() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know I normally lean towards "just build what you need", but this method feels way too specific to me.
Did you consider a getAuthenticationFailureHeaders() method instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the suggestion yes, you right it's too specific and I also felt it should return a List of supported schemes. Usually, the authentication failure response headers will be populated in the ElasticsearchSecurityException and the method name you suggested might confuse. How about getSupportedAuthenticateChallenges instead? or any other suggestion. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you consider a getAuthenticationFailureHeaders() method instead?
+1. I feel like this is the way to go. Ultimately this might allow us to remove the authentication failure handler (way off low priority future idea)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, are we thinking of letting the realms drive everything? Because I do see the value in it. Current flow makes us look at the code all over to see where the exception was populated whether it was populated with right headers, that too outside the realm if not then add those headers. I will make it a generic name as suggested. But would like to know more on what other headers do you foresee that needs to be sent and might be the realm driven?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes sense to let the realms handle this.
I don't know what other headers we could expect - but that's kind of the point, we can just support a relatively generic method and let custom realms do whatever they need. My guess is that anything other than WWW-Authenticate would be due to weird proprietary protocols, but if they exist then we can support them.
0c24b1a to
435d19c
Compare
jaymode
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left some minor comments. Otherwise this change LGTM
| */ | ||
| public DefaultAuthenticationFailureHandler(Map<String, List<String>> failureResponseHeaders) { | ||
| if (failureResponseHeaders == null || failureResponseHeaders.isEmpty()) { | ||
| failureResponseHeaders = new HashMap<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just use Collections.singletonMap
| * Creates an instance of {@link ElasticsearchSecurityException} with | ||
| * {@link RestStatus#UNAUTHORIZED} status. | ||
| * <p> | ||
| * Also adds response headers as configured |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
complete the thought, configured where?
| */ | ||
| public Map<String, List<String>> getAuthenticationFailureHeaders() { | ||
| final Map<String, List<String>> headers = new HashMap<>(); | ||
| headers.put("WWW-Authenticate", Arrays.asList("Basic realm=\"" + XPackField.SECURITY + "\" charset=\"UTF-8\"")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use Collections.singletonMap here and Collections.singletonList
Till now we had support for 'Basic', 'Bearer' auth schemes and
this was sufficient for us to reply
WWW-Authenticateheaderwith one value either for
BasicorBearerfor unauthorizedaccess.
After introducing Kerberos we will be supporting
Negotiatescheme.As per RFC7235,
we may respond with the list of challenges. This list is of auth
schemes supported by the server. We can also have custom Realms
defining their own response header value for 'WWW-Authenticate'
header. This commit introduces a
getWWWAuthenticateHeaderValuein
Realmto identify the scheme which it wants to use. By default,it uses 'Basic' auth scheme. This can be overridden
by realms like KerberosRealm to specify 'Negotiate' scheme or OAuth
to specify 'Bearer' or custom realms added by security extensions to
specify their own scheme.
SAML specifications do not specify anything related to the header but
unofficially many have used 'SAML' as auth scheme or used 'Bearer'
auth scheme for passing SAML tokens.
But most of the realms would use the existing schemes
like 'Basic', 'Digest', 'Bearer', 'Negotiate' etc.
At the startup,
Security#createComponentswill take care ofcreating
DefaultAuthenticationFailureHandlerwith defaultresponse header values for 'WWW-Authenticate' as a list of configured
and enabled auth schemes.