Add role to User in Liferay programmatically - java

I need to assign roles to my Liferay's users when they log in the application.
I have implemented all the logic in the 'authenticateByScreenName' method of a custom class that implements 'Authenticator'.
Example code:
public class ESBAuthenticator implements Authenticator{
public int authenticateByScreenName(long companyId, String screenName, String password,
Map<String, String[]> headerMap, Map<String, String[]> parameterMap)
setProfile(companyId, screenname);
return 1;
}
public static void setProfile(long companyId, long userId){
User user = UserLocalServiceUtil.getUser(userId);
Role liferayRole = RoleLocalServiceUtil.fetchRole(companyId, "Administrator");
RoleLocalServiceUtil.addUserRole(user.getUserId(), liferayRole.getRoleId());
UserLocalServiceUtil.updateUser(user);
}
}
When I log-in, apparently it works, I check liferay database's tables and they are updated, my user has "Administrator" role assigned. However, the portal in front-end doesn't show the "Admin" option.
But If I go to 'My Account', press the 'save' button, log-out and log-in again I have the Admin options availables.
Anyone know why this happens?, I am calling 'updateUser()' after assign the role, It is not the same as the 'save' button?
Possible solution:
I have found that If I clear the content cached across the cluster it works fine. I found it in this post:
https://www.liferay.com/es/web/kamesh.sampath1/blog/-/blogs/how-to-clear-liferay-cache
Add the following line:
MultiVMPoolUtil.clear();
Anyone know if is this the right solution?, I can't find what does liferay when the "save" button from the "my_account" page is pressed. Maybe it clear this cache?. I was searching for a synchronize with database function but couldn't find anything. It seems to be that if a column is updated, liferay doesn't use it if it's cached :(.

I can give you a cheap hack.
Step 1: Make sure you have the hold of user credential.
Step 2: Do as necessary to change user roles etc
Step 3: Flush all kinds of cache (client or server) related to the flow
Step 4: redirect the user to a temp view where the user credential you held will be applied automatically and then redirected to the portal.
Lemme know whether it works

When you call the method you are passing screenName
setProfile(companyId, screenname);
But in ur setProfileMethod, you are using UserId
public static void setProfile(long companyId, long userId){
User user = UserLocalServiceUtil.getUser(userId);
Role liferayRole = RoleLocalServiceUtil.fetchRole(companyId, "Administrator");
RoleLocalServiceUtil.addUserRole(user.getUserId(), liferayRole.getRoleId());
UserLocalServiceUtil.updateUser(user);
}
Use Method
UserLocalServiceUtil.fetchUserByScreenName(companyId, screenName)

I think that the solution of clear cache works because you need to remove all cached portlets repsones. This is the way my_account do it.
// Clear cached portlet responses
PortletSession portletSession = actionRequest.getPortletSession();
InvokerPortletImpl.clearResponses(portletSession);
The problem is that InvokerPortletImpl is not visible externally. to replicate this functionally you can try a login.events.post and get the responses cache from the HttpSession e clear the map;
httprequest.getSession().getAttribute("CACHE_PORTLET_RESPONSES").clear()
but it is like a hack its better in this case MultiVMPoolUtil.clear();

Related

How is a session ID authenticated in SharedPreferences?

I am learning more about SharedPreferences and would like to understand how exactly everything is working. I have watched a decent amount of videos but I still have some questions.
Upon a user logging in, I generate a random session ID using UUID. I then assign the user their session ID and save a session by passing the UserModel into a SessionManagement instance that handles SharedPreferences.
userModel.setSessionId(UUID.randomUUID().toString());
SessionManagement sessionManagement = new SessionManagement(LoginActivity.this);
sessionManagement.saveSession(userModel);
When the user closes/opens the app, onStart() is called. It creates another instance of SessionManagement and checks if the session is null using getSession() to determine whether they're logged in or not.
SessionManagement sessionManagement = new SessionManagement(LoginActivity.this);
if (sessionManagement.getSession() != null) {
// go to some activity
}
And here is what SessionManagement constructor looks like:
private SharedPreferences sharedPreferences;
private final SharedPreferences.Editor editor;
private MasterKey masterKey;
//private String SHARED_PREF_NAME = "session";
private final String SESSION_KEY = "session_user";
private final String SESSION_USERNAME = "session_username";
public SessionManagement(Context context) {
try {
masterKey = new MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
} catch (GeneralSecurityException | IOException e) {
e.printStackTrace();
}
try {
sharedPreferences = EncryptedSharedPreferences.create(
context,
"secret_shared_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
} catch (GeneralSecurityException | IOException e) {
e.printStackTrace();
}
//sharedPreferences = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
}
My question now is, if I am just checking whether the session is null or not, how does SharedPreferences know that the sessionID corresponds to the user that initialized it in step 1?
What are the ways that people work around weak/exposed session ID's that a SharedPreferences implementation can protect against?
Is my implementation/flow correct?
Is it safe to save the sessionID to a user model?
I appreciate any help I can get with this topic!
I use SharedPreferences a lot but did not yet use EncryptedSharedPreferences. I think this is only necessary, if you have data that deserves protection in a very strict way (like passwords or similar). But then you might probably want to use Google Identity or similar.
If you use private SharedPreferences, by calling context.getSharedPreferences(.., Context.MODE_PRIVATE) the OS already makes sure your data is only accessable from your app. Unless there is a bug in the system or the device is hacked, no other party has access to your data.
Now to answer your question, what do you use the session ID for?
For me it looks like you try to implement a web application inside an Android app. If this is the case because you are used to build web apps and have no more specific reason, then just forget about session handling and implement the app assuming there is only one user.
If you want it because you are communicating with a web service or similar, then let that service do the session handling, if possible.
If you really need that session, then the answer to your question is:
With your example the system doesn't know the SharedPrefrences you are calling is valid for the current session. The values are always the same, independent on who is currently logged in.
What you can do, is to choose a name for your SharedPreferences that corresponds with your logged in user (e.g. the hash of the username/mail address or similar).
So you always load the SharedPreferences based on some user identification, just like that:
context.getSharedPreferences(username.hashCode(), Context.MODE_PRIVATE)
There are two points to consider, if you do so:
You might generate junk data, if a user logs in once, therefore generates a SharedPreferences file, and never logs in again. So it might be appropriate to save the users last activity and clean up from time to time.
If you have lot's of users logging in, you might want to consider a database or some other storage type, like json files or whatever, as it's much easier to handle and clean them up.
sharedPrefences is like a repo. So write our data with string types. You can select your data is private or public. And remove your data when your deleted app.
Maybe your help this link:
https://www.geeksforgeeks.org/shared-preferences-in-android-with-examples/

Play Framework 2.4.Trying to Alter main template based User Logged in status

First thank you for reading this far.Here is a basic introduction.
I have implemented the simple authentication demo in the play 2.4 documentation.
And Here is a method where i use it.
#Security.Authenticated(Secured.class)
public Result reviewSubmit(){
//Review newReview = contactFormData.get();
//newReview.save();
Form<Review> reviewFormData = reviewForm.bindFromRequest();
User user = User.findByEmail(request().username());
if(reviewFormData.hasErrors()) {
return badRequest("Form Field has Errors" +reviewFormData);
}
Review newReview =reviewFormData.get();
newReview.user = user.fName +" " + user.lName;
newReview.save();
return redirect(routes.Reviews.review());
}
AS you can see as part of the review saving process i use
User user = User.findByEmail(request().username());
The request().username() gets the currently logged in users email address
from which i use to find the user and access there first and last names when i go to save the review object later on.
What i want to know is there a way in which i can use
if(request.username() == null ){
//Show login Button
}else{
//show Logout button
}
Inside say a main.scala.html template as an easy way of altering the main template without passing a user object from every action.
Thanks for any help or pointers provided.
N.B as i am new to play and have really struggled to understand securescoial plugins/deadbolt/play-authenticate i just want a way of obfuscating the links shown
Not sure if I am answering your question but why can't you do something like this
#if(user) {
<button>LogOut</button>
} else {
//login button
}
in your template.
Where user is passed into the template , as given in the documentation.

Using textfields and a grid in another page

I need to know how to take info from the user in one page using a label and textfield and displaying that in a grid in another page.
For example, Im getting the name of the user and displaying their name in following page in a grid. I'm using eclipse and working with vaadin, if that helps.
if what you need is an info from connected user, I suggest you to set the User object as Session Attribute.
IE:
User connectedUser = new User();
VaadinSession.getCurrent().setAttribute(User.class, connectedUser);
Then, if you need to pick this information, you just have to call
User currentUser = (User) VaadinSession.getCurrent().getAttribute(User.class);
Then, you can pick with all your getter all the required infos, like
String username = currentUser.getUsername();
In my opinion the best approach is to set the user attribute after his login, so you can have it everywhere you need to pick it from any class of your Vaadin application.
Hope this helps.
Bye

Link with hidden Id

I'm using Java, SpringMVC, Hibernate and MySql.
I have a question. In database i have user entity. Some User have role Admin.
If user have role Admin, can create project travel like "Go to Africa" and can join another people.
When User with admin Role login to system, in first site he see projects created by him. He can click on any project. For examle "Go to africa". Then he join friend to list.
But.
Link to a specific project look like:
ProjectXX
and in controller i have #RequestParam("idProject")
But it is really stupid solution because URL look like:
localhost:2233/managementProject?idSchool=5
If i change idSchool param in URL, i have access to someone projects.
I dont no how send this value Post method (because this is element , not form)
So I wrote a method that checks if idProject agree with project created by a person logged on:
private boolean checkAuth(int idProject,User user){
List<Project> projectList = new ArrayList<Project>(user.getProjectsAdministrators());
for(Project project:projectList){
if (project.getId_project()==idProject){
return true;
}
}
return false;
}
If true, user can add people to project. If false, modelAndView return 403 page (something like "you do not have permission"
But i don't no it is really good solution. Maybe someone have better?
Sorry for my english.
Thanks!

Getting a RuntimeException : Datasource user is null ? when updating User model in Play Framework 2.2.1

I am currently trying to enhance the To-Do List tutorial from Play framework's website. I've added a login form, (and of course a User class acting as a model), and it works perfectly well. I also made a small "dashboard" in which the logged user is able to change his password and his email address. But when I submit the form, I get a "Datasource user is null ?" error (RuntimeException).
The whole problem came when I wanted to restrict the edition possibilities (I first used a whole User form, which is quite over the top (User do not need to edit their ID). So I made a small inner class in my Application file called UpdateUser which gathers the required informations, just as I did for the login system.
Searching this error gave me many results but people saw their problem fixed by uncommenting the ebean.default line in the conf file, which I already did.
Here is the method I used to update user's informations :
Firstly, I made a small class in my Application to hold the form (exactly like I did for the login thing).
Then I made a update function as found here in my user class :
public static String update(String id, User newuser) {
newuser.update(id);
return("Your profile has been updated");
}
which returns the String that will be in my flash and which is according to my compiler the problem function.
This function is called in my Application like this :
public static Result updateUser(String id)
{
Form<UpdateUser> filledForm = updateUserForm.bindFromRequest();
System.out.println("Updated User : "+filledForm.get().id);
if(filledForm.hasErrors())
{
flash("success","Error while updating");
}else{
User user = new User(filledForm.get().id, filledForm.get().email, User.find.byId(filledForm.get().id).name, User.find.byId(filledForm.get().id).surname, filledForm.get().password);
flash("success", User.update(id,user));
}
return redirect(routes.Application.dashboard());
}
I tracked the data in the Form and it is not null (I mean I can get everything from the form). But I wonder if I have to create another ebean or if it's my function which is wrong. I also wonder if it's not my User creation that fail. Or maybe I should take the updateUser function and put it in my inner UpdateUser class ?
I have to admit that I worked on that all of yesterday (and probably today too), and I can't find anything on the internet except the ebean.default thing.
------EDIT
I continued to search, so here's what I tried :
1) Getting the form result into an instance of UpdateUser in order to use it
2) Use this instance instead of getting the data from the form
But it failed too. What's really weird is that I've added a toString() method for User class, and calling it on the user I want to insert (as an update) gives me the full stuff. I think it must be a configuration problem, but I can't see it.
Another thing : when I come to the error page and when I try to come back to the application by modifying the URL, I am disconnected. Is it my ebean that closes himself ?
Last edit for the day, I'm getting tired of this. I tried to delay the action (i.e. making it happen after the user has logged out), the new data are correctly saved but I still get the error when calling the update function.
Alright, I finally found it, but totally by chance.
I just had to write this :
public static String update(String id, User user) {
user.update((Object)id);
return ("Your profile has been updated");
}
Because for some reason that I don't really understand, The id String needs to be cast to Object. The rest of the code was correct. But apparently, when using update() on this particular case (is it because my id is a String or because I get the informations from another class before using it as my Model), the parameter which is supposed to be a String (even in the documentation) HAS to be cast.
That's it.

Categories