I have updated the PR and KIP to address the comments made so far. Please take another look at them and share your thoughts. KIP: https://cwiki.apache.org/confluence/display/KAFKA/KIP-342%3A+Add+support+for+Custom+SASL+extensions+in+OAuthBearer+authentication PR: Pull request <https://github.com/apache/kafka/pull/5379>
Best, Stanislav On Thu, Jul 19, 2018 at 1:58 PM Stanislav Kozlovski <stanis...@confluent.io> wrote: > Hi Ron, > > Agreed. `SaslExtensionsCallback` will be the only public API addition and > new documentation for the extension strings. > A question that came up - should the LoginCallbackHandler throw an > exception or simply ignore key/value extension pairs who do not match the > validation regex pattern? I guess it would be better to throw, as to avoid > confusion. > > And yes, I will make sure the key/value are validated on the client as > well as in the server. Even then, I structured the getNegotiatedProperty() > method such that the OAUTHBEARER.token can never be overridden. I > considered adding a test for that, but I figured having the regex > validation be enough of a guarantee. > > On Thu, Jul 19, 2018 at 9:49 AM Ron Dagostino <rndg...@gmail.com> wrote: > >> Hi Rajini and Stanislav. Rajini, yes, I think you are right about the >> login callback handler being more appropriate for retrieving the SASL >> extensions than the login module itself (how many times am I going to have >> to be encouraged to leverage the callback handlers?!? lol). >> OAuthBearerLoginModule should ask its login callback handler to handle an >> instance of SaslExtensionsCallback in addition to an instance of >> OAuthBearerTokenCallback, and the default login callback handler >> implementation (OAuthBearerUnsecuredLoginCallbackHandler) should either >> return an empty map via callback or it should recognize additional JAAS >> module options of the form unsecuredLoginExtension_<extensionName>=value >> so >> that arbitrary extensions can be added in development and test scenarios >> (similar to how arbitrary claims on unsecured tokens can be created in >> those scenarios via the JAAS module options >> unsecuredLoginStringClaim_<claimName>=value, etc.). Then the >> OAuthBearerLoginModule can add a map of any extensions to the Subject's >> public credentials where the default SASL client callback handler class ( >> OAuthBearerSaslClientCallbackHandler) can be amended to support >> SaslExtensionsCallback and look on the Subject accordingly. There would >> be >> no need to implement a custom sasl.client.callback.handler.class in this >> case, and no logic would need to be moved to a public static method on >> OAuthBearerLoginModule as I had proposed (at least not right now, anyway >> -- >> there may come a time when a need for a custom >> sasl.client.callback.handler.class is identified, and at that point the >> default implementation would either have to made part of the public API >> with protected rather than private methods so it could be directly >> extended >> or its logic would have to be moved to public static methods on >> OAuthBearerLoginModule). >> >> So, to try to summarize, I think SaslExtensionsCallback will be the only >> public API addition due to this KIP in terms of code, and then maybe the >> recognition of the unsecuredLoginExtension_<extensionName>=value module >> options in the default unsecured case (which would be a documentation >> change and an internal implementation issue rather than a public API in >> terms of code). And then also the fact that extension names and values >> are >> accessed on the server side via negotiated properties. Do I have that >> summary right? >> >> One thing I want to note is that the code needs to make sure the extension >> names are composed of only ALPHA [a-zA-Z] characters as per the spec (not >> only for that reason, but to also make sure the token available at the >> OAUTHBEARER.token negotiated property can't be overwritten). >> >> Ron >> >> On Thu, Jul 19, 2018 at 12:43 PM Stanislav Kozlovski < >> stanis...@confluent.io> >> wrote: >> >> > Hey Ron, >> > >> > Come to think of it, I think what Rajini said makes more sense than my >> > initial proposal. Having the OAuthBearerClientCallbackHandler populate >> > SaslExtensionsCallback by taking a Map from the Subject would ease >> users' >> > implementation - they'd only have to provide a login callback handler >> which >> > attaches extensions to the Subject. >> > I will now update the PR and the examples in the KIP. Let me know what >> you >> > think >> > >> > Hi Rajini, >> > Yes, I will switch both classes to private/public as it makes total >> sense. >> > >> > Best, >> > Stanislav >> > On Thu, Jul 19, 2018 at 9:02 AM Rajini Sivaram <rajinisiva...@gmail.com >> > >> > wrote: >> > >> > > Hi Stanislav, >> > > >> > > Thanks for the KIP. Since SaslExtensions will be an internal class, >> can >> > we >> > > remove it from the KIP to avoid confusion? Also, can we add the >> package >> > > name for SaslExtensionsCallback? The PR has it in >> > > org.apache.kafka.common.security which is an internal package. As a >> > public >> > > class, it could be in org.apache.kafka.common.security.auth. >> > > >> > > Regards, >> > > >> > > Rajini >> > > >> > > On Thu, Jul 19, 2018 at 4:50 PM, Rajini Sivaram < >> rajinisiva...@gmail.com >> > > >> > > wrote: >> > > >> > > > Hi Ron, >> > > > >> > > > Is there a reason why wouldn't want to provide extensions using a >> login >> > > > callback handler in the same way as we inject tokens? The easiest >> way >> > to >> > > > inject custom extensions would be using the JAAS config. So we could >> > have >> > > > both OAuthBearerTokenCallback and SaslExtensionsCallback processed >> by >> > a >> > > > login callback handler. And the map returned by >> SaslExtensionsCallback >> > > > could be added to Subject by the default >> > > OAuthBearerSaslClientCallbackHandler. >> > > > Since OAuth users have to provide a login callback handler anyway, >> > > wouldn't >> > > > it be a better fit? >> > > > >> > > > Thank you, >> > > > >> > > > Rajini >> > > > >> > > > >> > > > On Thu, Jul 19, 2018 at 4:08 PM, Ron Dagostino <rndg...@gmail.com> >> > > wrote: >> > > > >> > > >> Hi Stanislav. >> > > >> >> > > >> Implementers of a custom sasl.client.callback.handler.class must be >> > sure >> > > >> to >> > > >> provide the existing logic in >> > > >> org.apache.kafka.common.security.oauthbearer.internals.OAuth >> > > >> BearerSaslClientCallbackHandler >> > > >> that handles instances of OAuthBearerTokenCallback (by retrieving >> the >> > > >> private credential from the Subject); a custom implementation that >> > fails >> > > >> to >> > > >> do this will not work, so the KIP should state this requirement. >> > > >> >> > > >> The question then arises: how should implementers provide the >> existing >> > > >> logic in the OAuthBearerSaslClientCallbackHandler class? That >> class >> > is >> > > >> not >> > > >> part of the public API, and its >> > handleCallback(OAuthBearerTokenCallback) >> > > >> method, which implements the logic, is private anyway (so even if >> > > someone >> > > >> took the risk of extending the non-API class the method would >> > generally >> > > >> not >> > > >> be available in the subclass). So as it stands right now >> implementers >> > > are >> > > >> left to copy/paste that logic into their code. A better solution >> > might >> > > be >> > > >> to have the private method in OAuthBearerSaslClientCallbackHandler >> > > >> invoke a >> > > >> public static method on the >> > > >> org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule >> > > class >> > > >> (which is part of the public API) to retrieve the credential (e.g. >> > > public >> > > >> static OAuthBearerToken retrieveCredential(Subject)) . The >> commit() >> > > >> method >> > > >> of the OAuthBearerLoginModule class is what puts the credential >> there >> > in >> > > >> the first place, so it could make sense for the class to expose the >> > > >> complementary logic for retrieving the credential in this way. >> > > Regarding >> > > >> your question about plugability of LoginModules, yes, the >> LoginModule >> > > >> class >> > > >> is explicitly stated in the JAAS config, so it is indeed >> pluggable; an >> > > >> extending class would override the commit() method, call >> > super.commit(), >> > > >> and if the return value is true it would do whatever is necessary >> to >> > add >> > > >> the desired SASL extensions to the Subject -- probably in the >> public >> > > >> credentials -- where a custom sasl.client.callback.handler.class >> would >> > > be >> > > >> able to find them. The KIP might state this, too. >> > > >> >> > > >> I'll look forward to seeing a new PR once the fix for the 0x01 >> > separator >> > > >> issue in the SASL/OAUTHBEARER implementation (KAFKA-7182 >> > > >> <https://issues.apache.org/jira/projects/KAFKA/issues/KAFKA-7182>) >> is >> > > >> merged. >> > > >> >> > > >> Ron >> > > >> >> > > >> On Wed, Jul 18, 2018 at 6:38 PM Stanislav Kozlovski < >> > > >> stanis...@confluent.io> >> > > >> wrote: >> > > >> >> > > >> > Hey Ron, >> > > >> > >> > > >> > You brought up some great points. I did my best to address them >> and >> > > >> updated >> > > >> > the KIP. >> > > >> > >> > > >> > I should mention that I used commas to separate extensions in the >> > > >> protocol, >> > > >> > because we did not use the recommended Control-A character for >> > > >> separators >> > > >> > in the OAuth message and I figured I would not change it. >> > > >> > Now that I saw your PR about implementing the proper separators >> in >> > > OAUTH >> > > >> > <https://github.com/apache/kafka/pull/5391> and will change my >> > > >> > implementation once yours gets merged, meaning commas will be a >> > > >> supported >> > > >> > value for extensions. >> > > >> > >> > > >> > About the implementation: yes you're right, you should define ` >> > > >> > sasl.client.callback.handler.class` which has the same >> functionality >> > > >> as ` >> > > >> > OAuthBearerSaslClientCallbackHandler` plus the additional >> > > >> functionality of >> > > >> > handling the `SaslExtensionsCallback` by attaching extensions to >> it. >> > > >> > The only reason you'd populate the `Subject` object with the >> > > extensions >> > > >> is >> > > >> > if you used the default `SaslClientCallbackHandler` (which >> handles >> > the >> > > >> > extensions callback by adding whatever's in the subject), as the >> > SCRAM >> > > >> > authentication does. >> > > >> > >> > > >> > https://github.com/stanislavkozlovski/kafka/blob/KAFKA-7169- >> > > >> custom-sasl-extensions/clients/src/main/java/org/ >> > > >> apache/kafka/common/security/oauthbearer/internals/OAuthBea >> > > >> rerSaslClient.java#L92 >> > > >> > And yes, in that case you would need a custom `LoginModule` which >> > > >> populates >> > > >> > the Subject in that case, although I'm not sure if Kafka supports >> > > >> pluggable >> > > >> > LoginModules. Does it? >> > > >> > >> > > >> > Best, >> > > >> > Stanislav >> > > >> > >> > > >> > On Wed, Jul 18, 2018 at 9:50 AM Ron Dagostino <rndg...@gmail.com >> > >> > > >> wrote: >> > > >> > >> > > >> > > Hi Stanislav. Could you add something to the KIP about the >> > security >> > > >> > > implications related to the CSV name/value pairs sent in the >> > > >> extension? >> > > >> > > For example, the OAuth access token may have a digital >> signature, >> > > but >> > > >> the >> > > >> > > extensions generally will not (unless one of the values is a >> JWS >> > > >> compact >> > > >> > > serialization, but I doubt anyone would go that far), so the >> > server >> > > >> > > generally cannot trust the extensions to be accurate for >> anything >> > > >> > > critical. You mentioned the "better tracing and >> troubleshooting" >> > > use >> > > >> > case, >> > > >> > > which I think is fine despite the lack of security; given that >> > lack >> > > of >> > > >> > > security, though, I believe it is important to also state what >> the >> > > >> > > extensions should *not* be used for. >> > > >> > > >> > > >> > > Also, could you indicate in the KIP how the extensions might >> > > actually >> > > >> be >> > > >> > > added? My take on that would be to extend >> OAuthBearerLoginModule >> > to >> > > >> > > override the initialize() and commit() methods so that the >> derived >> > > >> class >> > > >> > > would have access to the Subject instance and could add a map >> to >> > the >> > > >> > > subject's public or private credentials when the commit >> succeeds; >> > > >> then I >> > > >> > > think the sasl.client.callback.handler.class would have to be >> > > >> explicitly >> > > >> > > set to a class that extends the default implementation >> > > >> > > (OAuthBearerSaslClientCallbackHandler) and retrieves the map >> when >> > > >> > handling >> > > >> > > the SaslExtensionsCallback. But maybe you are thinking about >> it >> > > >> > > differently? Some guidance on how to actually take advantage >> of >> > the >> > > >> > > feature via an implementation would be a useful addition to the >> > KIP. >> > > >> > > >> > > >> > > Finally, I note that the extension parsing does not support a >> > comma >> > > in >> > > >> > keys >> > > >> > > or values. This should be addressed somehow -- either by >> > supporting >> > > >> via >> > > >> > an >> > > >> > > escaping mechanism or by explicitly acknowledging that it is >> > > >> unsupported. >> > > >> > > >> > > >> > > Thanks for the KIP and the simultaneous PR -- having both at >> the >> > > same >> > > >> > time >> > > >> > > really helped. >> > > >> > > >> > > >> > > Ron >> > > >> > > >> > > >> > > On Tue, Jul 17, 2018 at 6:22 PM Stanislav Kozlovski < >> > > >> > > stanis...@confluent.io> >> > > >> > > wrote: >> > > >> > > >> > > >> > > > Hey group, >> > > >> > > > >> > > >> > > > I just created a new KIP about adding customizable SASL >> > extensions >> > > >> to >> > > >> > the >> > > >> > > > OAuthBearer authentication mechanism. More details in the >> > proposal >> > > >> > > > >> > > >> > > > KIP: >> > > >> > > > >> > > >> > > > >> > > >> > > >> > > >> > https://cwiki.apache.org/confluence/display/KAFKA/KIP-342% >> > > >> >> > 3A+Add+support+for+Custom+SASL+extensions+in+OAuthBearer+authentication >> > > >> > > > JIRA: KAFKA-7169 < >> > > https://issues.apache.org/jira/browse/KAFKA-7169> >> > > >> > > > PR: Pull request <https://github.com/apache/kafka/pull/5379> >> > > >> > > > >> > > >> > > > -- >> > > >> > > > Best, >> > > >> > > > Stanislav >> > > >> > > > >> > > >> > > >> > > >> > >> > > >> > >> > > >> > -- >> > > >> > Best, >> > > >> > Stanislav >> > > >> > >> > > >> >> > > > >> > > > >> > > >> > >> > >> > -- >> > Best, >> > Stanislav >> > >> > > > -- > Best, > Stanislav > -- Best, Stanislav