How to call oracle function using Hibernate criteria? - java

I am new to Hibernate. I am building a Login Portal. We have used DB Function to encrypt User Password. It seems that using hibernate for complex queries/functions/procedures on existing databases is difficult.
Is it possible to write below queries using Hibernate criteria?
SQL Query 1 :
SELECT first_name
FROM user.emp_group
WHERE username = 'XXX'
AND user.decrypt(password, 2) = 'YYYY';
SQL Query 2 :
SELECT a.DESC
,b.total
FROM user.STATUS a
,(
SELECT STATUS
,count(*) total
FROM user.emp
GROUP BY STATUS
) b
WHERE a.TYPE = b.STATUS (+)
User is the schema name and decrypt is function name.
I also faced problem for getting data from views which was resolved by this Stackoverflow post. How hibernate retrieve data from existing database view?
Thanks for that.

You can use native SQL with hibernate.
The way is something like this (for example):
String sql = "SELECT first_name, salary FROM EMPLOYEE";
SQLQuery query = session.createSQLQuery(sql);
List data = query.list();
for(Object object : data)
{
Map row = (Map)object;
System.out.print("First Name: " + row.get("first_name"));
System.out.println(", Salary: " + row.get("salary"));
}

Related

Java dynamically generate SQL query - ATHENA

I am trying to generate sql query based on user input. There are 4 search fields on the UI:
FIRST_NAME, LAST_NAME, SUBJECT, MARKS
Based on user input I am planning to generate SQL query. Input can be of any combination.
eg: select * from TABLE where FIRST_NAME="some_value";
This query needs to be generated when FIRST_NAME is given and other fields are null
select * from TABLE where FIRST_NAME="some_value" and LAST_NAME="some_value";
This query needs to be generated when FIRST_NAME and LAST_NAME are given and other fields are null
Since there are 4 input fields, number of possible queries that can be generated are 24 (factorial of 4).
One idea is to write if condition for all 24 cases.
Java pseudo code:
String QUERY = "select * from TABLE where ";
if (FIRST_NAME!=null) {
QUERY = QUERY + "FIRST_NAME='use_input_value';"
}
if (LAST_NAME!=null) {
QUERY = QUERY + "LAST_NAME='use_input_value';"
}
if (SUBJECT!=null) {
QUERY = QUERY + "SUBJECT='use_input_value';"
}
if (MARKS!=null) {
QUERY = QUERY + "MARKS='use_input_value';"
}
I am not able to figure out how to generate SQL queries with AND coditions for multiple Input values.
I have been through concepts on dynamically generate sql query but couldn't process further.
Can someone help me on this.
FYI: I have been through How to dynamically generate SQL query based on user's selections?, still not able to generate query string based on user input.
Let's think about what would happen if you just ran the code you wrote and both FIRST_NAME and LAST_NAME are provided. You'll wind up with this:
select * from TABLE where FIRST_NAME='use_input_value';LAST_NAME='use_input_value';
There are two problems here:
The query is syntactically incorrect.
It contains the literals 'use_input_value' instead of the values you want.
To fix the first problem, let's first add and to the start of each expression, and remove the semicolons, something like this:
String QUERY = "select * from TABLE where";
if (FIRST_NAME!=null) {
QUERY = QUERY + " and FIRST_NAME='use_input_value'";
}
Notice the space before the and. We can also remove the space after where.
Now the query with both FIRST_NAME and LAST_NAME will look like this:
select * from TABLE where and FIRST_NAME='use_input_value' and LAST_NAME='use_input_value'
Better but now there's an extra and. We can fix that by adding a dummy always-true condition at the start of the query:
String QUERY = "select * from TABLE where 1=1";
Then we append a semicolon after all the conditions have been evaluated, and we have a valid query:
select * from TABLE where 1=1 and FIRST_NAME='use_input_value' and LAST_NAME='use_input_value';
(It may not be necessary to append the semicolon. Most databases don't require semicolons at the end of a single query like this.)
On to the string literals. You should add a placeholder instead, and simultaneously add the value you want to use to a List.
String QUERY = "select * from TABLE where";
List<String> args = new ArrayList<>();
if (FIRST_NAME!=null) {
QUERY = QUERY + " and FIRST_NAME=?";
args.add(FIRST_NAME);
}
After you've handled all the conditions you'll have a string with N '?' placeholders and a List with N values. At that point just prepare a query from the SQL string and add the placeholders.
PreparedStatement statement = conn.prepareStatement(QUERY);
for (int i = 0; i < args.size(); i++) {
statement.setString(i + 1, args[i]);
}
For some reason columns and parameters are indexed starting at 1 in the JDBC API, so we have to add 1 to i to produce the parameter index.
Then execute the PreparedStatement.

MySQL - Hibernate SQL Query

I created a query like this in my project with hibernate connected to a mysql database:
String sqlQuery = "select e.EXPEDITE_NUM_DISPLAY from receiver e where e.ID = 113";
List<Object> rows = session.createSQLQuery(sqlQuery).list();
The result list (rows) is a list with only one element with value = null (Ex. rows: [null]).
When i run the same query in MySQL workbench the value of the column is presented.
Any idea why in hibernate the returned value is null and not the right value?

How can I create a new table in a Hibernate Java web service without introducing a SQL injection flaw?

I have a Java web service that uses Hibernate. One of its methods is designed to create a new table in SQL Server, and that table isn't mapped to an object. The current design accepts the database name, schema name, table name, and the field definitions as arguments, and executes creates a query string from them, and then executes it. It works fine, but it is a SQL injection flaw.
Is there a way to create a table without introducing this flaw, for instance using a parameterized query, or using some feature in Hibernate I don't know about?
The flaw happens at the call to createSQLQuery:
String sSql = "CREATE TABLE [" + sDatabaseName + "].[" + sSchema + "].[" + sTableName + "] (" + sSqlFields + ")";
Session session = getSession();
Query q = session.createSQLQuery(sSql);
q.executeUpdate();
It's possible. You can parameterise a query like:
String sSql = "CREATE TABLE [ ? ].[ ? ].[ ? ] (?)";
Query q = session.createQuery(sSql);
q.setString(0, sDatabaseName)
.setString(1, sSchema)
.setString(2, sTableName)
.setString(3, sSqlFields )
.executeUpdate();

How to add selection criteria dyanmically in Java or SQL

I am trying to implement a functionality where I have to query a database with input parameter values. Input values are optional.
For example
I have a table student with following fields
a)student_id
b)student_roll_no
c)student_first_name
d)student_last_name .. etc
I am need to write a dao layer function so as to retrieve student details depending upon input criteria or parameters.
1) if Input contains only student_id then query should be
select * from student where student_id = :inputStudentId
2) if Input contains student_id, firstName then query should be
select * from student where student_id = :inputStudentId and first_name = :inputFirstName
like wise for other input parameters, please note input parameters can be 0 to n size
Please suggest what is the best approach to do it?
I dont wann add null checks and append the query for not null parameters. I want to try something reasonable and logical either in Java or sql (named query)
I am using java1.6 and hibernate
If you using Hibernate, you can use HSQL to do that in following manner:
query=em.createQuery("SELECT s FROM Student s WHERE s.id=:id");
query.setParameter("id",studentIt)
For exact API details, check the documentation # http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/Hibernate_User_Guide.html
You can also use CriteraApi - this is made for dynamic query creation.
You can do this by dynamically building your HQL with optional Parameters something like shown below:
Map<String, Object> parameters= new HashMap<String,Object>();
parameters.put("firstName", firstName);
parameters.put("lastName", lastName);
StringBuilder hql = "SELECT student FROM Student as student where 1 = 1";
if (firstName != null) {
hql.append(" and student.firstName in :firstName");
}
if (lastName != null) {
hql.append(" and student.lastName in :lastName ");
}
Query query = session.createQuery(hql.toString());
for (String p : query.getNamedParameters()) {
query.setParameter(p, parameters.get(p));
}

How to prevent SQL Injection with JPA and Hibernate?

I am developing an application using hibernate. When I try to create a Login page, The problem of Sql Injection arises.
I have the following code:
#Component
#Transactional(propagation = Propagation.SUPPORTS)
public class LoginInfoDAOImpl implements LoginInfoDAO{
#Autowired
private SessionFactory sessionFactory;
#Override
public LoginInfo getLoginInfo(String userName,String password){
List<LoginInfo> loginList = sessionFactory.getCurrentSession().createQuery("from LoginInfo where userName='"+userName+"' and password='"+password+"'").list();
if(loginList!=null )
return loginList.get(0);
else return null;
}
}
How will i prevent Sql Injection in this scenario ?The create table syntax of loginInfo table is as follows:
create table login_info
(user_name varchar(16) not null primary key,
pass_word varchar(16) not null);
Query q = sessionFactory.getCurrentSession().createQuery("from LoginInfo where userName = :name");
q.setParameter("name", userName);
List<LoginInfo> loginList = q.list();
You have other options too, see this nice article from mkyong.
You need to use named parameters to avoid sql injection. Also (nothing to do with sql injection but with security in general) do not return the first result but use getSingleResult so if there are more than one results for some reason, the query will fail with NonUniqueResultException and login will not be succesful
Query query= sessionFactory.getCurrentSession().createQuery("from LoginInfo where userName=:userName and password= :password");
query.setParameter("username", userName);
query.setParameter("password", password);
LoginInfo loginList = (LoginInfo)query.getSingleResult();
What is SQL Injection?
SQL Injection happens when a rogue attacker can manipulate the query
building process so that he can execute a different SQL statement than
what the application developer has originally intended
How to prevent the SQL injection attack
The solution is very simple and straight-forward. You just have to make sure that you always use bind parameters:
public PostComment getPostCommentByReview(String review) {
return doInJPA(entityManager -> {
return entityManager.createQuery("""
select p
from PostComment p
where p.review = :review
""", PostComment.class)
.setParameter("review", review)
.getSingleResult();
});
}
Now, if some is trying to hack this query:
getPostCommentByReview("1 AND 1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) )");
the SQL Injection attack will be prevented:
Time:1, Query:["select postcommen0_.id as id1_1_, postcommen0_.post_id as post_id3_1_, postcommen0_.review as review2_1_ from post_comment postcommen0_ where postcommen0_.review=?"], Params:[(1 AND 1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) ))]
JPQL Injection
SQL Injection can also happen when using JPQL or HQL queries, as demonstrated by the following example:
public List<Post> getPostsByTitle(String title) {
return doInJPA(entityManager -> {
return entityManager.createQuery(
"select p " +
"from Post p " +
"where" +
" p.title = '" + title + "'", Post.class)
.getResultList();
});
}
The JPQL query above does not use bind parameters, so it’s vulnerable to SQL injection.
Check out what happens when I execute this JPQL query like this:
List<Post> posts = getPostsByTitle(
"High-Performance Java Persistence' and " +
"FUNCTION('1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) ) --',) is '"
);
Hibernate executes the following SQL query:
Time:10003, QuerySize:1, BatchSize:0, Query:["select p.id as id1_0_, p.title as title2_0_ from post p where p.title='High-Performance Java Persistence' and 1 >= ALL ( SELECT 1 FROM pg_locks, pg_sleep(10) ) --()=''"], Params:[()]
Dynamic queries
You should avoid queries that use String concatenation to build the query dynamically:
String hql = " select e.id as id,function('getActiveUser') as name from " + domainClass.getName() + " e ";
Query query=session.createQuery(hql);
return query.list();
If you want to use dynamic queries, you need to use Criteria API instead:
Class<Post> entityClass = Post.class;
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<?> root = query.from(entityClass);
query.select(
cb.tuple(
root.get("id"),
cb.function("now", Date.class)
)
);
return entityManager.createQuery(query).getResultList();
I would like to add here that is a peculiar SQL Injection that is possible with the use of Like queries in searches.
Let us say we have a query string as follows:
queryString = queryString + " and c.name like :name";
While setting the name parameter, most would generally use this.
query.setParameter("name", "%" + name + "%");
Now, as mentioned above traditional parameter like "1=1" cannot be injected because of the TypedQuery and Hibernate will handle it by default.
But there is peculiar SQL Injection possible here which is because of the LIKE Query Structure which is the use of underscores
The underscore wildcard is used to match exactly one character in
MySQL meaning, for example, select * from users where user like
'abc_de'; This will produce outputs as users that start with abc, end
with de and have exactly 1 character in between.
Now, if in our scenario, if we set
name="_" produces customers whose name is at least 1 letter
name="__" produces customers whose name is at least 2 letters
name="___" produces customers whose name is at least 3 letters
and so on.
Ideal fix:
To mitigate this, we need to escape all underscores with a prefix .
___ will become \_\_\_ (equivalent to 3 raw underscores)
Likewise, the vice-versa query will also result in an injection in which %'s need to be escaped.
We should always try to use stored Procedures in general to prevent SQLInjection.. If stored procedures are not possible; we should try for Prepared Statements.

Categories