Tuesday 26 August 2008

Field level security in Crm

There are no supported way to enforce field level security in Crm. What is often done is that the field or tab is hidden on the form. This has a number of weaknesses.
  • Firstly, when you print the form, all the hidden fields will be printed out too. Now you can simply hide the print button too, but this can be overcome in the same way as the next bullet point.
  • Any user with a little bit of javascript knowledge could easily unhide these fields by using a tool such as the IE Dev Toolbar

The second option is to create a child entity that hangs off the entity that the sensitive fields live on and then to move these sensitive fields to this new entity. This will allow you to use the Crm out of the box security on this child entity. This will work fine, but it does mean that each record you create, you'll have to also create a child record, which can be a pain.

The final, and most complicated, way is to do a combination of both the above. Now this is a little hard to explain, so bear with me. Note that for this part I do assume that the user has a reasonable grasp on writing plugins and javascript as well as knowledge of how to do a webservice call to the crmService via javascript.

For this example, I will use the account entity, and assume a new bankaccount field is the sensitive field.

I create the bankaccount field on the account form and show and hide it based on whether the user is in the "Manager" security role (note that determining the security role of a user is covered by other blogs and out of scope for this entry, if anyone needs more information, email me).

Next I create a new entity called bankaccount, and create a 1:N relationship with account. This entity only has one field, "bankaccount". Assign security to this entity so that only users in the "Manager" security role can use it (read, write, create etc) and no one else can see it.

Now, onCreate of an entity, if the bankaccount field is filled in I create a bankaccount record that hangs off the account entity. Also in this plugin I clear the value of the bankaccount field on the account form, so it is essencially empty. Note that you may even put something like "bank account hidden" as the bankaccount in in the plugin.

So now when a user opens this new account and does not have rights to see the bankaccount details, the field is both hidden and empty, so even if they do try and unhide it, it won't show the correct value.

Finally, if a user has rights to see the bank acount, use a crm soap call (also covered on blogs elsewhere, and is similar to retrieving the user role, email me if you need more info) to retrieve the bankaccount from the child record and populate the field accordingly.

Now you could also create an onUpdate plugin to compare the account.bankaccount field with the bankaccount.bankaccount field and update the bankaccount.bankaccount accordingly.

This was rather hard to explain, so feel free to post questions and I'll answer them.

Thanks

Bossie

Monday 18 August 2008

Showing and hiding fields based on another field

Hi All,

This is not a new topic, but it does creep up in the forums from time to time. I thought it may be easier to write a blog entry on the topic.

So here is the scenario, you have a picklist (or any other field) and you want to show and hide other fields based on this. Let's say your picklist field is called "mypicklist" and you have two other fields, one is a text field called "mytextfield" and one is a lookup called "mylookup". The values in the picklist are "Show Text Field", with a value of 1 and "Show Lookup Field" with a value of 2. You want to show/hide the fields accordingly.

Firstly you need to write the following code in the mypicklist onChange event:

if (crmForm.all.mypicklist.DataValue == 1) //show text field
{
//hide the lookup
crmForm.all.mylookup.style.display = 'none';
crmForm.all.mylookup_c.style.display = 'none'; //note the _c
crmForm.all.mylookup_d.style.display = 'none'; //note the _d, only required for lookups


//show the text field
crmForm.all.mytextfield.style.display = 'inline';

crmForm.all.mytextfield_c.style.display = 'inline'; //note the _c
}
else if (crmForm.all.mypicklist.DataValue == 2) //show loookup
{
//hide the lookup
crmForm.all.mylookup.style.display = 'inline';

crmForm.all.mylookup_c.style.display = 'inline'; //note the _c
crmForm.all.mylookup_d.style.display = 'inline'; //note the _d, only required for lookups

//show the text field

crmForm.all.mytextfield.style.display = 'none';
crmForm.all.mytextfield_c.style.display = 'none'; //note the _c
}
else // hide all
{
//hide the lookup crmForm.all.mylookup.style.display = 'none';
crmForm.all.mylookup_c.style.display = 'none'; //note the _c
crmForm.all.mylookup_d.style.display = 'none'; //note the _d, only required for lookups

//show the text field
crmForm.all.mytextfield.style.display = 'none';
crmForm.all.mytextfield_c.style.display = 'none'; //note the _c

}

As you can see, each field has two (three for lookups) sections that has to be hidden, the first section is identified by the field schema name and represents the textbox area. The second, represented by the fieldname following by an "_c" represents the label area. Lookups also has an additional area, replresented by the fieldname followed by an "_d" which represents the lookup button. Each of these sections needs to be shown/hidden individually.

The second part is ensuring these are hidden/shown after they are saved, so the exact same code above needs to be placed in the form load event too. It may also make your life easier to create a global function in the onload event and then call this function from both within the onload event and the picklist onchange event. Something like:

ShowHideField = function()
{
//all the above code goes in here
}

// then call the above in both the onload and the relevent onchange event
ShowHideField();

The above goes for most field types and you can also show or hide fields based on whether they contain data or not with the following:

if (crmForm.all.mypicklist.DataValue != null) //show text field
{

...
}

Hope this helps

Bossie