I'm new to connecting Java to SQL Server but hopefully I manage to connect them successfully through helps of various tutorials. But there are these methods and syntax that I couldn't explain for myself.
1.
Connection conn=DriverManager.getConnection("jdbc:sqlserver://localhost:1433;databaseName=login_DB;integratedSecurity=true");
Regarding the code above, what does integratedSecurity=true do?
2.
String user = rss.getString(1);
String pass = rss.getString(2);
Does the parameter inside getString(1) and getString(2) pertains to the column in the Database? And also, how does the ResultSet affects the getString()?
3.
while(rss.next()){
String user = rss.getString(1);
String pass = rss.getString(2);
if(usernameTF.getText().trim().equals(user)&&passwordTF.getText().trim().equals( pass)){
count = 1;
}//if success
}//while
Lastly, at least for now, does the while(rss.next()) method simply means that while there is a row in my table?
I know my code is a bad practice. But I am really trying my best to make it better.
Integrated Security = true/SSPI : the current Windows account credentials are used for authentication.
Integrated Security = False : User ID and Password are specified in the connection String.
rs.getString(1) - get 1 return column from your select statement.
Select x,y,z from table; rs.getString(1) gives x column result for particular row.
Your query returning n number row ,each time rs.next() check is there row available after current row.
Difference between Integrated Security = True and Integrated Security = SSPI
Yes the number refers to the column number, or you can pass a String as the column name to pull data.
Yes, whilst there is data in your ResultSet, for each iteration it will move the cursor to the next row of data available. Where you can access columns specifically using the syntax from part 2 of your question.
Hope this is useful.
According to Microsoft they are the same thing.
When false, User ID and Password are specified in the connection. When true, the current Windows account credentials are used for authentication.
Recognized values are true, false, yes, no, and sspi (strongly recommended), which is equivalent to true.
There however is a difference between them according to the comment below:
True ignores User Id and Password if provided and uses those of the running process, SSPI it will use them if provided which is why MS prefers this.
They are equivalent in that they use the same security mechanism to authenticate but that is it.
refer this link...!
Related
I have a requirement. The technology is quite old doesn't support spring at all . It is pure java application with jdbc connection.
Requirement is :
Suppose
select * from employee where empid = <<empid>> and designation = 'Doctor'
I am trying to replace <> with actual int value in java . How I can do it ?
String query = "select * from employee where empid = <<empid>> and designation = 'Doctor'";
if(query.contains("<<empid>>"))
/// Here I want to replace <<empid>> with actual int value in java
Any leads will be helpful
The code you didn't paste, that actually executes the SQL is either [A] a massive security leak that needs serious rewrites, or [B] is using PreparedStatement.
Here's the problem: SQL injection. Creating the SQL string by mixing a template or a bunch of string constants together with a bunch of user input is a security leak. For example, if you try to make SELECT * FROM users WHERE email = 'foo#bar.com' by e.g. String sql = "SELECT * FROM users WHERE email = '" + email + "'";, the problem is, what if the user puts in the web form, in the 'email' field: whatever#foo.com'; DROP TABLE users CASCADE; EXEC 'FORMAT C: /y /force'; --? Then the SQL becomes:
SELECT * FROM users WHERE email = 'whatever#foo.com'; DROP TABLE users CASCADE; EXEC 'FORMAT C: /y /force'; --';
That is legal SQL and you really, really, really don't want your DB engine to execute it.
Each DB engine has its own ideas on what's actually legal, and may do crazy things such as treating curly quotes as real quotes, etc. So, there is no feasible blacklist or whitelist technology you can think of that will properly cover all the bases: You need to ask your DB engine to do this for you, you can't fix this hole yourself.
Java supports this, via java.sql.PreparedStatement. You instead always pass a fully constant SQL string to the engine, and then fill in the blanks, so to speak:
PreparedStatement ps = con.prepareStatement("SELECT * FROM users WHERE email = ?");
ps.setString(1, "foo#whatever.com");
ps.query();
That's how you do it (and add try-with-resources just like you should already be doing here; statements and resultsets are resources you must always close). Even if you call .setString(1, "foo#whatever.com'; DROP TABLE users CASCADE; --"), then it'll simply look for a row in the database that has that mouthful in the email field. It will not delete the entire users table. Security hole eliminated (and this is the only feasible way to eliminate it).
So, check out that code. Is it using preparedstatement? In that case, well, one way or another that code needs to be calling:
ps.setInt(1, 999);
Where ps is the PreparedStatement object created with connection.prepareStatement(...) where ... is either an SQL constant or at least your input string where the <<empid>> was replaced with a question mark and never with any string input from an untrusted source. The 1 in ps.setInt(1, 999) is the position of the question mark (1 = the first question becomes 999), and the 999 is your actual number. It may look like:
if (input instanceof String) {
ps.setString(idx++, (String) input);
} else if (input instanceof Integer) {
ps.setInt(idx++, ((Integer) input).intValue());
} ...
etcetera. If you don't see that, find the setInt invoke and figure out how to get there. If you don't see any setInt, then what you want is not possible without making some updates to this code.
If you don't even see PreparedStatement anywhere in the code, oh dear! Take that server offline right now, research if a security leak has occurred, if this server stored european data you have 72 hours to notify all users if it has or you can't reasonably figure out e.g. by inspecting logs that it hasn't, or you're in breach of the GDPR. Then rewrite that part using PreparedStatement to solve the problem.
Yesterday searching through some repositories on Github I found some interesting stuff: one Java project (I won't mention the name of the repository but I've already notified the owner of it) contained a bad handling of HQL queries which could lead to SQL/HQL injections. The code was the following: (note that username and password come from the user)
Query query = session.createQuery("from Client where username = '" + username + "'");
List clients = query.list();
Client client = (Client) clients.get(0);
if (!validPassword(client.getPassword(), password)) {
return false;
}
//client is authenticated....
I think it is obvious that this query is injectable. I don't really know how this vulnerable query could be exploited because even if we inject the username, the
password is still checked. The database used was MySql (if it helps).
So my question is: how could this be exploited?
Even though HQL is more restrictive than SQL for injections, it can still be exploited.
Some example injections are explained at https://blog.h3xstream.com/2014/02/hql-for-pentesters.html
A similar question to this one has been asked already before at https://security.stackexchange.com/questions/24265/hql-injection-example
The answer to this question explains how characters of a password (hash) could be scanned. e.g. if for an Oracle database the value of username is:
admin' AND SUBSTR(password, 0, 1) = 'A
Then if
the first character of the password (hash) is not 'A' -> the clients List is empty and the clients.get(0) method call throws an IndexOutOfBoundsException
the first character of the password (hash) is 'A', but the provided password is false -> the user is not authenticated
the first character of the password (hash) is 'A' and the provided password is correct -> the user is authenticated
A hacker can repeat the query for each x and z in
SUBSTR(password, x, x + 1) = z
in the query above until the outcome is always case 2. where the user is not authenticated. This way he can find out the password hash for the user admin and may be able to crack his password.
Other exploits are possible, I am not going to list all of them...
Yes so...once you had start hibernate session, You can fetch data using query. Now you have written query for Client table.
For ex,
username = "ABC"
1) Your query from Client where username = 'ABC' will fetch data from Client whoes username is exact ABC.
If it found multiple same Username, it also return all.
2) It is going to store in list. 0 or more record will store in list.
3) Then whatever records came, it fetch only first record using
Client client = (Client) clients.get(0);
4) it check with client object record password with your expected password that may be suppose to save in some variable via method calling.
5) if it won't match then it return with false boolean flag otherwise code will go ahead with authenticated client execution.
Hope you got your answer.
So in my database, I have 3 rows, two rows have defaultFlag as 0 and one is set to 1, now in my processing am updating defaultProperty of one object to 1 from 0 but am not saving this object yet.
Before saving I need to query database and find if any row has defaultFlag set or not, there would be only 1 default set.
So before doing update am running query to find if default is set and i get 2 values out, note here if i go and check in db then there is only 1 row with default set but query gives me two result because this.object default property has changed from 0 to 1 but note that this object is not yet saved in database.
I am really confused here as to why hibernate query is returning 2 when there is one row with default set in database and other object whose default property has changed but it is not saved.
Any thoughts would be helpful. I can provide query if need be.
Update
Following suggestions, I added session.clear() to before running the query.
session.clear();
String sql = "SELECT * FROM BANKACCOUNTS WHERE PARTYID = :partyId AND CURRENCYID = :currencySymbol AND ISDEFAULTBANKACCOUNT= :defaultbankAccount";
SQLQuery q = session.createSQLQuery(sql);
q.addEntity(BankAccount.class);
q.setParameter("partyId", partyId);
q.setParameter("currencySymbol", currencySymbol);
q.setParameter("defaultbankAccount", 1);
return q.uniqueResult();
and it returns 1 row in result as expected but now am getting
nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session exception
Either query which row has the "default flag" set before you start changing it, or query for a list of rows with default flag set & clear all except the one you're trying to set.
Very easy, stop mucking about with your "brittle" current approach which will break in the face of concurrency or if data is ever in an inconsistent state. Use a reliable approach instead, which will always set the data to a valid state.
protected void makeAccountDefault (BankAccount acc) {
// find & clear any existing 'Default Accounts', other than specified.
//
String sql = "SELECT * FROM BANKACCOUNTS WHERE PARTYID = :partyId AND CURRENCYID = :currencySymbol AND ISDEFAULTBANKACCOUNT= :defaultbankAccount";
SQLQuery q = session.createSQLQuery(sql);
q.addEntity(BankAccount.class);
q.setParameter("partyId", partyId);
q.setParameter("currencySymbol", currencySymbol);
q.setParameter("defaultbankAccount", 1);
//
List<BackAccount> existingDefaults = q.list();
for (BankAccount existing : existingDefaults) {
if (! existing.equals( acc))
existing.setDefaultBankAccount( false);
}
// set the specified Account as Default.
acc.setDefaultBankAccount( true);
// done.
}
This is how you write proper code, do it simple & reliable. Never make or depend on weak assumptions about the reliability of data or internal state, always read & process "beforehand state" before you do the operation, just implement your code clean & right and it will serve you well.
I think that your second query won't be executed at all because the entity is already in the first level cache.
As your transaction is not yet commited, you don't see the changes in the underlying database.
(this is only a guess)
That's only a guess because you're not giving many details, but I suppose that you perform your myObject.setMyDefaultProperty(1) while your session is open.
In this case, be careful that you don't need to actually perform a session.update(myObject) to save the change. It is the nominal case when database update is transparently done by hibernate.
So, in fact, I think that your change is saved... (but not commited, of course, thus not seen when you check in db)
To verify this, you should enable the hibernate.show_sql option. You will see if an Update statement is triggered (I advise to always enable this option in development phase anyway)
I am attempting to use zxJDBC to connect to a database running on SQL Server 2008 R2 (Express) and call a stored procedure, passing it a single parameter. I am using jython-standalone 2.5.3 and ideally do not want to have to install additional modules.
My test code is shown below.
The database name is CSM
Stored Procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE dbo.DUMMY
-- Add the parameters for the stored procedure here
#carrierId VARCHAR(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO dbo.carrier (carrierId, test)
VALUES (#carrierId, 'Success')
END
GO
Jython Script:
from com.ziclix.python.sql import zxJDBC
conn = None
try :
conn = zxJDBC.connect('jdbc:sqlserver://localhost\SQLEXPRESS', 'sa', 'password', 'com.microsoft.sqlserver.jdbc.SQLServerDriver')
cur = conn.cursor()
cur.callproc(('CSM','dbo','DUMMY'), ['carrier1'])
conn.commit()
except Exception, err :
print err
if conn:
conn.rollback()
finally :
if conn :
conn.close()
By using cur.execute() I have been able to verify that the above is successfully connecting to the database, and that I can query against it. However, I have thus far been unable to successfully call a stored procedure with parameters.
The documentation here(possibly out of date?) indicates that callproc() can be called with either a string or a tuple to identify the procedure. The example given -
c.callproc(("northwind", "dbo", "SalesByCategory"), ["Seafood", "1998"], maxrows=2)
When I attempt to use this method, I receive the following error
Error("Could not find stored procedure 'CSM.DUMMY'. [SQLCode: 2812], [SQLState: S00062]",)
It would appear that zxJDBC is neglecting to include the dbo part of the procedure identifier.
If I instead call callproc with "CSM.dbo.DUMMY" as the first argument then I receive this error
Error('An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name. [SQLCode: 1038], [SQLState: S0004]',)
Using a profiler on the database whilst running my script shows that in the second case the following SQL is executed:
use []
go
So it would seem that when using a single string to identify the procedure, the database name is not correctly parsed out.
One of my trial and error attempts to fix this was to call callproc as follows:
cur.callproc(('CSM', '', 'dbo.DUMMY'), ['carrier1'])
This got me only as far as
Error("Procedure or function 'DUMMY' expects parameter '#carrierId', which was not supplied. [SQLCode: 201], [SQLState: S0004]",)
In this case what I think is happening is that zxJDBC attempts to call a system stored procedure (sp_proc_columns) to determine the required parameters for the stored procedure I want to call. My guess is that with the procedure identifier in the incorrect format above, zxJDBC does not get a valid/correct return and assumes no parameters are required.
So basically I am not a bit stuck for ideas as to how to get it to
Use the correct database name
Correctly determine the required parameters using sp_proc_columns
Call my stored procedure with the correct name
all at the same time.
I do have a workaround, which is to use something like
cur.execute('EXEC CSM.dbo.DUMMY ?', ['carrier1'])
However I feel like callproc() is the correct solution, and would likely produce cleaner code when I come to call stored procedures with large numbers of parameters.
If anyone can spot the mistake(s) that I am making, or knows that this is not ever going to work as I think then any input would be much appreciated.
Thanks
Edit
As suggested by i-one, I tried adding cur.execute('USE CSM') before calling my stored procedure (also removing the database name from the procedure call). This unfortunately produces the same Object or Column missing error as above. The profiler shows USE CSM being executed, followed by USE [] so it seems that callproc() always fires a USE statement before the procedure itself.
I have also experimented with turning on/off autocommit, to no avail.
Edit 2
Further information following comments/suggested solutions:
"SQLEXPRESS" in my connection string is the database instance name.
Using double quotes instead of single has no effect.
Including the database name in the connection string (via ;databaseName=CSM; as specified here) and omitting it from the callproc() call leads to the original error with a USE [] statement being fired.
Using callproc(('CSM', 'dbo', 'dbo.DUMMY'), ['carrier1']) gives me some progress but results in the error
Error("Procedure or function 'DUMMY' expects parameter '#carrierId', which was not supplied. [SQLCode: 201], [SQLState: S0004]",)
I'll attempt to investigate this further
Edit 3
Based on the queries I could see zxJDBC firing, I manually executed the following against my database:
use CSM
go
exec sp_sproc_columns_100 N'dbo.DUMMY',N'dbo',N'CSM',NULL,N'3'
go
This gave me an empty results set, which would seem to explain why zxJDBC isn't passing any parameters to the stored procedure - it doesn't think it needs to. I have yet to figure out why this is happening though.
Edit 4
To update the above, the empty result set is because the call should be
exec sp_sproc_columns_100 N'DUMMY',N'dbo',N'CSM',NULL,N'3'
This unfortunately brings me full circle as I can't remove the dbo owner from the stored procedure name in my callproc() call or the procedure won't be found at all.
Edit 5
Table definition as requested
CREATE TABLE [dbo].[carrier](
[carrierId] [varchar](50) NOT NULL,
[test] [varchar](50) NULL
) ON [PRIMARY]
Though completely unaware of the technologies used here (unless some minor knowledge of SQL Server), I will attempt an answer (please forgive me if my jython syntax is not correct. I am trying to outline possibilities here not exact code)
My first approach (found at this post) would be to try:
cur.execute("use CSM")
cur.callproc(("CSM","dbo","dbo.DUMMY"), ["carrier1"])
This must have to do with the fact that sa users always have the dbo as a default schema (described at this SO post)
If the above does not work I would also try to use the CSM database name in the JDBC url (this is very common when using JDBC for other databases) and then simply call one of the two below.
cur.callproc("DUMMY", ["carrier1"])
cur.callproc("dbo.DUMMY", ["carrier1"])
I hope this helps
Update: I quote the relevant part of the link that you can't view
>> Program calls a Stored Procedure - master.dbo.xp_fixeddrives on MS SQL Server
from com.ziclix.python.sql import zxJDBC
def getConnection():
url = "${DBServer.Url}"
user= "${DBServer.User}"
password = "${DBServer.Password}"
driver = "${DBServer.Driver}"
con = zxJDBC.connect(url, user, password, driver)
return con
try:
conn = getConnection()
print 'Connection successful'
cur = conn.cursor()
cur.execute("use master")
cur.callproc(("master", "dbo", "dbo.xp_fixeddrives"))
print cur.description
for a in cur.fetchall():
print a
finally:
cur.close()
conn.close()
print 'Connection closed'
The error you get when you specified the call function like above suggests that the parameter is not passed correctly. So please modify your stored procedure to take a default value and try to call with passing params = [None]. If you see that the call succeeds we must have done something right as far as specifying the database is concerned.
Btw: the most recent documentation suggests that you should be able to access it with your syntax.
As outlined in comments callproc will work only with SELECT. Try this approach instead:
cur.execute("exec CSM.dbo.DUMMY #Param1='" + str(Param1) + "', #carrierId=" + str(carrierID))
Please see this link for more detail.
Hi I have read Glassfish 3.1.2's JDBCRealm has a new Password Encryption Algorithm field. What is it for? and googled for similar topics but it seems no definitive answer has been published.
In short, I have a jdbc realm working in glassfish 3, when I upgrade to 3.1.2, same configuration does not work. According to the previous thread, I have set the JaasContext to jdbcDigestRealm (in addition to jdbcRealm which also does not work), set the Digest Algorithm to MD5 (I used MD5 in v 3 and it worked). For Password Encryption Algorithm I tried 'blank', and 'hex', both do not work.
Could someone please tell me how I should configure. My credentials table is based on mysql with MD5 hashed passwords according to http://jugojava.blogspot.hk/2011/02/jdbc-security-realm-with-glassfish-and.html.
I succeed to make it works with the following settings. I add a few comments with my current (mis)understanding.
JAASContext = "jdbcRealm" => The value must be set according to file 'glassfish3/glassfish/domains/domain1/config/login.conf'. By default, the class 'com.sun.enterprise.security.auth.login.JDBCLoginModule' (which implement the JDBCrealm) is configured under "jdbcRealm". There is another login module configured under "jdbcDigestRealm". This one is not part of the current topic.
JNDI = "..." => I put there the name of a datasource that already
exists for the database of my application.
UserTable = "MY_SCHEMA.usertable" => The 'full qualified name' of the
database table.
UserNameColumn = "userid" => column name where you store the user
name
PasswordColumn = "password" => column name where you store the (hash
of the) user passsword.
GroupTable = "MY_SCHEMA.grouptable" => The 'full qualified name' of
the database table.
GroupTableUserNameColumn = "" => no clue about the usage of this...
GroupNameColumn = "groupid" => column name where you store the user
name
AssignGroups = "" => As far as I understand the GF code, this is a way to assign a list of groups to every user registered in the realm. It's kind of hard-coding. More or less every realm available on GlassFish (could) make use of this property.
DatabaseUser = "" => As I understood, you need this if you aren't
using the JNDI (the second parameter).
DatabasePassword = "" => As I understood, you need this if you aren't
using the JNDI (the second parameter).
DigestAlgorithm = "SHA-256" => 'MD5', 'SHA-1' or 'SHA-256'. 'SHA-256'
is the default. Let's take 'SHA-256'.
PasswordEncryptionAlgorithm = "AES" => The digest algorithm is applied to the password before storing the password. The new password encryption is an added layer of security which allows the "hash" (the string after the DA has been applied to the password) to be encrypted. In this way, if an attacker retrieves the passwords from the database they are encrypted and hashed. It's highly unlikely that such data would be useful to an attacker.
Encoding = "Hex" => You have the choice between 'Hex' or 'Base64'.
Hex was convenient for me.
Charset = "" => As my database does not have an 'exotic' charset, I
do not think I need to set something smart there. I leave it blank
and it works.
Hope it will help.
PS: If somebody have a link to REAL documentation (not the official one which is completly useless at this moment), please, put a link here.
I spent a while today playing with this (Java EE 7, Glassfish 4 on Ubuntu 12.04). As it turns out, most of the fields on the Realm Page are not needed. The following fields were the only ones that are needed to establish a successful connection to the database.
Realm Name - Any name, as long as you use the same name in web.xml
JAAS Context - Any Name
JNDI - Any Name (I used jdbc/DB Name)
User Table - Table which contains all the users
User Name column - Column in the users table which contains your user-names
Password - Column which contains hashed passwords (SHA 256)
Group Table - Table which contains groups
Group Name Column - Column in the groups table which contain group names
I left everything else blank. My database password column had the password hashed using SHA 256.
I tested this by filling in random text in the 'Password Encryption' field and saving it. Redeployed my application and restarted Glassfish 4. Still worked. This means that the field, while still present is not being read anymore.
P.S - The real documentation as mentioned in the first answer is still quite poor.
First things first. What is your log output?
What are the symptoms of your "not working problem"?
Did basic-authentication pop-up window occurred?
Did you get
No login module configured for jdbcDigestRealm
or other error message?
change security log level if don't have any log output from unsuccessful login attempt.
I have two variations to the jdbcRealm issue. The first existed from a domain that was created using GF 3.1.1 which continued to work after updating the GF server to the 3.1.2.2 release. I then created a new domain on this server. The new domain was configured using the jdbcRealm. All of the parameters were the same for the 3.1.1 configuration except for the "Password Encryption Algorithm" which didn't exist under the 3.1.1 configuration screen. When I tried to login using my Web Application I was constantly getting the "jdbcrealm.invaliduserreason[#]" error in the log file.
The only way that I was able to resolve and to successfully login to my application was by adding the AES to the "Password Encryption Algorithm" field. I saved the change and restarted the server and once again I am able to successfully authenticate users from the jdbcRealm connection.
There is a somewhat more detailed guide here -> http://is.gd/Jx6Gnp