I have a simple small application which involves an admin having the ability to update and delete information or individual user's from a database. Basically, so far the administrator can view all the current registered user's in a table format on a page. I need to know how I can delete or update the user information based on the user in each row, so assuming based on their actual userID. So far I have been able to extract all the user's from the database and put them into a table, and using JSTL fill in the necessary table values(username, email, etc..).
I do not know, the proper process for doing this, and do not know how to code up the controller to handle this specific task. So far my controller is like this:
#RequestMapping("/deleteUser")
public String deleteUser(#RequestParam(value = "id", required= false) Integer id) {
usersService.delete(id);
return "users";
}
where the request mapping comes from a button in the table, and "return users;" just returns back to the same jsp page which displays all the users. This is a little buggy, and I would like to know what would be the proper and best way to implementing this functionality.
Check the users Authority with the Principal.
#RequestMapping("/deleteUser")
public String deleteUser(#RequestParam(value = "id", required= false, Principal princiapl) Integer id) {
// Check if user has admin authority using principal.getAuthorities();
}
You could also use the #Secured("ROLE_ADMIN") annotation and lock down the method to the admin role.
Related
I have users registration controller in my Spring Boot project with spring-boot-starter-data-jpa and spring-boot-starter-web dependencies, which implements the following logic, where usersRepository is an instance of standard CrudRepository:
#PostMapping
public String processRegistrationForm(#Valid #ModelAttribute("registrationForm") UserForm form,
Errors errors, Model model) {
if (!errors.hasErrors()) {
UserEntity user = usersRepository.findByUsername(form.getUsername());
if (user != null) {
errors.rejectValue("username", "registration.username.not.unique");
} else {
usersRepository.save(form.toUserEntity(passwordEncoder));
model.addAttribute("isRegistrationComplete", true);
}
}
return "registration";
}
The method first checks whether the user with the given username exists, and if not - saves it into the database. The problem here is that this check-then-act behavior may result in DataIntegrityViolationException (with the underlying unique username constraint violation) if someone intervenes in between findByUsername() and save() calls and manages to save the user with the same username into the database. How can I avoid this? And would making the whole method #Transactional solve this problem?
It seems you want to create an entity but not overwrite it, and in an atomic operation you cannot test for existence first.
You could, however put a unique key on your resource and then simply go for the create option. If that entity (with that specific key) already exists you should receive an exception telling you about duplicate data. Now you can still decide whether you want to error out or simply update the existing entry.
Edit: Reading the other comments: your unique key is probably the user name, and you want to error out saying that the chosen user name is already in use.
Edit2: So you mention that my suggestion is what you had implemented but you were not happy. I think you did not suffer from performance but did not like the code (parsing - see my comment) or the user behaviour.
A user just fills in a form to register and while being delayed by a captcha or some bad password pattern all of a sudden that user name is taken by someone else. Not a nice situation.
You will only resolve it by acting as soon as a user tries to register with a name. Upon the first such check (and when you return the status that the user is still available) create the entity with an attribute that this is just a placeholder. While the user still fills in the registration form other users already can see the name is taken.
For all cases where a registration is not finished and thus names are blocked for nothing, have a garbage collector job that removes all placeholders after some time. So if a placeholder has not completed to a full user account within one hour, just remove that entry from the DB and another user is free to reuse the name.
I'm in the middle of fumbling around with JPA. I've so far successfully created an entity representing the user data and a stateless bean for the access to the user data.
The data the users can work on is like this (SQLFiddle link):
CREATE TABLE data
(
email character varying(128) NOT NULL,
data character varying(128) NOT NULL,
lastchange timestamp NOT NULL,
CONSTRAINT email_data PRIMARY KEY (email,data)
);
The idea is to save the unaltered, current version for all users with an empty email key. Then, when a user alters the data and creates an auditable version, the email field is filled with the users email. This way, each user can alter their copy of the data. The merging is a problem for a later date and not part of my question.
Now, I have the entities already in place. I created a stateless bean to load/save/find the data records by using the EntityManager. The logic to load the user specific version first, then load the unaltered version if the user has no user specific version still eludes me.
Consider this part of the bean:
#Stateless
public class DataBean {
#PersistenceContext(unitName = "authPU")
private EntityManager em;
public List<DataEntry> findAll() {
TypedQuery<DataEntry> query = em.createQuery("SELECT d FROM data d", DataEntry.class);
List<DataEntry> list = query.getResultList();
return query.getResultList();
}
...
}
How do I inject the user information into this class? I need to get the data for the current user first, then get the data for all users if there's no user-specific data available.
You could use standard EJB authentication. Then you can call SessionContext.getCallerPrincipal() in your session bean to get a user ID. Use this user ID to query the database.
In this case you have to add another column to your table (containing the user ID), if the authentication user ID does not equal the email address.
Far simpler (but less elegant) is to add the email address to the arguments of your EJB service method: Just make it part of the public API.
I'm using Struts 2, my problem is that I don't want to update all my object properties because I got some sensitive data.
Here is my code example
public class person {
private name;
private email;
private password;
}
In my form for example I display the name and email for update ,so when I update my person properties after submission ,the password property of the person gets the value null,but when I put the property password in the <s:hidden> tag in the form the update works fine.
How to make Struts 2 remember the value of the password without using the hidden tag in the form ?
If you need to store informations that
must be persistent across the requests;
must not be shown in the page;
then you have to use the Session, by implementing SessionAware:
That said, I'm not sure you should store the user password, nor associate passwords to users;
You should make a login page in your web application, handling the password in that Action only, validating it against the database (or whatever), and storing some authentication id in the Session, not the password itself (you won't validate the user again, unless the session expires, then the user will be redirected to login page... no need to keep the password in memory).
That said too, the best practices for user authentication discourage to validate entered passwords against stored passwords on database;
you should use some one-way hashing algorithm (adding a salt to prevent Rainbow Tables attacks) to hash a password, and checking it against the hashed password on the database. This way, not even the database administrator could know the passwords of the users, and in case of a forgotten password, it will be resetted, not retrieved.
In Java one of the best implementations out there is jBCrypt, based on BCrypt.
Hope that helps...
EDIT
As a way to conceptually separate the objects you handle in your Web Application, you can use two different beans: a "Full Bean" for reading, with all the properties, and a "Subset Bean" for writing, containing only the properties that could change.
For example, ID and Password should not change... you could read from Database the "Full", and write to the JSP and then to database the "Subset" (except that in user registration, where you will write the full)...
To make it more understandable, the Full Bean is the Dao Object mapping exactly the database fields, while the Subset Bean is a Presentation Object, that you will create by copying only the desired attributes from the Dao Object... they're both DTOs, but with two different levels of semantic.
Otherwise just put in session your bean, it is one row of code, and you will be ok.
You can check "null"(or a unique value) value at server-side (If it is null, it means : There is no change.) .
or you can use this class for update request
Public class person
{
protected name;
protected email;
}
Public class personNew: person // inherit from person
{
private password;
}
I dont use "Struts 2", but in my Web-app(APS.NET C#). I go on this way
I'm adding more information to a user model through a LinkedIn API, and all this code is handled in a controller. When the information is added to the model, I re-render the form (of User class) in a new view. Is there any way to attach additional information to this form (built into Play!), to display which fields have been updated by the API-call?
Use case:
User enters view/edit profile page
User clicks "import information from LinkedIn"
An API-call is made to the LinkedIn API - the user is then returned to a specific controller (called Social) which handles the JSON to JAVA conversion of data, and binds the new data to the user model, and stores the updated model in the database.
The controller then redirects the user to the index() controller which renders the view/edit profile view again. (now I'd like to add the functionality that the user can see which of the fields on his profile were modified due to the API-call).
For instance, something similar to form.errrors() (called form.info() or something). If this isn't possible, then is it any way to gain access to the FieldElements, and maybe add something to them?
Cheers!
I don't clearly see the problem.
When the controller redirects the user to its profile page, you just have to populate the form with the data from the database.
Something like that:
public static Result profile(String userId) {
Form<User> userForm = form(User.class);
User user = User.findById(userId); // data have been set in the database
if (user != null) {
userForm = userForm.fill(user);
}
return redirect(your.view.render(userForm));
}
I have a JBoss Seam app that leverages Seam's IdentityManager and JpaIdentityStore components for handling user account creation and authentication. My components.xml file is setup correctly, and I'm able to use IdentityManager for creating accounts with no problem.
I have created a page to allow me to perform rudimentary account maintenance, such as enabling/disabling accounts. However, whenever I call the isUserEnabled(String username) method on IdentityManager, it always returns false. The corresponding method in JpaIdentityStore also returns false. Both occur even though I can see that the accounts have been enabled in the database. My user account class is annotated as follows:
#Name("user")
#Entity(name = "UserAccount")
#Table(name = "tbl_user_acct", uniqueConstraints = { #UniqueConstraint(columnNames = "username") })
public class UserAccountBean extends BaseDomainEntity implements
VersionedDomainEntity {
private static final long serialVersionUID = -3573332411594504888L;
#UserEnabled
private boolean enabled;
...
}
I don't have any issues with any of the other aspects of the IdentityManager class (changing passwords, creating/deleting accounts, etc.) The only error I run into is when I try to determine if a user is enabled or not. I don't receive any exceptions or error messages, I just get the wrong result returned.
Has anyone else encountered this? Any idea how best to start troubleshooting this issue?
EDIT: Some additional info...
I notice that when I call disableUser(String username), I do actually see the database reflect that in the ENABLED column. Additionally, when I call enableUser(String username), I immediately see that the account is enabled. However, if I navigate to another page and then come back and call isUserEnabled(), it still shows false.
Turned out to be an issue related to lazy fetching. I have a UserProfile object with a userAccount property on it. The relation is Lazy-fetched. Once I changed it to Eager fetching, I received the appropriate response from isUserEnabled().