Spring Data JPA query returns null - java

My project based on spring boot,Thymeleaf,mysql,html and Jquery.
i wrote a query for checking user name and password is valid or not,if valid means return TRUE otherwise false..This is my scenario..but it passing null...so it becomes nullpointer exception..
Here is my code
public interface RepoUserSignup extends JpaRepository<EntUserSignup, Integer>
{
#Query("SELECT pk FROM EntUserSignup pk WHERE pk.username=:uname AND pk.password=:pwd")
Boolean checkUsername(#Param("uname") String username,#Param("pwd") String password);
}
Please help me..Thanks in advance

Your query return an Object and not a boolean so you have two ways :
Your method should return EntUserSignup checkUsername(#Param("uname") String username,#Param("pwd") String password); instead then check if there are a result or not
Another way is to check the number of result #Query("SELECT COUNT(pk) > 0 FROM EntUserSignup pk WHERE pk.username=:uname AND pk.password=:pwd") so if there are some results COUNT(pk) > 0 will return true else it will return false

Replace your method with this:
Optional<EntUserSignup> findByUsernameAndPassword(String username, String password);
Then in your business layer you can do something like this:
EntUserSignup user = findByUsernameAndPassword(username, password)
.orElseThrow(() -> new UsernameNotFoundException("User not found!"));
And of cause don't forget about password in plain text...
A good tutorial how to implement security in Spring Boot application...

i just change my return type
#Query("SELECT pk FROM EntUserSignup pk WHERE pk.username=:uname AND pk.password=:pwd")
EntUserSignup checkUsername(#Param("uname") String username,#Param("pwd") String password);
So when passing username and password matches menans it will return the entity value otherwise null.so we can decide there is no matched username and password.then we can write the logic as
#Service
public Boolean doCheckUserLogin(EntUserSignup user) {
Boolean result = false;
try {
EntUserSignup entResult = repoSignup.checkUsername(user.getUsername(),user.getPassword());
if(entResult!=null)
{
result = true;
}
else
{
result = false;
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
result = false;
}
return result;
}
This logics works perfectly...

Related

Problem to implement FindById to a return statement in java with MongoDB

UPDATE: The return statement is still not working as expected to show single user detail by id in the DAO. I could only use for loop to iterate through the _id to match the userId, but when I click the edit button for the number of user will show all previous user Id in the console.
Another problem is when I call this method in the Service class, the output is null. Still crave for the solution to help me get over it.
#Override
public User get(Object userId) {
User user = new User();
FindIterable<Document> userTbl = database.getCollection("User").find();
for (Document doc : userTbl) {
String id = doc.getObjectId("_id").toString();
System.out.println("_id = " + id);
if (id.equals(userId)) {
return user;
}
}
return null;
}
edit user in Service class
public void editUser() throws ServletException, IOException {
Object userId = request.getParameter("id"); // get query string from the jsp
User user = userDAO.get(userId);
System.out.println("User full name is? " + user.getFullName());
}
After getting hints from #Smutje and think through it again, finally figured it out at my 2nd weeks of learning MongoDB. At my level I need to iterate the user document then find the id and return it.it
#Override
public User get(Object userId) {
FindIterable<User> userTbl = database.getCollection("User", User.class).find();
for (User doc : userTbl) {
String id = doc.getId().toHexString();
System.out.println("_id = " + id);
if (id.equals(userId)) {
return doc;
}
}
return null;
}

is it possible to return "if condition satisfies return a list else return an error message" using a java method

I know that in Java a method can return only one return type... But if there is any possiblity to this, kindly let me know. From the below method I am trying to return a list if condition satisfies else i am trying to return an error message.
Here is my code:
#RequestMapping(value = "/getcompanies", method = RequestMethod.POST)
public List<CompanyMaster> getCompanies(#RequestBody UserDetails user) {
String OrgLoginId = user.getOrgLoginId();
String password = user.getuPassword();
String checkLoginId = null;
String uPassword = null;
String encPassword = null;
String loginId = null;
String checkAuthorized = null;
// String loginId=userService.getLoginId(OrgLoginId);
List<Object[]> CheckIdPassword = userService.checkLoginId(OrgLoginId);
List<Object[]> results = CheckIdPassword;
for (Object[] obj : results) {
checkLoginId = obj[0].toString();
if (null == obj[1]) {
uPassword = "";
} else {
uPassword = obj[1].toString();
}
loginId = obj[2].toString();
}
checkAuthorized = loginId.substring(0, 3);
if (null != password) {
MD5 md5 = new MD5();
encPassword = md5.getPassword(password);
}
if (checkLoginId == null) {
return "Incorrect loginId..Please enter valid loginId";
} else if (encPassword.equals(uPassword)) {
if (checkAuthorized.equals("STE")) {
List<CompanyMaster> companyList = userService.getCompanyList(OrgLoginId);
return companyList;
} else {
return "You are not Authorized";
}
} else {
return "Incorrect Password";
}
Yes its possible, create a custom Exception say 'MyAppException' and throw that exception with the error message you want.
Write your logic in a try{}catch block and throw the exception in catch so that the response has the error message
public List<CompanyMaster> getCompanies(#RequestBody UserDetails user) throws MyAppppException
{
try
{
//your logic which throws error
return companyList;
}
catch( final MyAppException we )
{
throw new MyAppException("User not found", HttpStatus.NOT_FOUND);
}
}
Refer this link
https://www.codejava.net/java-core/exception/how-to-create-custom-exceptions-in-java
You can achieve this by creating a new presenter Class which contains List and status of type String and change the return type of getCompanies method to presenter class like
public CompaniesPresenter getCompanies()
And your CompaniesPresenter class should look like
public class CompaniesPresenter {
private List<CompanyMaster> companyMaster;
private string status;
//default constructor
public CompaniesPresenter(){
}
//parameterized constructor to return only string in exception case
public CompaniesPresenter(Stirng status){
this.status = status;
}
//parametirized constructor to return success case
public CompaniesPresenter(List<CompanyMaster> companyMaster, Stirng status){
this.companyMaster = companyMaster;
this.status = status;
}
//getters and setters
}
This is how your updated method lokks like
#RequestMapping(value = "/getcompanies", method = RequestMethod.POST)
public CompaniesPresenter getCompanies(#RequestBody UserDetails user) {
String OrgLoginId = user.getOrgLoginId();
String password = user.getuPassword();
String checkLoginId = null;
String uPassword = null;
String encPassword = null;
String loginId = null;
String checkAuthorized = null;
// String loginId=userService.getLoginId(OrgLoginId);
List<Object[]> CheckIdPassword = userService.checkLoginId(OrgLoginId);
List<Object[]> results = CheckIdPassword;
for (Object[] obj : results) {
checkLoginId = obj[0].toString();
if (null == obj[1]) {
uPassword = "";
} else {
uPassword = obj[1].toString();
}
loginId = obj[2].toString();
}
checkAuthorized = loginId.substring(0, 3);
if (null != password) {
MD5 md5 = new MD5();
encPassword = md5.getPassword(password);
}
if (checkLoginId == null) {
return new CompaniesPresenter("Incorrect loginId..Please enter valid loginId");
} else if (encPassword.equals(uPassword)) {
if (checkAuthorized.equals("STE")) {
List<CompanyMaster> companyList = userService.getCompanyList(OrgLoginId);
return new CompaniesPresenter(companyList,"success");
} else {
return new CompaniesPresenter("You are not Authorized");
}
} else {
return new CompaniesPresenter("Incorrect Password");
}
This is not tested please make sure for any compilation errors
vavr's Either class would be a good choice.
The usage of custom exception is most reasonable solution. However, creating custom exception for just one case is not ideal always.
Another solution is to return empty List from your method, check if the List is empty in your servlet (or wherever you are invoking this method from), and show error message there.
It seems like you want to return multiple error messages for different cases. In this case, custom exception is recommended solution. If you don't like custom exceptions, you can return List<Object> and populate error message as the first element in the list. In the place where this List is obtained, check if the first element is instanceOf String or CompanyMaster. Based on what it is, you can perform your operations. This is a weird but possible solution (only if you don't like custom exceptions).
You need to understand the problem first. You are mixing two things here, first authorization, does the user has correct privileges to get company details, second giving the company details itself. Let's understand the first problem when a user tries to access "/getcompanies" endpoint will you let him in if does not have access, in REST world your security model should take care of it. I would use spring security to achieve this. My recommendation would be to explore on "interceptor" and solve the problem of invalid user. This will make your other problem easy as your "/getcompanies" endpoint can focus only on getting the details and return it (SRP).

Update row if references is exist, otherwise delete using spring boot

Need guideline -
How to do hard delete when no reference is available and do soft delete when reference is available, this operation should be performed in a single method itself.
E.g.
I have 1 master table and 3 transactional tables and the master reference is available in all 3 transactional tables.
Now while deleting master row - I have to do the following: If master reference is available then update the master table row and if no master ref. is available delete the row.
I tried following so far.
Service Implementation -
public response doHardOrSoftDelete(Employee emp) {
boolean flag = iMasterDao.isDataExist(emp);
if(flag) {
boolean result = iMasterDao.doSoftDelete(emp);
} else {
boolean result = iMasterDao.doHardDelete(emp);
}
}
Second Approach:
As we know that while deleting a record if the reference is available then it throws ConstraintViolationException so simply we can catch it and check that caught exception is of type ConstraintViolationException or not, if yes then call doSoftDelete() method and return the response. So here you don't need to write method or anything to check the references. But I'm not sure whether it is the right approach or not. Just help me with it.
Here is what I tried again -
public Response deleteEmployee(Employee emp) {
Response response = null;
try{
String status= iMasterDao.deleteEmployeeDetails(emp);
if(status.equals("SUCCESS")) {
response = new Response();
response.setStatus("Success");
response.setStatusCode("200");
response.setResult("True");
response.setReason("Record deleted successfully");
return response;
}else {
response = new Response();
response.setStatus("Fail");
response.setStatusCode("200");
response.setResult("False");
}
}catch(Exception e){
response = new Response();
Throwable t =e.getCause();
while ((t != null) && !(t instanceof ConstraintViolationException)) {
t = t.getCause();
}
if(t instanceof ConstraintViolationException){
boolean flag = iMasterDao.setEmployeeIsDeactive(emp);
if(flag) {
response.setStatus("Success");
response.setStatusCode("200");
response.setResult("True");
response.setReason("Record deleted successfully");
}else{
response.setStatus("Fail");
response.setStatusCode("200");
response.setResult("False");
}
}else {
response.setStatus("Fail");
response.setStatusCode("500");
response.setResult("False");
response.setReason("# EXCEPTION : " + e.getMessage());
}
}
return response;
}
Dao Implementation -
public boolean isDataExist(Employee emp) {
boolean flag = false;
List<Object[]> tbl1 = session.createQuery("FROM Table1 where emp_id=:id")
.setParameter("id",emp.getId())
.getResultList();
if(!tbl1.isEmpty() && tbl1.size() > 0) {
flag = true;
}
List<Object[]> tbl2 = session.createQuery("FROM Table2 where emp_id=:id")
.setParameter("id",emp.getId())
.getResultList();
if(!tbl2.isEmpty() && tbl2.size() > 0) {
flag = true;
}
List<Object[]> tbl3 = session.createQuery("FROM Table3 where emp_id=:id")
.setParameter("id",emp.getId())
.getResultList();
if(!tbl3.isEmpty() && tbl3.size() > 0) {
flag = true;
}
return flag;
}
public boolean doSoftDelete(Employee emp) {
empDet = session.get(Employee.class, emp.getId());
empDet .setIsActive("N");
session.update(empDet);
}
public boolean doHardDelete(Employee emp) {
empDet = session.get(Employee.class, emp.getId());
session.delete(empDet);
}
No matter how many transactional tables will be added with master tbl reference, my code should do the operations(soft/hard delete) accordingly.
In my case, every time new transactional tables get added with a master reference I've do the checks, so Simply I want to skip the isDataExist() method and do the deletions accordingly, how can I do it in a better way?
Please help me with the right approach to do the same.
There's a lot of repeated code in the body of isDataExist() method which is both hard to maintain and hard to extend (if you have to add 3 more tables the code will double in size).
On top of that the logic is not optimal as it will go over all tables even if the result from the first one is enough to return true.
Here is a simplified version (please note that I haven't tested the code and there could be errors, but it should be enough to explain the concept):
public boolean isDataExist(Employee emp) {
List<String> tableNames = List.of("Table1", "Table2", "Table3");
for (String tableName : tableNames) {
if (existsInTable(tableName, emp.getId())) {
return true;
}
}
return false;
}
private boolean existsInTable(String tableName, Long employeeId) {
String query = String.format("SELECT count(*) FROM %s WHERE emp_id=:id", tableName);
long count = (long)session
.createQuery(query)
.setParameter("id", employeeId)
.getSingleResult();
return count > 0;
}
isDataExist() contains a list of all table names and iterates over these until the first successful encounter of the required Employee id in which case it returns true. If not found in any table the method returns false.
private boolean existsInTable(String tableName, Long employeeId) is a helper method that does the actual search for employeeId in the specified tableName.
I changed the query to just return the count (0 or more) instead of a the actual entity objects as these are not required and there's no point to fetch them.
EDIT in response to the "Second approach"
Is the Second Approach meeting the requirements?
If so, then it is a "right approach" to the problem. :)
I would refactor the deleteEmployeeDetails method to either return a boolean (if just two possible outcomes are expected) or to return a custom Enum as using a String here doesn't seem appropriate.
There is repeated code in deleteEmployeeDetails and this is never a good thing. You should separate the logic which decides the type of the response from the code that builds it, thus making your code easier to follow, debug and extend when required.
Let me know if you need a code example of the ideas above.
EDIT #2
Here is the sample code as requested.
First we define a Status enum which should be used as return type from MasterDao's methods:
public enum Status {
DELETE_SUCCESS("Success", "200", "True", "Record deleted successfully"),
DELETE_FAIL("Fail", "200", "False", ""),
DEACTIVATE_SUCCESS("Success", "200", "True", "Record deactivated successfully"),
DEACTIVATE_FAIL("Fail", "200", "False", ""),
ERROR("Fail", "500", "False", "");
private String status;
private String statusCode;
private String result;
private String reason;
Status(String status, String statusCode, String result, String reason) {
this.status = status;
this.statusCode = statusCode;
this.result = result;
this.reason = reason;
}
// Getters
}
MasterDao methods changed to return Status instead of String or boolean:
public Status deleteEmployeeDetails(Employee employee) {
return Status.DELETE_SUCCESS; // or Status.DELETE_FAIL
}
public Status deactivateEmployee(Employee employee) {
return Status.DEACTIVATE_SUCCESS; // or Status.DEACTIVATE_FAIL
}
Here is the new deleteEmployee() method:
public Response deleteEmployee(Employee employee) {
Status status;
String reason = null;
try {
status = masterDao.deleteEmployeeDetails(employee);
} catch (Exception e) {
if (isConstraintViolationException(e)) {
status = masterDao.deactivateEmployee(employee);
} else {
status = Status.ERROR;
reason = "# EXCEPTION : " + e.getMessage();
}
}
return buildResponse(status, reason);
}
It uses two simple utility methods (you can make these static or export to utility class as they do not depend on the internal state).
First checks if the root cause of the thrown exception is ConstraintViolationException:
private boolean isConstraintViolationException(Throwable throwable) {
Throwable root = throwable;
while (root != null && !(root instanceof ConstraintViolationException)) {
root = root.getCause();
}
return root != null;
}
And the second one builds the Response out of the Status and a reason:
private Response buildResponse(Status status, String reason) {
Response response = new Response();
response.setStatus(status.getStatus());
response.setStatusCode(status.getStatusCode());
response.setResult(status.getResult());
if (reason != null) {
response.setReason(reason);
} else {
response.setReason(status.getReason());
}
return response;
}
If you do not like to have the Status enum loaded with default Response messages, you could strip it from the extra info:
public enum Status {
DELETE_SUCCESS, DELETE_FAIL, DEACTIVATE_SUCCESS, DEACTIVATE_FAIL, ERROR;
}
And use switch or if-else statements in buildResponse(Status status, String reason) method to build the response based on the Status type.

How to get username inside CustomPasswordEncoder in SpringSecurity?

I am introducing Spring Security in an existing application. Currently db has MD5 encoded passwords which we want to migrate to bcrypt. Since we have a large number of users initially we would like to support both MD5 and bcrypt together. We have thought off having a table which will store how many users are migrated to bcrypt once we have every one migrated we will stop supporting MD5.
So I thought of extending the BCryptPasswordEncoder class of SpringSecurity and do the things inside matches method. So I have below class,
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class CustomPasswordEncoder extends BCryptPasswordEncoder {
#Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if (rawPassword == null || encodedPassword == null) {
return false;
}
if (!super.matches(rawPassword, encodedPassword)) { // This is not BCrypt password try OLD password encoding instead
boolean isOldPasswordMatched = rawPassword.equals(SHA1.getSHA1Hash(encodedPassword));
if(isOldPasswordMatched){
migrateToBCrypt(userName /* error here*/, encode(rawPassword));
}
return isOldPasswordMatched;
}
return true;
}
private boolean migrateToBCrypt(String userName, String newBcryptPassword){
//update password in database
//Insert to migrated table
return true;
}
}
However my problem is I don't get username inside this function to do the migration, How can I get username inside matches() of password encoder ? Am I doing something wrong here ? What could be the best approach in this situation ?
The proposed logic is just my idea, you can modify it as per your needs.
public class UserService extends BCryptPasswordEncoder{
public Response login(#RequestBody User user){
User existingUser = UserDao.getInstance().getUserByUsername( user.getUsername() );
//Assuming all the users have `PasswordType` column as "MD5" in user table
if( existingUser.getPasswordType().equals("MD5") ){
// Your MD5 verification method, return boolean
if( verifyMD5(user.getPassword, existingUser.getPassword()) ){
migrateToBCrypt(existingUser, user);
return Response.status(200).entity("Successfully Logged in").build();
}else{
return Response.status(400).entity("Invalid Credentials").build();
}
}else if( existingUser.getPasswordType().equals("BCrypt") ){
if( matches(user.getPassword(), existingUser.getPassword()) ){
return Response.status(200).entity("Successfully Logged in").build();
}else{
return Response.status(400).entity("Invalid Credentials").build();
}
}
}
private void migrateToBcrypt(User existingUser, User user){
existingUser.setPassword( encode(user.getPassword()) );
existingUser.setPasswordType( "Bcrypt" );
UserDao.getInstance().updateUser( existingUser );
}
}
Or if you don't want to introduce another column on table,
public class UserService extends BCryptPasswordEncoder{
public Response login(#RequestBody User user){
User existingUser = UserDao.getInstance().getUserByUsername( user.getUsername() );
if( !existingUser.getPassword().startsWith("$") ){
// Your MD5 verification method, return boolean
if( verifyMD5(user.getPassword, existingUser.getPassword()) ){
migrateToBCrypt(existingUser, user);
return Response.status(200).entity("Successfully Logged in").build();
}else{
return Response.status(400).entity("Invalid Credentials").build();
}
}else {
if( matches(user.getPassword(), existingUser.getPassword()) ){
return Response.status(200).entity("Successfully Logged in").build();
}else{
return Response.status(400).entity("Invalid Credentials").build();
}
}
}
private void migrateToBcrypt(User existingUser, User user){
existingUser.setPassword( encode(user.getPassword()) );
UserDao.getInstance().updateUser( existingUser );
}
}

How can I compare request.getParameter(string) in Controller class with MySQL database?

I'm currently working on a (relatively) basic web application that functions as a time clock for a fictional employer. Currently, the application implements HTML, JavaScript, Java, MySQL, the Spring Framework and xml. I have a log in page, and it takes the user input for the Username and Password and stores the information. The problem is, I can't seem to figure out how to take that information and compare it with the MYSQL database to successfully log in. I can post examples of code, if necessary and thanks in advance for the assistance.
This is a piece of the LoginController:
#RequestMapping(value = "/jsp/login")
public ModelAndView existUser(HttpServletRequest request) {
return new ModelAndView("UserPrint.jsp", hashmap.makeHashMap());
}
#RequestMapping(value = "userLogin")
public ModelAndView loginUser(HttpServletRequest request,
HttpSession session) {
String strLoginJsp = "login.jsp";
String strSessionErrorAttribute = "errors";
User sessionUser = getUserFromSession(session);
if (request.getHeader("referer") == null
|| request.getHeader("referer").contains("AddNewUser.html")) {
session.setAttribute(SESSION_USER_ATTRIBUTE, new User());
session.setAttribute(strSessionErrorAttribute, "");
return new ModelAndView(strLoginJsp, hashmap.makeHashMap());
}
User requestUser = new User();
String requestedUserName = request.getParameter("userName");
requestUser.setUserName(requestedUserName);
String requestedPassword = request.getParameter("password");
requestUser.setPassword(requestedPassword);
session.setAttribute(strSessionErrorAttribute, "");
// Check if username and password is in DB
User loginUser = userDao.login(requestUser);
if (loginUser == null) {
// Either the username doesn't exist, or the password was bad.
if (userDao.userNameExist(requestedUserName)) {
// user entered bad password
if (sessionUser.getUserName() != null
&& sessionUser.getUserName().equals(
requestUser.getUserName())) {
} else {
sessionUser.setUserName(requestUser.getUserName());
}
}
} else {// username does not exist in db
session.setAttribute(strSessionErrorAttribute,
"Please register account.");
Here's a piece of the UserDao:
#SuppressWarnings("unchecked")
#Transactional
public List<User> getAllUsers() {
Query query = em.createNamedQuery("fetchAllUsers");
return query.getResultList();
}
public User login(User user) {
Query query = em.createNamedQuery("userLogin");
query.setParameter("userName", user.getUserName());
query.setParameter("password", user.getPassword());
List<User> currentUsers = query.getResultList();
if (currentUsers.size() > 0) {
return (User) currentUsers.get(0);
}
return null;
}
#SuppressWarnings("unchecked")
#Transactional
public Boolean userNameExist(String userName) {
Query query = em.createNamedQuery("getUserWithUsername");
query.setParameter("userName", userName);
List<User> existUser = query.getResultList();
if (existUser.size() > 0) {
return true;
}
return false;
}
To expand on dm03514 's answer - yes you should "sanitize" user input by using prepared statement objects in Java JDBC.
If you're using Spring then you should use spring-security. They have pretty much done this for you already and you just have to configure it.
Normally you would take your login and password and search for a user
String queryStr = "SELECT * FROM users WHERE login='"+sanitize(userLogin)+"' AND password='"+sanitize(userPass)"'";
This is not actual code just psuedo code. I do not know how java or spring handles sanitation but it is of utmost importance that you dont' trust anything input by the user when you are building a query string.
The idea is if this results in 1 user the user is valid, if it returns none the user is not valid!
Using paramaterized queries could be the best approach
Yes, please, post some code.
What exactly is the issue?
On the most basic level you should be able to:
pass the username and password as parameters in the HttpServletRequest object
Retrieve said parameters by "name" from the HSR object in the Controller.
Pass them to the SQL query for comparison against the database field.
Which of the above steps failed?

Categories