19 January 2008

CRM 4.0 : Check current user's security role using JavaScript

It's a common question about how to show/hide fields based on user's security roles.
Ronald Lemmen had a very popular post on his blog about how to use 'RemoteCommand' to achieve that in CRM 3.0. Because 'RemoteCommand' is for internal use and unsupported, it doesn't work in CRM 4.0.
Michael H?hne also had a great post about how to access web service using client-side JavaScript. Since CRM 4.0 web service EndPoint changed, some people get 401 authorization error.

Here's code which works great in CRM 4.0, the function UserHasRole("ROLE_NAME") returns true if the current has the role, returns false if it doesn't. GetCurrentUserRoles() function generated by Michael H?hne's tool with some changes. Thanks for Regan who point out that using GenerateAuthenticationHeader() instead of hard-coding the Organization's Name.



//check if the current user has the 'System Administrator' role
alert(UserHasRole("System Administrator"));

function UserHasRole(roleName)
{
//get Current User Roles, oXml is an object
var oXml = GetCurrentUserRoles();
if(oXml != null)
{
//select the node text
var roles = oXml.selectNodes("//BusinessEntity/q1:name");
if(roles != null)
{
for( i = 0; i < roles.length; i++)
{
if(roles[i].text == roleName)
{
//return true if user has this role
return true;
}
}
}
}
//otherwise return false
return false;
}

function GetCurrentUserRoles()
{
var xml = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
GenerateAuthenticationHeader() +
" <soap:Body>" +
" <RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
" <query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:QueryExpression\">" +
" <q1:EntityName>role</q1:EntityName>" +
" <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +
" <q1:Attributes>" +
" <q1:Attribute>name</q1:Attribute>" +
" </q1:Attributes>" +
" </q1:ColumnSet>" +
" <q1:Distinct>false</q1:Distinct>" +
" <q1:LinkEntities>" +
" <q1:LinkEntity>" +
" <q1:LinkFromAttributeName>roleid</q1:LinkFromAttributeName>" +
" <q1:LinkFromEntityName>role</q1:LinkFromEntityName>" +
" <q1:LinkToEntityName>systemuserroles</q1:LinkToEntityName>" +
" <q1:LinkToAttributeName>roleid</q1:LinkToAttributeName>" +
" <q1:JoinOperator>Inner</q1:JoinOperator>" +
" <q1:LinkEntities>" +
" <q1:LinkEntity>" +
" <q1:LinkFromAttributeName>systemuserid</q1:LinkFromAttributeName>" +
" <q1:LinkFromEntityName>systemuserroles</q1:LinkFromEntityName>" +
" <q1:LinkToEntityName>systemuser</q1:LinkToEntityName>" +
" <q1:LinkToAttributeName>systemuserid</q1:LinkToAttributeName>" +
" <q1:JoinOperator>Inner</q1:JoinOperator>" +
" <q1:LinkCriteria>" +
" <q1:FilterOperator>And</q1:FilterOperator>" +
" <q1:Conditions>" +
" <q1:Condition>" +
" <q1:AttributeName>systemuserid</q1:AttributeName>" +
" <q1:Operator>EqualUserId</q1:Operator>" +
" </q1:Condition>" +
" </q1:Conditions>" +
" </q1:LinkCriteria>" +
" </q1:LinkEntity>" +
" </q1:LinkEntities>" +
" </q1:LinkEntity>" +
" </q1:LinkEntities>" +
" </query>" +
" </RetrieveMultiple>" +
" </soap:Body>" +
"</soap:Envelope>" +
"";

var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");

xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction"," http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest.send(xml);

var resultXml = xmlHttpRequest.responseXML;
return(resultXml);
}



Due to Bloger's format issue, I have rewrite the code, it should work for everyone now.:)

46 comments:

Anonymous said...

Instead of manually piecing the authentication header together you should use the new javascript function GenerateAuthenticationHeader() which takes care of it all for you meaning you can leave out the hard-coding of the ORG_NAME stuff:)

Fit it in as follows:

...xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
GenerateAuthenticationHeader() +
" <soap:Body...

Jim Wang said...

See we got something now. :)
Thanks Regan!
Jim

venu said...

Can you please post the entire script with a sample role name?

Thanks in advance

Anonymous said...

Should this code work in CRM 3.0? If so what could I have messed up, because it will not work for me.

Unknown said...

Jim,

I copied all of the code above into the OnLoad event for my main Account form and then changed the alert to look for the "Test" security role.

When I open an Account the alert always returns false, whether or not the current user is assigned to the "Test" role.

Is there any part of the code that I need to alter to be specific to my CRM 4.0 installation?

Anonymous said...

I always get false as well. My alerting some of the workings, I can see roles.length is always equal to zero abnd thus no comparison to the given role is ever made.

Anonymous said...

the script return "false" for every role...
i'm missing something?

Anonymous said...

the script return "false" for every role...
i'm missing something?

Jim Wang said...

Answer some questions here:
1. It works for CRM 4.0 only, for CRM 3.0 security check, please check my post on the CRM Forum:

http://forums.microsoft.com/Dynamics/ShowPost.aspx?PostID=2773685&SiteID=27


2. For those who always get 'false' return(I known some of you didn't call the function ;)) please add a debug alert at:

function UserHasRole(roleName)
{
//get Current User Roles, oXml is an object
var oXml = GetCurrentUserRoles();
alert(oXml.xml); // add this debug alert


see what's you got!

Cheers,
Jim

Anonymous said...

Can you please post the entire script with a sample role name?

Thanks in advance

Аля Кнастер said...

I've got 'false' return too. I've added debug alert like you do and recieved an empty alert message.
If you have any idea, please post it.
Thanks in advance

Anonymous said...

hi all,
i've added the alert as Aline has done and i get the same results. Any Suggestions?

Unknown said...

I've got 'false' return too and if I show 'roles.length' using an alert comand it returns '0' elements...

Any suggestions???

Thanks a lot.

Bigcalm said...

I'm having the same problem as everyone else - no results. After inserting this line:
alert("" + xmlHttpRequest.statusText);

after the
xmlHttpRequest.send(xml);

I'm getting "Bad request"

Bigcalm said...

Got it - in the original post the RetrieveMultiple line ends in

"%22%3e"

This is wrong, it should end

\" >"

Anonymous said...

So how do you call the function?

IanR said...

Hi,

I altered the RetrieveMultiple line, as per bigcalm's advice, but still got no results...
So I added
alert(xmlHttpRequest.statusText);

straight after
xmlHttpRequest.send(xml);

(again, as per bigcalms previous post)
and got : Internal Server Error.

Am logged in as Administrator (am CRM System administrator)

Anybody got similar results or advice on how to fix?
thanks,

IanR said...

also...
I inserted

alert (oXml.xml)

and found out that I was getting an error 0x80040203 Invalid Argument

help???

thanks,

Anonymous said...

Thanks bigcalm...That fixed it for me...

Anonymous said...

Does anyone know if there is a page on the webserver that this code can be inserted into so that these objects can be called from any onload event?

Anonymous said...

Hi, Can you get user teams using the same code?

Unknown said...

I have modified the RetrieveMultiple line like BigCalm has posted but I'm getting the same result:

---> "Internal Server Error"

---> 0x80040203

---> false

Any suggestion?

Anonymous said...

It fixed my problem as BigCalm said above.

Thanks

Anonymous said...

This was a lifesaver! Kudos.

Anonymous said...

How would you rewrite this code to include an if statement to check for user role instead of passing one in?

Anonymous said...

It's so smooth and clean!

Thanks man!

BTW: depending on your requests, you could need to cache the roles xml, in case you have to check for multiple roles.

I did this:

/////////////
var userRoles = null;

function UserHasRole(roleName)
{
if (!userRoles)
{
userRoles = GetCurrentUserRoles();
}
var oXml = userRoles;
if(oXml != null)
.....
.....
.....

This keeps you from double requesting user roles.

Keep up with the good work!

hero said...

Thanks a ton Jim, you saved a day for me

Anonymous said...

Hi Jim,
Thanks for the updated code, work great. I do have one question though, do you know why when I load the page it asks me to log in even though I already log into the system? It only asks to log in once though so if I close and open the screen again, it won't ask and know what my role is. Anyway to stop this log in screen from come up at all?

Thanks.

Anonymous said...

What does this look like in c# in plugin development. I want to do this on the server side.

Anonymous said...

I just posted how to do get the same security roles via C# for CRM server-side development. This was not well documented due to the many-to-many relationship.

http://jamiemiley.com/wordpress/?p=26

Mark Chaffee said...

Great Code. I been looking for this high and low for 6 hours now.

Mark Chaffee said...

Venu.

Try this.

//check if the current user has the '_AFM Acct. Rating Priv.' role
//alert(UserHasRole("_AFM Acct. Rating Priv."));

var oARC = crmForm.all.accountratingcode;

if(UserHasRole("_AFM Acct. Rating Priv."))
{
oARC.Disabled = false;
}
else
{
oARC.Disabled = true;
}

Put that before or after the main function.

Anonymous said...

thanks! just what i needed! you deserve to be MVP

Anonymous said...

酒店經紀PRETTY GIRL 台北酒店經紀人 ,禮服店 酒店兼差PRETTY GIRL酒店公關 酒店小姐 彩色爆米花酒店兼職,酒店工作 彩色爆米花酒店經紀, 酒店上班,酒店工作 PRETTY GIRL酒店喝酒酒店上班 彩色爆米花台北酒店酒店小姐 PRETTY GIRL酒店上班酒店打工PRETTY GIRL酒店打工酒店經紀 彩色爆米花

G.Alvarez said...

At first, sorry my English is no very good.

The first method, no is good for me. For me only run this.!!


alert(UserHasRole("Administrador del sistema"));


function UserHasRole(roleName)
{

var oXml = GetCurrentUserRoles();
alert(oXml.xml);
if(oXml != null)
{
alert(oXml .text);
var roles = oXml.selectNodes("//soap:Envelope/soap:Body/RetrieveMultipleResult/BusinessEntities/BusinessEntity") ;
var rol;
var valores;
if(roles != null)
{

alert(roles.length);
for( i = 0; i < roles.length; i++)
{
rol=roles[i];
valores=rol.selectSingleNode("q1:name");
if(valores.text == roleName)
{
return true;
}
}
}
}
return false;

}



But the second function, no run.
"Client server was unable to process request. Error 0x80040216"

Help me please, I dont undertand!!

G.Alvarez said...

here is the solution.

http://www.crowehorwath.com/cs/blogs/crm/archive/2008/05/08/hide-show-fields-in-crm-4-0-based-on-security-role.aspx

DigiOz Multimedia said...

Thank you very much for the code Jim. I was looking for those exact two functions, so you saved me a lot of work. Much appreciated.

Pete

Hojabri, Omid said...

Great Code!!!!
you solved my problem

Jose said...

Hello, I am trying to do this on the orderprdouct page. I want check all itmems in orderproduct page if a value is checked. If one of the values are checked update the order form by updated a picklist field to a specific value.

Jose said...

Hello, I am trying to do this on the orderprdouct page. I want check all itmems in orderproduct page if a value is checked. If one of the values are checked update the order form by updated a picklist field to a specific value.

myfootprint said...
This comment has been removed by the author.
myfootprint said...

Hi,

Can use this script for hide/show tab by check security role. Such as
- System Administrator Show Tab
- Other role hide tab

Please help and thanks in advance

Unknown said...

Hi can i use for CRM2011

Unknown said...

HI,
How can i use it for CRM 2011

Unknown said...

Works great. Thank you.

Quân Đào said...

học kế toán thực hành cấp tốc
học kế toán thực hành cấp tốc
học kế toán thực hành tại cầu giấy
học kế toán thực hành tại thanh xuân
]học kế toán thực hành tại hà đông
học kế toán thực hành tại long biên
học kế toán thực hành tại long biên
học kế toán thực hành tại hải phòng
học kế toán thực hành tại bắc ninh
học kế toán thực hành tại tphcm
học kế toán thực hành tại quận 3
học kế toán thực hành tại hải phòng
học kế toán thực hành tại bắc ninh
học kế toán thực hành tại bình dương
học kế toán thực hành tại biên hòa
học kế toán thực hành tại vinh
học kế toán thực hành tại vinh
học kế toán thực hành tại huế
học kế toán thực hành tại đà nẵng
học kế toán thực hành tại đà nẵng
học kế toán thực hành tại đà nẵng
học kế toán thực hành tại hải dương
học kế toán thực hành tại hưng yên
học chứng chỉ kế toán
học kế toán ở đâu tốt