-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Adding SPNEGO authentication support for Jetty Client #2868
Comments
See also #1708. |
Work is in progress for this issue, and we also took the chance to rewrite the server side, which allows us to test the whole scenario. We have working code that allows us to derive few conclusions. SPNEGO requires a 401+200 for every request. This is a performance hit for Why people insist using SPNEGO with HTTP when it's so broken? |
The only way around is to have the server-side emit a non-guessable cookie after the initial SPNEGO handshake. Actually, SPNEGO emits a The server would then need to check the incoming token and allow the request if the value matches. @gregw should we implement this workaround or just leave SPNEGO as is (i.e. 401+200 for every request - with problems for |
IIUC in Hadoop, after the authorization process, the server will then return a cookie to the client, for subsequence requests, the cookie will be used instead. That seems their workaround for the performance problem. |
Implemented client-side SPNEGO authentication. Reimplemented server-side SPNEGO authentication. Added tests to verify behavior. Signed-off-by: Simone Bordet <[email protected]>
@CaoManhDat I pushed working code to branch @joshelser I have taken into account your observations in #1708 (use multiple Oids on server) in the new server-side implementation. Can you try it out? To build:
Thanks! |
Added missing copyright header. Signed-off-by: Simone Bordet <[email protected]>
Hi @sbordet I'm meeting some trouble when trying to integrate your implementation to Solr, since the configuration is provided through JAAS, i.e
In your implementation it seems that we must provide all the parameters manually. |
@CaoManhDat you only have to provide the service And you have to provide the JAAS config name So with old code you need to A) set the system property with the JAAS config file path, and B) set the JAAS config name. With the new code you need to A) set the service name, and B) set the keyTab path. |
@CaoManhDat the old way was as official as the new way and it's not enough to only set the system property, unless you have hardcoded in the code the name of the JAAS configuration, All in all, the old way is quite more complex than the new way. Looking at the stack trace you posted, it is the client-side of the GSS negotiation. So the JAAS configuration should be called My point being that on the client side you had to use system properties and external JAAS config files only because the implementation you were using was forcing you to do that. Had that implementation done the opposite, you will be here asking me why you cannot set the principal via a setter 😉 I don't know... seems all more complicated to me. I'm a bit confused if you want this on the client-side or on the server-side. |
Sorry, the example
|
@sbordet You're right, this seems reasonable to me. Solr in that case must include some way to automatically convert the old magic properties to the new one. Since we want users to have a pleasure experience when update from the old version of Solr to a new one. |
@sbordet Thanks a lot, tests seem happy now, We will try to setup the authentication in a real cluster to check whether any errors can arise. |
@CaoManhDat as I said we can have a subclass that works like your old way, but we need more information, in particular: how was the JAAS config name |
@sbordet Currently Solr implement a class for doing this work private static class SolrJaasConfiguration extends javax.security.auth.login.Configuration {
private javax.security.auth.login.Configuration baseConfig;
// the com.sun.security.jgss appNames
private Set<String> initiateAppNames = new HashSet(
Arrays.asList("com.sun.security.jgss.krb5.initiate", "com.sun.security.jgss.initiate"));
public SolrJaasConfiguration() {
try {
this.baseConfig = javax.security.auth.login.Configuration.getConfiguration();
} catch (SecurityException e) {
this.baseConfig = null;
}
}
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String appName) {
if (baseConfig == null) return null;
String clientAppName = System.getProperty("solr.kerberos.jaas.appname", "Client");
if (initiateAppNames.contains(appName)) {
log.debug("Using AppConfigurationEntry for appName '"+clientAppName+"' instead of: " + appName);
return baseConfig.getAppConfigurationEntry(clientAppName);
}
return baseConfig.getAppConfigurationEntry(appName);
}
} |
Uhm, hardcoded system properties everywhere. I'll think about this, but I prefer to not hardcode anything in Jetty. If you can pass the JAAS config name to a subclass, then surely you can pass other configuration parameters so that there is no need to hardcode anything, right? |
Right, I can pass other configuration parameters (with some casting and null checks). But are you sure that This is my attempt so far, tests of Solr seems happy with this integration. We will now test the build against real kerberos setup. Will tell you about the result soon AppConfigurationEntry[] entries = jaasConfig.getAppConfigurationEntry(clientAppName);
if (entries == null) {
log.warn("Could not find login configuration entry for {}. " +
"SPNego authentication may not be successful.", clientAppName);
return authentication;
}
if (entries.length != 1) {
log.warn("Multiple login modules are specified in the configuration file");
return authentication;
}
Map<String, ?> options = entries[0].getOptions();
String keyTab = (String) options.get("keyTab");
if (keyTab != null) {
authentication.setUserKeyTabPath(Paths.get(keyTab));
}
authentication.setServiceName("HTTP");
authentication.setUserName((String) options.get("principal"));
if ("true".equalsIgnoreCase((String) options.get("useTicketCache"))) {
authentication.setUseTicketCache(true);
String ticketCachePath = (String) options.get("ticketCache");
if (ticketCachePath != null) {
authentication.setTicketCachePath(Paths.get(ticketCachePath));
}
authentication.setRenewTGT("true".equalsIgnoreCase((String) options.get("renewTGT")));
} |
Ugh, no. I'll create a subclass so that you can do: new JAASSPNEGOAUthentication(clientAppName); so that you only set the JAAS system property and you're good. |
BTW: @gerlowskija helped on testing the integration in an AWS cluster with Kerberos setup. The result seems good. We are unable to find any problem. The current implementation seems solid! |
@CaoManhDat let me recap:
What do you use on the server? The old Jetty implementation? Something else? |
@CaoManhDat there is another thing that needs to be configured on the client: the service name. |
Updates after review. Signed-off-by: Simone Bordet <[email protected]>
@sbordet SolrCloud have 2 components
All kind of servers/clients above are guarded by Kerberos. So the setup which contains Our current implementation of Kerberos on server side based on |
BTW: What is the expected date for the next release of Jetty that include this implementation. Since Solr 8.0 tends to release in October. Therefore the switch from Apache Http Client to Jetty Client should be ready by then. If not I will probably have to do some workaround (like copy paste all the necessary source code of this implementation then remove it latter on the next release of Jetty). |
Renamed server-side classes and added javadocs. Deprecated old server-side classes in favor of the new ones. Signed-off-by: Simone Bordet <[email protected]>
Added client-side classes javadocs. Signed-off-by: Simone Bordet <[email protected]>
Avoid hardcoded KDC port in tests. Updated Krb5LoginModule options with refreshKrb5Config=true, to make sure the KDC configuration is re-read for every test. Signed-off-by: Simone Bordet <[email protected]>
Updated server-side authentication logic after review. Signed-off-by: Simone Bordet <[email protected]>
Fixed server-side logic after review. Signed-off-by: Simone Bordet <[email protected]>
Restored behavior where authentication results are stored no matter the response status. Signed-off-by: Simone Bordet <[email protected]>
Running tests only on JDK 11, as apparently other JDKs have problems with AES encryption/decryption. Another hypothesis is that Kerby does AES encryption differently from what earlier JDKs expect. Signed-off-by: Simone Bordet <[email protected]>
Issue #2868 - Adding SPNEGO authentication support for Jetty Client.
Removed old deprecated SPNEGO implementation on server-side. Signed-off-by: Simone Bordet <[email protected]>
@CaoManhDat eventually we decided to not implement the version with hardcoded system properties. This is now merged in the main line of Jetty, and the next release should be in October - targeting a couple of weeks. Thanks! |
Jetty 11 is now at End of Community Support Please try again with Jetty 12, and if you still have problems open a new issue against Jetty 12, don't revive this one. |
Although this kind of authentication seems not follow the HTTP rules but in production Spnego/Kerberos is widely used, i.e: Hadoop, Ambari. This is also a requirement feature for us when trying to move from Apache HttpClient to Jetty Client.
The text was updated successfully, but these errors were encountered: