-
Notifications
You must be signed in to change notification settings - Fork 429
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
Use provided username and password for JavaKerberos #66
Comments
If you are referring to the principal name and principal's Kerberos password used to generate TGT through kinit, using those values in connection string will defeat the purpose of Kerberos protocol. Either TGT or keytab file is used by JavaKerberos to prove that client knows the password without actually revealing it, thus making it is more secure. You could always use username and password for authentication instead of going for integrated authentication like Kerberos. |
That's correct. However, mssqlc-jdbc can handle getting the TGT for the user if the user doesn't already have a token. That way they don't have to pull up a terminal and type 'kinit' before connecting. When you pass doNotPrompt=false to Krb5LoginModule, it will trigger a CallbackHandler if no valid credentials are found where a username and password can be entered to acquire a new TGT. But that CallbackHandler has to be provided by the interface, in this case mssql-jdbc. Having spent a bunch of time dealing with the Kerberos ccache on OS X, I think this is better for the end user. Often the TGT is non-existent, expired, or stored in the memory cache where Krb5LoginModule can't get to it, which forces the user to do extra steps if they are running a client that needs to connect to MSSQL. |
Also, in our case where MS SQL Server is configured to only allow Kerberos/SSPI logins (which is not an uncommon configuration), simple password authentication is not an option. |
Actually, you don't need kinit with the JVM. You just need à JAAS config file named .java.login.config in the home directory of the user with a keytab for the technical user. It works on both mac, linux and windows very well. About ticket expiration, it can be configured in the jaas config file. |
Yes, but then you need to maintain a keytab. While it works, there are two reasons why I don't like it generally: 1) You need to update the keytab every time you change your password (not a problem for a technical user, but not good for a general user), and 2) A keytab is basically your authentication token stored on disk. It can be easily stolen and used by someone else. If you password protect the token, then you have to unlock it before you can use it, which brings the problem back to needing a username/password dialog presented to the user. |
@hoeflerb JDBC driver currently doesn't support doNotPrompt=false. We will consider it for future enhancement. |
Yes, I understand the purpose of Kerberos, but how can I log in a windows domain user using username and password? It seems that only users local to the actual database server can be logged in using username and password (as @hoeflerb mentions this might be a MS SQL Server configuration issue, but it is outside of my control) . The app that needs to authenticate is a server side app where password is kept in a protected file. At the moment there is no way we can run "kinit" when deploying the app. |
@jedvardsson I implemented it: #163 |
@jedvardsson safe option to log in a windows domain user would be to use Kerberos constrained delegation. It is implemented in #178. Let us know if this works for you. |
@v-suhame do you plan as well to integrate PR #163 that supports username/passwords (and quicker failure in case of wrong credentials)? |
@pierresouchay, @jedvardsson, I'm trying to understand the scenarios in which authenticating using Kerberos and password is needed. Can you help provide some more examples? |
@ajlam The principle reason is that, for Kerberos authentication, the TGT has to be maintained by the user somehow. Sometimes there is a facility within the OS to acquire and renew the TGT automatically for the user, but this is not always the case. Another scenario might be the user needing a different TGT from the one provided automatically by the OS. In either case, the very user-unfriendly way of doing this is to tell your users to "kinit" before trying to make a database connection using your app. Since Krb5LoginModule supports the ability to acquire a TGT for the user with provided credentials, it seems mssql-jdbc should use it to provide a more user-friendly experience. |
@ajlam I connect to 2 databases kerberos enabled from several realms without trusts from a GUI, in each realm I have a different user in that realm. My principal on my workstation is not known to those realms. |
@pierresouchay, @jedvardsson, @hoeflerb - apologies for the delay in getting this issue resolved. We're hoping to merge PR #163 within the next few releases. |
Great. I appreciate your work with this. |
I desperately need this feature, too. I hope this is merged soon! |
@hoeflerb, @jedvardsson, we have tested and merged PR #163, thanks to @pierresouchay! Lets leave this issue open until the same is fixed for IBM JVM. |
…on per connection properties. We also set a different default LoginConfig for IBM JVM, so it should work well with user-provided passwords and username for Kerberos. Should solve microsoft#66 for IBM JVM.
@hoeflerb @jedvardsson this issue is fixed by #163 and #254. Let us know if it works for you, so we can go ahead and close the issue. |
@v-suhame I can't get it working, but I'm probably doing something wrong. I've checked out the master branch and built a 6.1.6-SNAPSHOT using maven. Tested it using the following program and public class Main {
public static void main(String[] args) throws SQLException {
String url = "jdbc:sqlserver://myserver:1433;integratedSecurity=true;authenticationScheme=JavaKerberos";
try (Connection ds = DriverManager.getConnection(url, "myuser", "mypassword"); Statement s = ds.createStatement()) {
s.execute("select 1");
try (ResultSet rs = s.getResultSet()) {
rs.next();
int i = rs.getInt(1);
if (i != 1) {
throw new IllegalStateException("Expected 1 got " + i);
}
}
}
System.out.println("Success!");
}
}
The program results in the following stack trace:
|
@jedvardsson Master branch does not have it... branch dev does |
Works as advertised. However, as a point of clarification, this does not enable doNotPrompt=false. It took me a few tries before I realized it was expecting user= and password= in the connection string. |
@jedvardsson and btw, remove your .java.login.config file or remove the attribute: |
@hoeflerb doNotPrompt is not set when using default config. If you specify it in a jaas file, it will disable the feature however. It should work with both getConnection(URL, login, password) or within the URL with getConnection(URL) |
@pierresouchay Is it possible to create an actual prompt dialog for the username and password? Or is that too complicated? Storing the username and password in the connection string/login.config file works and is easier to update for a non-technical user than a keytab, but an SSO login credential stored in a plaintext config file seems dangerous from a security perspective. |
Use a GUI such as DBeaver, or implement this in your app. Prompting the user is not doable easily: in text mode? With a Swing dialog box? While it might work in your app, it might not in a server. Most applications requesting a database have usually a way to query the user for username/password to connect to database, those patches make it doable while using Kerberos, nothing more |
Yes, ok, I see what you are saying. It would be difficult to write a generic mechanism for mssql-jdbc itself to prompt for the username/password because it would need to be tailored to the specific environment (text, gui, remote, headless, etc). I'm not actually writing my own app. I'm using a commercial product that uses mssql-jdbc to connect to SQL Server via Kerberos. My interest in this stems from a problem on OS X, where JavaKerberos does not read the TGT from the memory cache, but instead attempts to look for it in a file cache. Since the TGT isn't there (hasn't been since ca 10.3), the Kerberos authentication mechanism for mssql-jdbc fails, so the user has to maintain a separate and independent ticket cache to use Kerberos with mssql-jdbc. I was hoping the doNotPrompt mechanism would be an easy enough workaround because I think it would be harder to implement support for the memory cache in JavaKerberos. |
@hoeflerb It is perfectly doable to have the ticket read from Memory cache, I am doing this myself (my Mac is integrated into an AD domain, so when I connect, I already have a Kerberos ticket with my identity). kinit on Mac OS also supports using the Keychain for storing the user credentials for your cache, so for instance, launching the product with kinit --keychain not requesting the user to write the password each time. |
@pierresouchay when you say you are reading the ticket from the memory cache, do you mean you are using mssql-jdbc with integratedAuthentication=true;authenticationScheme=JavaKerberos;useTicketCache=true and it works just like that with your managed identity? Or are you using a keytab? I tried for many hours to get JavaKerberos to read from the memory cache. Ultimately, the only way I was able to make it work was to kinit -c a new TGT into a new file cache. I dug into the code at one point and there were explicit comments indicating that the memory cache wasn't supported. It actually greps around in the filesystem to find the file cache and reads the TGT directly (ie: it doesn't use userspace apis to do this). |
Great. My test as specified above works as expected, i.e., getConnection(url, username, password) works. |
@hoeflerb useficketCache & friends have to be set in .java.login.config file. On my side, I use keytab for servers and user/password from GUI, but I think it is working. You may try with a recent JVM |
@pierresouchay it also works from the connection string. I've used both. But anyway, the point is that unless you are using a file cache, useTicketCache does not work. The only reason that's a problem is because all of the ticket managing utilities on OS X get and renew tickets from the memory cache, and they unfortunately don't respect environment variables like KRB5CCNAME which, if they did, would allow me to move everything to a single per user file cache. Only current workarounds that I have found are: |
@jedvardsson I am closing this issue as you already able to test patch. Please feel free to reopen or create new issue depend on your tests & observation. |
Hello @pierresouchay, |
@sbuettne It has been included here: https://github.com/Microsoft/mssql-jdbc/releases/tag/v6.1.7 So it is already merged in master. So, ask MSFT employees when it will be included for a public release, but it is still available as version 6.1.7 preview. |
@pierresouchay @jedvardsson please help
and set the .java.login.config as below and using mssql-jdbc-6.2.2.jre8.jar (download from http://www.java2s.com/example/jar/m/download-mssqljdbc622jre8jar-file.html)
I'm getting below error
looks like its not using the provided username and password to establish connection, did I miss anything here? please let me know how to solve this. |
If you set (It is annoying that the JDBC Driver for [MS] SQL Server deviates from the |
It would be great if the driver could pick up username and password from the connection settings instead of having to be provided through "kinit".
The text was updated successfully, but these errors were encountered: