Is it possible to add user specific properties (next to userName, fullName, ID) to the directory.currentUser() object?
Result: directory.currentUser()
{
"result": {
"userName": "jsmith",
"fullName": "John Smith",
"ID": "12F169764253481E89F0E4EA8C1D791A"
}
}
http://livedoc.wakanda.org/HTTP-REST/Authenticating-Users/directorycurrentUser.303-815875.en.html
No, you can't. However don't consider it as a drawback:
I suggest you to keep the directory as the authentication service of your application and store your user profile information on another entity (called userProfile, userInfo, client, ...).
This entity should be created just after the signup / first login of the user. It should have an attribute (for example auth) with the same value as the ID retrieved from the directory.currentUser function.
This way when the user makes a login, you fetch his profile searching the entity
where auth = ID
and consume / update his information there.
The solution is very effective if you want to keep separated your authentication system and your model. You will maintain the flexibility to rely on a different authentication system or make a dedicated micro-service later.
Related
I'm using Shiro in a JSF application and look for guidance on how to handle user attributes like: Id (from the database), email etc. as part of the information held by the Shiro Subject.
Having read the Shiro manual, it seems to me that there's no reason for me to have a SessionScoped bean to hold the user information, as I already have the Subject. The question is how to best store the user information that is not part of the Subject by default.
I've seen different examples where some use Principals and other put a separate custom made User object in the current Session like:
User user = userDAO.findByName(user.getUsername());
subject.getSession().setAttribute("user", user);
It would be elegant to get hold of - for example - the user id like this:
userId = subject.getUserId();
or email:
email = subject.getEmail();
But I guess that is not likely to be possible - so my question is: What is best practice for this? And I'd also like to ask: is there any good reason to keep a separate SessionScoped bean alive for the purpose of user sessions?
For my understanding the principal is the pure object for identification, authentication or remember me function. So put additional info to session (setAttribute).
When a user logs in, load the data and put it to the session with setAttribute. Or when a user comes back with remember me, use the principal to identify the user, and load the necessary things back to session.
It's up to you to decide how much data you want to hold in session for every user. If you want to keep memory consumption small on server, just store data to identify the user (maybe it's already in the principal) and load the data when needed in every function. This way is typically more cpu and database heavy.
If you don't have that much users, just put it to session and make your life easier.
// Do login
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(email, password);
currentUser.login(token);
// load attribues
Long uuid = (Long) currentUser.getPrincipal();
Long ucid = // load other ids;
String email = // maybe load email and other stuff
// set attributes
currentUser.getSession().setAttribute("UUID", uuid);
currentUser.getSession().setAttribute("UCID", ucid);
currentUser.getSession().setAttribute("EMAIL", email);
...
// some function
public void doSomething() {
Long ucid = (Long)SecurityUtils.getSubject().getSession().getAttribute("UCID");
// do something
}
In my example, my principal is just the Unique User Id. That's enough to identify every user. Some Users are also customers, so i save this id too (saves me database access everytime).
You can also save more stuff like email or whatever you need.
I duplicated the UUID from the principal to the session, just for comfort. I don't like mixing up principal casts and session access. This keeps my code clean.
I successfully implemented JWT as a authentication filter in my web application. When user's login is successful, I am creating a new JWT and assigning userName in the sub field of JWT.
In the subsequent request's I am using userName in the JWT sub field to identify the user. But what if the user changes his userName in the update section of the application. Is there way, I can update the value of sub field in JWT ?
What I am thinking!
I am thinking of getting the existing JWT in the RestController and after updating the userName, I will update the JWT with new userName and again send back to the client. Is this fine or is there a better approach?
I think I should refresh the token after update is done and send back the refreshed token back to client.
#RequestMapping( value = "/account", method = RequestMethod.POST )
public ResponseEntity<?> updateAccount( #RequestBody UserDetailsBean userDetailsBean, HttpServletRequest request,
HttpServletResponse response )
{
try
{
UserAccessDetails accessDetails = getLoggedInUser();
UserDetailsBean updatedUserBean = userService.updateAccount(userDetailsBean, accessDetails);
// send updated jwt incase of mobile number update by user
response.addHeader(SecurityConstants.HEADER_STRING,
SecurityConstants.TOKEN_PREFIX + refreshJWT(updatedUserBean.getMobileNumber()));
return buildResponse(updatedUserBean);
}
catch( DataException e )
{
return buildError(e);
}
}
private String refreshJWT( String subject )
{
return Jwts.builder().setSubject((subject))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SecurityConstants.SECRET).compact();
}
This is working. If anyone has a cleaner and industry standard approach please specify.
If you allow your users to change their usernames, they should also have an immutable user id that can be used to identify any data or activity associated with a given user. Otherwise, any time a user changes his or her name, you will either lose the ability to audit the user's past actions or you will have to update all references to that username in the database. What's worse is if there are references to an old username in the database and another user takes that username -- now you have data from one user now being associated with another due to incorrect handling of user identification.
Now with that said, the sub claim should contain this immutable user id. You can create a separate claim for the mutable username. When a username is changed, you now only need to change a single field in the database (assuming that only the users table references this mutable username). You could then use the refresh token retrieve a new token that would contain the latest username that could then be used by your API as needed.
Using this approach, you should be careful to only use the username claim for display purposes, not for identifying the logged in user due to the fact that it is mutable. The sub claim containing the user id would serve the purpose of identifying a user.
It is also important to note that this solution requires no special logic for "updating the sub claim." You would be using the same logic that you're already using to generate a token for a supplied refresh token.
Given a controller which will create/update/delete/query for User:
Get /users query the list
Post /users add a new user
Get /users/1 query a single record
Delete /users/1 delete a single record
Put /users/1 update a single record
Note the last Put method to action /users/1 which means the user of identify 1 should be updated with the data in the request.
However suppose the user with identify 1 have the following properties(partially):
{username:uname,location:sg}
Now given the following requests:
PUT /user/1
username=hg
PUT /user/1
username=hg&location=
We should set the username to hg, but how do we handle the location? Should it be set null or left as it is in the database?
Generally we may use the Data binding like spring mvc in the controller:
#RequestMapping(value="/{userId}",method="PUT")
public String update(#PathVariable String userId, User user){
//merge the model, suppose the `user` contains all the properties of the user
user = entityManager.merge(user);
entityManager.persist(user);
return "user/show"
}
In this case, once the two example requests are executed, the location will set to null in the database, which may or not what the client want.
Normally, we should use the Patch to update the partial properties of the resource, however not all the framework support that method.
And what's more, even the Patch method is supported like this:
#RequestMapping(value="/{userId}",method="PATCH")
public String updatePartial(#PathVariable String userId, User user){
//just set the properties no null
User userInDB=entityManager.find(userId);
//iterator all the properties, set the property which is not null or empty to the userInDB
entityManager.persist(userInDB);
return "user/show"
}
As shown, we have to check the properties of the model, it would be tedious once the model have some deep nested beans.
What's your general practice when handling this kind of situation?
The best practice is to use mentioned PATCH method if partial (in the meaning of fields) request is being sent. Then, all the fields that are present in the request should be modified - set to null value e.g.
When it comes to PUT you should not accept partial requests - since this is not compatible with the standards. When a request is syntactically correct you should modify all the fields unless DB constraints prevents you to do so. So if a particular user can (in terms of the system) set location to null value, he/she should be allowed to do so. If it's not possible you should raise bad request exception and return 400 status code along with the message.
The scenario:
a User class has several groups of properties: password, address, preference, roles.
We need different Ajax calls to update the (1) user password, (2) user profile, (3) roles a user is in.
All the tutorials and examples only shows one POST action to update the whole User class. My question is how we can update only part of the class.
For example, when updating the user password, we will:
Display a text box to collect new password from user input.
Make an Ajax call that only POST the new password together with the userId (like: {id=3, newPassword=xxxxx}) to the WebAPI POST action.
That action will only update the password for the user.
One solution: (the easiest to think of)
Call the GET action with the userId to retrieve all the data for a user
Update the password in the user data with the values obtained from the web user input
Call the POST action with the updated data, which contains all properties in the User class.
That POST action will update the whole data without knowing only the password is changed.
The benefit: only one POST action is needed for the ApiController.
The shortcoming: we have to Ajax twice.
So, is it possible that we can have multiple POST actions in one ApiController? For example, PostPassword(userId, password), PostProfile(userId, profile) and PostRoles(userId, roles).
In this way, we will only call PostPassword to send the password to ApiController. In client side, there will be only one Ajax call. It is on the server where we will do the update. The benefit is of course the reduced data transferred over Internet.
If it is possible, what is the correct way to direct all different POST calls to their corresponding actions in the ApiController?
Please help us. Thank you all.
Most of cases, needless to have muptile post actions, I think. The typical case is consumer needs to edit user. So, s/he needs to load user data first to show on the edit form. After editing, consumer can click Save button to submit data and call POST action on api controller.
If your case is different, you should have nullable property for value type, and then the logic which should be checked in controller is if any property is null, it should not update this property into database.
You can only have one post action per controller action name. That is, you cannot do
// NOT VALID:
public ActionResult UpdateUser(string newPassword) { }
public ActionResult UpdateUser(List<string> newRoles) { }
However, parameters of the action can certainly be nullable. If a given property is not supplied in a given HTTP request, the value of the property in the controller would be null.
// VALID:
public ActionResult UpdateUser(string newPassword, List<string> newRoles)
{
if (newPassword != null) { } // It must have been supplied
if (newRoles != null) { } // It must have been supplied
}
Alternatively, you can have related controller actions that each handle one of your use cases, e.g. UpdatePassword(...), UpdateAddress(...), ...
I am developing an ASP.Net MVC 3 Web Application. Within some of my Views I display tabular data to the user, and beside each record in the table there is an Edit link. When the user clicks this link it takes them to an edit page where they can edit and update the record.
My issue is that once the user clicks the edit link, the URL becomes something like this
http://www.mytestsite.com/myData/edit/3
The '3' is the ID of the record to be updated, however, there is nothing stopping the user from changing the '3' to another digit, and this then means they can edit potentially a record which does not belong to them.
Does anyone have a solution on how I can prevent this from happening?
Thanks for you help.
You need to introduce Authentication and Authorisation into your application. Here is one article of many out there on how to get started with this. You will additionally need to work out how to store logged on user identity and then how to attach this to the record when it was created in the first place. You must then validate, on the server, that the subsequent edit request is being made by the user who created the record in the first place (or by a user who has a role on your system which allows them to do this, such as an Administrator).
Even if the ID wasn't being displayed on the URL a malicious user could still manipulate the HTTP Request to pass an ID of their choice. In any secure system you should always, always, always validate that the currently logged on user genuinely has permission to carry out the requested action. You should never rely on what comes back from the browser to determine this (aside from the authentication context which is managed securely by the MVC framework. Usually).
I believe you should have the information about who have the edit permission on this purticular resource, in your tables. Ex : in your table you might have the "CreatedById" column where you store the ID of the user who created this record. Now in your edit action method, you check the "CreatedById" of the current Item is same as of the "UserId" of the Current user (you maye get this from the session, if you stored it there). Something like this.
public ActionResult Edit(int id)
{
int currentUserID=1; // TO DO : get this value from session or somewhere
ProductVieWModel product=myRepo.GetProduct(id);
if(product!=null)
{
if(product.CreatedById==currentUserID)
{
return View(product);
}
else
{
return View("NotAutherized");
}
}
return View("ProdcutNotFound");
}
You should try using the GUID data type as it helps in these kind of situations, and the user cannot easily guess the next value