Fetching particular value from entity in GAE DataStore without PersistantManager - java

I'm trying to register a user and allow him to login with userName and Password. My dataStore entity "Racer" contains Name, UserName, Password, Age, BikeModel, City. Key is generated by the application.
I want to validate user. I used query with addFilter() to get the entire details of a particular user. I am struck with getting a particular property of a particular user from the entity in dataStore, say, Password and UserName of a particular user from "Racer".
Over the web, whichever example i got, it was using PersistentManager. I don't want to use it. I don't find any query to fetch details other than Filter and Sort. Please suggest me how to proceed.
Servlet:
public class StoreInDataStore extends HttpServlet {
#SuppressWarnings("deprecation")
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException {
//Getting SignUp form values
String name=req.getParameter("name1");
String uname=req.getParameter("uname1");
String pswd=req.getParameter("pswd1");
String age=req.getParameter("age");
String city=req.getParameter("city");
String bike=req.getParameter("bike");
//Getting login form values
String lname=req.getParameter("name");
String lpswd=req.getParameter("pswd");
//Creating dataStore
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
//Creating entity
Entity e=new Entity("Racer");
//Entering details in racer
e.setProperty("Name", name);
e.setProperty("UserName", uname);
e.setProperty("Password", pswd);
e.setProperty("Age", age);
e.setProperty("City", city);
e.setProperty("Bike Model", bike);
//Storing in DataStore
ds.put(e);
//Getting entire details
Query q=new Query("Racer");
q.setFilter(FilterOperator.EQUAL.of("UserName", uname));/* UserName takes only the currently entered value(uname). Doesnot fetch from dataStore */
PreparedQuery pq=ds.prepare(q);
List<Entity> result = ds.prepare(q).asList(FetchOptions.Builder.withDefaults());
System.out.println(result);
}

Instead of
List<Entity> result = ds.prepare(q).asList(FetchOptions.Builder.withDefaults());
use
Entity result = ds.prepare(q).asSingleEntity();
String password = result.getProperty("Password");

Related

Unable to pass the extra parameter to Spring-Security with OAuth2.0

Good Day.
I have a requirement to implement OAuth2 with spring-security using springboot2 basing on below URL.
URL Name:
https://www.devglan.com/spring-security/spring-boot-oauth2-jwt-example
And I did it.
Here I got another different requirement for the above code in authenticating user.
I need to pass companyId along with userName and password and grant_type(password)in x-www-form-urlencoded tab in postman tool.
And i have to fetch User based on username and companyId.
So please help me out what changes I need to do in above link code so that i can achieve my requirement.
Here i am getting only email. I need email along with companyId.
#Override
#Transactional
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email).orElseThrow(
() -> new UsernameNotFoundException("User Not Found with -> username or email : " + email));
return UserPrinciple.build(user);
}
Expected:
#Override
#Transactional
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmailAndCompanyId(email,companyId).orElseThrow(
() -> new UsernameNotFoundException("User Not Found with -> username or email : " + email));
return UserPrinciple.build(user);
}
At present with username and password it is working fine.
But in my system i have same user mapped to different companies.if same user mapped to multiple companies found i am getting error like below.
{
"error": "unauthorized",
"error_description": "query did not return a unique result: 2; nested exception is javax.persistence.NonUniqueResultException: query did not return a unique result: 2"
}
I need to fetch user, based on username and password and companyId which results in single user.
Can some one help on this issue. Thanks a lot in advance.
Bhanuprakash, i have a similar problem but temporary i did this:
In the "loadUserByUsername" method write this:
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
System.out.println("compnayId: " + request.getParameter("companyId"));
I think there is a more elegant solution, but temporary i used this.
Thanks.
If you want additional information's with access tokens you can use TokenEnhancer class to do that.
CustomTokenEnhancer.java
public class CustomTokenEnhancer implements TokenEnhancer {
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
User user = (User) authentication.getPrincipal();
final Map<String, Object> additionalInfo = new HashMap<>();
additionalInfo.put("id", user.getCompanyId());
additionalInfo.put("authorities", user.getAuthorities());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
return accessToken;
}
}
Then user the instance of this class to void configure(AuthorizationServerEndpointsConfigurer endpoints) method like this
AuthorizationServerConfig.java
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
.tokenEnhancer(new CustomTokenEnhancer());
}
This comment worked for me perfectly!
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getRequest();
System.out.println("compnayId: " + request.getParameter("companyId"));

Send more than one attribute for the request.setAttribute ()

I am developing a web page where on the homepage (in my case it is my "Home" servlet) I wish to present information about several tables as well as queries to them. What I have achieved is to obtain the information of my company / brands table and show the last companies added, the detail is that I do not know how to send more than one attribute for the request.setAttribute () since I want to show in my homepage information of my users table and show my featured users as well as my table news show the last post (news from suppliers). I hope and I can help myself since I am super stuck with this.
This is my code for my servlet.
public class InicioController extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
RequestDispatcher rd;
//Connection DB
conexion conn = new conexion();
//send objectd Connection to the constructor of myDAO class
HomeDAO fun = new HomeDAO(conn);
List<companies> list1 = new LinkedList<>();
List<users> list2 = new LinkedList<>();
List<postNews> list3 = new LinkedList<>();
// call to the method that gets the information from my companies table
list1=fun.ShowCompanies("");
// call to the method that gets the information from my Users table
list2=fun.LastUsers("");
// call to the method that gets the information from my Posts table
list3=fun.News("");
//disconnect DB
conn.desconectar();
//how to send more than one attribute "request.setAttribute ()"
request.setAttribute("Companies", list1);
rd = request.getRequestDispatcher("/index.jsp");
rd.forward(request, response);
}
}
Why can't you have an object that will contain all three lists, plus whatever other objects you want to "pass" to your JSP? Your attribute will contain that single object in an attribute and the JSP can sort it out. It's good design also, because that way you have in one class, all the "parameters" that the specific JSP expects.

Spring (Hibernate) updating issue

I have an issue in Spring (or Hibernate) with checking for data existence in DB till updating. I want to update user’s profile and I can change Name, Password and Email fields. Name and Password hasn’t to be unique but Email has to. I show the form with fields filled by user’s old data, when I enter new data not changing Email it, of course, shows that it is already exists. If delete this check I’ll have two same emails in base. How can I set same data for certain user?
My method for update with checking email.
public void updateUser(User user) throws NotUniqueEmailException {
if (user == null) {
throw new NullPointerException();
}
if (user.getUserId() < 1) {
throw new IllegalArgumentException();
}
if (user.getEmail() == null || user.getEmail().intern().equals("")) {
throw new IllegalArgumentException();
}
if (getUserByEmail(user.getEmail()).getEmail() != null) {
throw new NotUniqueEmailException("The email of user not unique! " + user.getEmail());
}
currentSession().update(user);
// currentSession().saveOrUpdate(user);
}
And I’ve one more method for checking for existence.
public boolean isEmailExists(User user) {
Session session = HibernateUtil.openSession();
boolean result = true;
Query query = session.createQuery("SELECT u FROM User u WHERE u.email=?");
query.setString(0, user.getEmail());
User u = (User) query.uniqueResult();
if (u == null) {
result = false;
}
return result;
}
Update controller
#RequestMapping(value = "/edit/{userId}", method = RequestMethod.GET)
public String updateView(#PathVariable("userId")Integer userId,
UserForm userForm,
HttpSession session,
ModelMap model){
User user=userService.getUserById(userId);
userForm.setUser(user);
model.addAttribute("userForm",userForm);
return"profileupdate";
}
#RequestMapping(value = "/edit.do/{userId}", method = RequestMethod.POST)
public String updateUserProcess(#ModelAttribute(value = "userForm")
UserForm userForm,
#PathVariable("userId")Integer userId,
BindingResult result,Model model,
HttpSession session,
HttpServletRequest request){
User user=userService.getUserById(userId);
session.getAttribute("userForm");
model.addAttribute("userForm",userForm);
updateValidator.validate(userForm,result);
if(result.hasErrors()){
logger.error("Validation error");
return"profileupdate";
}
return updatingUser(userForm,user,model,request);
}
private void fillForm(UserForm userForm,User user){
userForm.setUserId(user.getUserId());
userForm.setLogin(user.getLogin());
userForm.setRegDate(user.getRegDate());
userForm.setComputers(userService.getAllUsersComputers(user.getLogin()));
userForm.setRole(roleService.findByName(user.getRole().getRoleName()));
}
private String updatingUser(UserForm userForm,User user,Model model,HttpServletRequest request){
fillForm(userForm,user);
user=userForm.getUser();
try{
userService.updateUser(user);
logger.info("User updated!");
request.getSession().setAttribute("user",user);
return"newprofile";
}catch(NotUniqueEmailException e){
logger.error("Can't update user - not unique email!!",e);
model.addAttribute("errorMsg","Email is already in use!");
return"profileupdate";
}
}
EDIT : add elements for Hibernate persistence methods
If you want Hibernate to automagically know that it should do an an update and not an insert, the primary key has to be set in user. As you say the fields have been modified, I suppose user fields come from a form input. You have two ways to keep the id :
store it in a hidden input field in your form - on submit, spring will populate it
have it in a path variable, get it in your controller and populate it yourself (#RequestMapping(/.../{id}) public String method(#PathVariable("id") user_id, ...))
But it may not be enough and you could have a merge vs update vs saveOrUpdate problem. This other post from SO could give indications Hibernate : Downside of merge over update
compare the args user.getId() with u.getId()

How to handle no entity in database for entered parameters?

I am trying to implement simple login system. I have a JSP with form where user enters username and password, and then servlet that is reading those parameters. You'll understand from servlet code:
User user = userDao.findUserWithUsernameAndPassword(username, password);
// user found
if (user!=null) {
session = request.getSession(true);
session.setAttribute("user", user);
loginMessage = "Welcome";
request.setAttribute("loginMessage", loginMessage);
RequestDispatcher dispatcher = request.getRequestDispatcher("login.jsp");
dispatcher.forward(request, response);
} else // username and password not matching
{
loginMessage = "Wrong username or password! Please try again.";
request.setAttribute("loginMessage", loginMessage);
RequestDispatcher dispatcher = request.getRequestDispatcher("login.jsp");
dispatcher.forward(request, response);
}
This works if I enter valid username and password, but if not I am getting next exception:
javax.persistence.NoResultException: Query "SELECT u FROM User u WHERE
u.username like :username AND u.password LIKE :password" selected no
result, but expected unique result.
What is the proper way of handling this situation? I would like for wrong username and password parameters to display appropriate message (forwarding in 'loginMessage' variable).
[added]This is the code in UserDAOBean:
#Stateless
#Local(UserDAOLocal.class)
#TransactionManagement(TransactionManagementType.CONTAINER)
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class UserDAOBean extends GenericDAOBean<User, Integer> implements UserDAOLocal{
public User findUserWithUsernameAndPassword(String username, String password)
{
Query q = em.createNamedQuery("findUserWithUsernameAndPassword");
q.setParameter("username", username);
q.setParameter("password", password);
User result = (User) q.getSingleResult();
return result;
}
}
And named query in entity User is:
#NamedQuery(name = "findUserWithUsernameAndPassword", query = "SELECT
u FROM User u WHERE u.username like :username AND u.password LIKE
:password")
This Exception is throw by the entity manager when you call the method getSingleResult and there is no resul, so you need to change the findUserWithUsernameAndPassword method.
If you are searching the entity by it's Primary Key you could use the em.find, it method returns null if there is no result.
Another option is not use the getSingleResult() and use the getResultList() it will not throw the NoResultException if there is no result, you need to check if the list is empty if there is no result.
If you want to maintain your method you must to catch the Exception and implements the logic where there is no result.

How can I secure a JSP page after adding it to my hosting and making it live?

I have a very basic login JSP that passes the variables to the servlet and checks from a MySQL DB if the username and password are available. Is this secure enough to use on a website, or does it need more security? If so, how to make it more secure?
This is the servlet:
import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.*;
import java.sql.*;
/**
* Servlet implementation class loginServlet
*/
#WebServlet("/loginServlet")
public class loginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #seeHttpServlet#HttpServlet()
*/
public loginServlet() {
super();
// TODOAuto-generated constructor stub
}
/**
* #seeHttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODOAuto-generated method stub
}
/**
* #seeHttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
String email = request.getParameter("email");
String pwd = request.getParameter("pass");
try {
Class.forName("com.mysql.jdbc.Driver");
Connection con =
DriverManager.getConnection("jdbc:mysql://localhost:3306/logindb",
"root", "password");
Statement st = con.createStatement();
ResultSet rs;
rs = st.executeQuery("select fname, lname, email from userAccount where Email='"
+ email + "' and password='" + pwd + "'");
if (rs.next()) {
session.setAttribute("email", email);
session.setAttribute("Fullname", rs.getString(1) + " " + rs.getString(2));
response.sendRedirect("success.jsp");
} else {
response.sendRedirect("fail.jsp");
}
} catch (Exception ssd) {
System.out.println(ssd.getMessage());
}
}
}
There are several security issues, and programming problems, with this code:
unless the application is served over HTTPS, the password passes in clear text over the network
passwords should not be stored in clear in a database. They should be salted using a random salt, and then hashed using a slow cryptographic algorithm like bcrypt. To check the password, you should salt and hash the input from the user, and compare the result with the salted and hashed password stored in the database
your code doesn't use prepared statements, opening itself to SQL injection attacks
your code doesn't use prepared stataments, which will make it fail, for example, as soon as there is a single quote inside the email or the password.
you shouldn't catch Exception. Only catch exceptions that you can handle, and that are supposed to happen. For unexpected exceptions, displaying a generic error page is fine. For expected exceptions, you should handle them. Your catch block logs something in the server console, and leaves the user with a blank page.
Is this secure enough to use on a website, or does it need more
security? If so, how to make it more secure?
No. this is not enough secure. You need to use form-based authentication, store password as hash and restrict direct resource invocation. For that, I prefer Spring Security. Following benefits you will get from Spring Security.
Basic Spring Security configuration
OpenID integration
Access Control List (ACL)
JDBC-based configuration
Remember-me services
LDAP-based authentication
Single Sign-on services
JSF and GWT integration
and many more
The above is insecure for the following reasons,
SQL Injection: If you see the below code, you are directly appending the user input to the SQL query. So lets say a user provided the email as "';drop table userAccount;". This would drop the table.
rs = st.executeQuery("select fname, lname, email from userAccount where Email='"+
email + "' and password='"+ pwd + "'");
Never show stack trace to user: If the code above throws any exception inside the try block, you are catching it and printing in console. But there is no response being sent. You can redirect the user to fail.jsp in that case as well.
Use Capcha or any token mechanism to avoid automated submissions.
It looks like your password is not hashed in the database. So before storing the password in the database call eg sha256 (https://stackoverflow.com/a/5531479/514463) and then when you are looking up the password in your above servlet do it again.
st.executeQuery("select fname, lname, email from userAccount where Email='"+ email + "' and password='"+ sha256(pwd) + "'");
Furthermore - you are not using bind variables in your sql so your code is open to sql injection which means someone could pass in as a password somehtlin like
"password; delete from users;"
and after your sql is executed the users table could all be deleted. Always use prepared statements
dbConnection.prepareStatement("select fname, lname, email from userAccount where Email=? and password=?" );
passing in your username and sha256(password)
You definitely should not store crear passwords so if you are hacked the hacker does not get the passwords.
You should digest them with a non-reversible algorithm (SHA-1 recommended) with salt.
Salt is a protection against rainbow tables.

Categories

Resources