LIFERAY - how to create a user with a specific userID? - liferay

I'm using Liferay 6.2.
My need is to add one user in LR, with a specific userID.
Or alternately, update a userID with another value.
The standard addUser service does not provide the possibility to specify the userID, and even the updateUser.
I would like to understand how LR choose the IDs for a new user, and if I can modify it.
thanks!

Like in almost any database driven application they're assigned in sequence. And no, you don't have to choose anything, it'll be taken care of by the framework. It needs to be unique, you can't add another user with the same ID and you must be sure that the user with this id will never be created in future. Thus: If you'd use an id that has already been given out, you'd have a duplicate. If you'd use one that has not yet been given out, you'll have a duplicate some time in future, when the sequence of ids comes to this value and the framework assigns the same id for the second time.
If you have an architecture that relies on a specific ID, your architecture is wrong. Rethink the problem and change the architecture and whatever you've already done to implement it.

LR core services use a CounterService to automatically assign UserId (and plugin developer should do the same)... so all the generating code is properly wrapper in the service methods that creates a number of rows in different tables when creating a user.
I agree with previous comment "If you have an architecture that relies on a specific ID, your architecture is wrong"... by the way you can use a tip.
Do you know Expando in LR? In enables you to add virtual columns on a DB entity... by using it, you can create a virtual column "myExternalId" to table "User_" (entity "User") and store there the ID you need. Then modify your code to use the field myExternalId instead userId.

Related

Batch Commit for Inserting users in Liferay

We are trying to insert about 100k users in Liferay. Is there a way to have this all updated in one batch commit, instead of making separate calls to add each user?
It think yes it's possible.
Build a custom remote service entity like BulkUserServiceUtil.addUsers, within it call the standard method UserLocalServiceUtil.addUser for each user.
Returning from the BulkUserServiceUtil method the transaction is committed.
#sandeep:
Yes, Liferay not provide us to add/update bulk users, because after user creation some table affected in that and also user indexed, but if you want to do that I have two suggestions :
Take a reference of REINDEX option of articles: in that case you can create a batch of counter range with some sort of value and update/add that batch, but the thing is Liferay internally call addUser default. So its iterative way which you can use.
Without Service : Create some custom script and directly hit the DB for once. which create users but in that case you have to take care of other liferay tables which need to be insert the userID or respective data.

Plugin: How do I set default value into an attribute depending business unit?

I have 3 business units (1 parent and 2 children), 3 users (for each business unit), 2 forms (for each business unit) and 1 plugin for the incident entity.
The incident plugin (create, pre-operation) is setting a default value in the attribute 'Case Origin' (caseorigincode) depending on user's business unit.
My problem is what if the user of the parent business unit creates an incident? how the plugin knows from which form that incident is created to set the default value?
What is the best approach to do that?
Thanks.
Unfortunately I don't think there is a way for the plugin to know which form was submitted. However, you could add a hidden field that gets set via javascript to something different for each form. Then, in the plugin you could query that field to see which form was used.
Be sure to check for null/empty as well, because the update could have been submitted programmatically without the use of a form.
IIRC all CRM entities (both stock and custom) should have a OwningBusinessUnit attribute which is an EntityReference to the Business Unit the record's Owner belongs to.
That should tell you exactly from which BU the record is being created.
(NOTE: The question is inconsistent, since it is stated that caseorigincode is set depending on the BU at first, then it asks about forms. I assume the first is the actual logic: check the BU to set the field)
(NOTE #2: This could be accomplished through a workflow aswell: Check Condition on Owner's BU and Update Record accordingly. Run on create.)
Given a user can only be a member of one business unit then you shouldn't need to worry about which form it was created in. Simply get the SystemUser from the EntityReference of the created by user and use the BusinessUnit EntityReference that provides you with.

How do we make a crystal report print only specific fields based off of the user running the report?

We use a construction software, Viewpoint. We need a report to print the GL Accounts associated only with the user running the report. I was wondering if anyone had any ideas on how I could easily and efficiently achieve this? My "last-resort alternative" is just creating separate reports for each GL that pulls only that GL's info.
It depends on how the accounts are associated to the user. If there is a link, you can simply create a user parameter that asks for the user name. Then in the record select of the report you only pull accounts that match the user name in the parameter.
So, for example your parameter is called {?userName}. In the Record Select the formula would something like {Accounts.Salesman} = {?userName}, where {Accounts.Salesman} would be the field that links the user with the account.
You can get the current user name and use it to filter the records in your report. There are 2 ways to do this :
create a parameter, hide it and automatically fill the value. You
will need a special viewer for this scenario. Let me know if this is
what would you prefer I can give you some links. If you leave the
parameter visible the user can insert any value and view any records
use an UFL . For example this one:
http://www.viksoe.dk/code/u2lwin32.htm provides a function LoginName
which will return currently logged user. There are other UFLs which
support similar functionality, check if your company is already
using something . This one is free. You need to register the UFL on
each system which will run the report . Once registered the
available functions will become available for formulas.
I personally prefer the viewer solution because it is more flexible and will cover other scenarios too. However if you need just the username UFL will be a better approach.

HTTP POST Vunerable to change?

I was wondering if anyone knows if the following scenario can happen.
Suppose I have dynamically generated a form that has check boxes for products specific to that customer. If the customer checks the boxes, the products will be deleted when form posted. The checkboxes are named after the productID.
Now my handler will check the response.form and parse the productID out, then delete the product from the database based on the productID.
Potentially could someone amend the post to allow other productIDs to be deleted, potentially everything in the product table by adding fake checkbox names to the POST?
If so, it would be easy to check prior to delete the productID is related to the authenticated user, and they have sufficient roles to delete, or to generate a nonce and label the checkboxes with that rather than their product ID, however I am not doing this at the moment. Any pointers to best practices for this would be good.
I have never considered this before, and wonder just how many people actually do this by default, or are there a million web sites out there vunerable?
Thanks
It is absolutely possible that someone could build a custom POST request with any key/value pairs (including product ID values) and submit it to your application. The fact that the checkboxes are not on the form that the POST is supposed to come from is irrelevant from a security perspective.
When thinking about web application security, the client is a completely untrusted entity. You have to assume that your JavaScript validation will be bypassed, your SELECT elements can be altered to contain any value an attacker wants, and so forth.
So yes, you should validate that the current user is authorized to delete any product ID submitted to this handler.
I'm not necessarily convinced that you need to go the nonce-obfuscation route. It is an additional layer of security, which is good, but if you are performing proper authorization I don't think it's necessary.
My $0.02
Yes this is a problem. What you are describing is an example of the "Insecure Direct Object References" risk as defined by the Open Web Application Security Project (OWASP).
As to how common it is, it currently (2011) ranks 4th in the OWASP's list of top 10 most severe web application security risks. Details of how to prevent this can be found on the OWASP page.
How Do I Prevent Insecure Direct Object References?
Preventing insecure direct object
references requires selecting an
approach for protecting each user
accessible object (e.g., object
number, filename):
Use per user or session indirect
object references. This prevents
attackers from directly targeting
unauthorized resources. For example,
instead of using the resource’s
database key, a drop down list of
six resources authorized for the
current user could use the numbers 1
to 6 to indicate which value the
user selected. The application has
to map the per-user indirect
reference back to the actual
database key on the server. OWASP’s
ESAPI includes both sequential and
random access reference maps that
developers can use to eliminate
direct object references.
Check access. Each use of a direct object reference from an
untrusted source must include an
access control check to ensure the
user is authorized for the requested
object.
Why not simply validate the values you get against the values you provided? Example: You have provided check boxes for items 1, 2 and 3, 9. The user posts 1, 2, 3, 4, 5, 6. You can find the intersection of the lists and delete that (in this case 1, 2, and 3 are in both lists).

Sitecore Custom User Profile - where is it stored how can it be queried

I have created a custom User profile template and object in the core database in Sitecore (as per the Security API Cookbook).
I can select this programmatically (as per the Security API Cookbook) so that my extranet users have an extended profile, that covers all the usual suspects (Address, phone, email format etc.)
However, where is this data stored? And how do I access it if I want to query the database to return a subset of users based on this profile data.
A typical requirement for an extranet member system is to extract a list of users to contact either in an email or a phone type campaign. Can this be done with the Sitecore membership system?
UPDATE>
I'm going to take a guess and say the profile data is stored in aspnet_Profile.PropertyValuesBinary .. which would make it nigh on impossible to query and not suited to my purpose. That is unfortunate. So to extend my question, if that is the case, is it possible to get Sitecore to store those values in the text field so they are searchable?
The standard Microsoft implementation of the SqlProfileProvider (which is used in Sitecore by default) stores the user profile information in the aspnet_Profile table. All the properties are serialized into the PropertyNames / PropertyValuesString columns. The PropertyValuesBinary is used to store the binary data (images). You can find more details if you look at the code of System.Web.Profile.SqlProfileProvider, SetPropertyValues method.
Next, all the custom properties you define in the user profile, are serialized to the SerializedData property of the Profile class, and it is again serialized to the PropertyNames / PropertyValuesString columns like any other property.
Also, couple of properties are stored in aspnet_Membership table (for some reason) - Email and Comment.
So, if you are going to query the users by Email, you can use FindUsersByEmail method of MembershipProvider. Otherwise, if you plan to filter by another property value, I suppose, you'll have to get all users and filter the obtained collection.
Hope this helps.
I faced this exact problem last week, didn't come up with a permanent solution, but to solve my particular issue, I wrote a little helper page and added it as a Sitecore application to be accessed from the CMS interface. All it did was query all users, and determine if they had any of like 5-6 profile properties assigned.
var userList = Sitecore.Security.Accounts.UserManager.GetUsers();
That is the relevant line to grab the users, it returns Sitecore.Common.IFilterable
So if you need to do something where you're grabbing profile info from all users, you cn do something like this:
foreach (Sitecore.Security.Accounts.User user in userList)
{
Sitecore.Security.UserProfile profile = user.Profile;
string whatever = profile["Whatever"];
//add whatever to a list or something
}
This worked out very well for my purposes, but I don't know how feasible it will be in your situation.

Resources