none
Plugin running under SYSTEM account

    Question

  • I have a plug-in registered on a custom entity's "CREATE" message that creates Contact and Opportunites. While creating Contact and Opportunities we have a custom code that sets Owner of the entity record. But sometimes it is setting the owner as "SYSTEM" user. Can somebody please explain what is "SYSTEM" user and the reason behind it is being set as Owner of the record?

    I also see that Created By and Modified By fields on the entity record are being set as 'SYSTEM' !!!

    Monday, July 05, 2010 1:44 PM

Answers

  • Hi Dave, 

    I have no problem with any open discussion. In fact, I appreciate your frankness, I like your style to get straight to the point. :-)

    I was not previously involved in the Javascript-impersonation discussion, so please excuse my ignorance. 

    I just did a quick test, and I used the following code to create a CRM contact record in my plug-in. The modifiedby, createdby and owner fields of the new contact record are all SYSTEM. 

    using (ICrmService service = context.CreateCrmService(false))
    {
      DynamicEntity createContact = new DynamicEntity("contact");
      createContact.Properties["firstname"] = "FistName";
      createContact.Properties["lastname"] = "LastName";
      service.Create(createContact);
    }

    I would appreciate to know if there is more accurate statement about the impersonation of the SYSTEM account. 

    Thanks David. 

    Cheers,


    Daniel Cai | http://danielcai.blogspot.com
    Wednesday, July 07, 2010 6:52 PM

All replies

  • Have you  checked who is set as the Calling user in the Plugin Reg tool?

    Also if it is running in Async mode then the user could well be the Async Services user.


    MSCRM Bing'd - http://bingsoft.wordpress.com
    Monday, July 05, 2010 2:55 PM
    Moderator
  • Yes. I already have checked the context and it is set to 'Calling User'. And Async service is running under one of the service account.
    Monday, July 05, 2010 3:25 PM
  • Check your systemuser table. We had a 'system' user disabled in 2008 (from upgrade CRM 3?) it was still listed as the modified by on 20,000 emails. not sure what it's for yet. 
    Tuesday, July 06, 2010 8:39 AM
  • I do see 'System' user disabled in my Organization. And as I said earlier, for few of the entity records it is being set as Owner.
    Tuesday, July 06, 2010 10:16 AM
  • The "System" user is a high-privilege account representing the Active Directory account which runs both the Async Processing Service, and the IIS Application Pool for CRM.  Unless you utilize impersonation, most Plugins execute in the context of this account, and any record actions you take will be taken in its name.

    Dave Berry
    Tuesday, July 06, 2010 7:12 PM
    Moderator
  • It might help if you can post the code that you use to instantiate CrmService when you try to set the owner in your plug-in. 

    When you instantiate CrmService in plug-in using false as parameter as below, you are actually impersonating 'SYSTEM' account, in which case, the Created By and Modified By fields will be 'SYSTEM'. 

    ICrmService service = context.CreateCrmService(false);
    You might want to look for such code in your plug-in project. 


    Daniel Cai | http://danielcai.blogspot.com
    Wednesday, July 07, 2010 12:51 AM
  • Please don't take the following as an affront to your otherwise fantastic record of technical expertise, Daniel.  I understood Impersonation to be the mechanism by which you instruct the "SYSTEM" account to perform an action in another user's name.  (This is evidenced by the necessary use of the InitiatingUserId within the context to impersonate the user that pushed the button on the UI.)  It was previously discussed in a Javascript-impersonation thread wherein it was discovered that for ordinary users to perform impersonation, they must belong to the PrivUserGroup AD group, to which only the "NETWORK SERVICE" for the server belongs (which also happens to be the execution account for both the IIS worker group, and the Async Processing service).  So, while the code you identify is likely the cause of the problem, I was concerned about the technical accuracy of your description.  Once again, please don't take that as an insult.
    Dave Berry
    • Edited by DavidBerryMVP, Moderator Wednesday, July 07, 2010 7:45 PM corrected "ImpersonatingUserId" to "InitiatingUserId", and changed the sentence around it for clarity
    Wednesday, July 07, 2010 4:12 AM
    Moderator
  • Hi Dave, 

    I have no problem with any open discussion. In fact, I appreciate your frankness, I like your style to get straight to the point. :-)

    I was not previously involved in the Javascript-impersonation discussion, so please excuse my ignorance. 

    I just did a quick test, and I used the following code to create a CRM contact record in my plug-in. The modifiedby, createdby and owner fields of the new contact record are all SYSTEM. 

    using (ICrmService service = context.CreateCrmService(false))
    {
      DynamicEntity createContact = new DynamicEntity("contact");
      createContact.Properties["firstname"] = "FistName";
      createContact.Properties["lastname"] = "LastName";
      service.Create(createContact);
    }

    I would appreciate to know if there is more accurate statement about the impersonation of the SYSTEM account. 

    Thanks David. 

    Cheers,


    Daniel Cai | http://danielcai.blogspot.com
    Wednesday, July 07, 2010 6:52 PM
  • It's all about simple semantics, I suppose.  Your code executes exactly as expected, because no impersonation is occurring.  We're not impersonating the "system" user by passing false to the CreateCrmService() method, we're simply stating that we wish for no impersonation.  Since the code is being run by IIS, it is therefore operating in the natural context of the "SYSTEM" AD account.  When performing additional platform operations, such as Retrieve(), Update(), etc., we can optionally impersonate these operations as a different user (such as the user who triggered the original operation, via context.InitiatingUserId ), so that the operation applies security roles appropriate to that user.  One exception for this, is for offline-executed Plug-ins, which execute in the natural context of the local user's AD account, so even though impersonation is impossible, passing false in that case maintains the paradigm that no impersonation is occurring.
    Dave Berry
    Wednesday, July 07, 2010 7:43 PM
    Moderator
  • Sorry Dave, I am a little slow to respond.

    I would like to apologize to the Sonuli for going a little off-topic here, but I see this as a good discussion, though it does seem to me that we are getting a little academic here. The good thing is it can help us be more precise in the terminology that we use. 

    With my simple (probably a little naive) sense, I believe it's the other way, which is, when the CRM service is instantiated with a user account other than the current user, it involves impersonation. Otherwise, it's not impersonation.

    So, based on that understanding, I believe we can categorize 3 different scenarios as below:

    • The following plug-in code does not involve impersonation as the CRM Service is instantiated using current user's credential. (The createdby, modifiedby, owner will be the current CRM user, if the service is used to create a new CRM record)

      ICrmService service = context.CreateCrmService(true);
    • The following plug-in code involves impersonation as the CRM Service is instantiated using the built-in SYSTEM account. (The createdby, modifiedby, owner will be SYSTEM, if the service is used to create a new CRM record)

      ICrmService service = context.CreateCrmService(false);
    • The following plug-in code involves impersonation as the CRM Service is instantiated using another CRM user's ID. (The createdby, modifiedby, owner will be the specified user, if the service is used to create a new CRM record)

      ICrmService service = context.CreateCrmService(anotherUserId);

    If we really want to put it in a strictly academic way, all the above scenarios actually involve impersonation, as the first sample code basically instructs CRM server to impersonate the current CRM user herself. 

    If you don't mind, let me quote your statement: 

    "One exception for this, is for offline-executed Plug-ins, which execute in the natural context of the local user's AD account, so even though impersonation is impossible, passing false in that case maintains the paradigm that no impersonation is occurring."

    You are basically indicating that when false is used as the parameter in offline mode, it's pretty much the same as if true were passed as the parameter, which involves no impersonation. This is exactly the same thing that I have believed and stated in the first scenario. 

    Dave, I appreciate your insightful information. However I am still more convinced about what I believed, maybe I am just a stubborn guy. :-)


    Daniel Cai | http://danielcai.blogspot.com
    Thursday, July 08, 2010 3:43 AM
  • Thursday, July 08, 2010 8:55 AM
    Moderator
  • Hi Rhett, 

    I am pretty sure that Dave has read this particular MSDN article (at least I did), but we just had different interpretation of our own. We are trying to solve the discrepancy here. Why don't you just share your thought? :-)

    Cheers,


    Daniel Cai | http://danielcai.blogspot.com
    Thursday, July 08, 2010 11:22 AM
  • I really appreciate the depth of conversation on this matter, because I feel it's important to sufficiently understand Impersonation and the methods behind it.  This is an engaging academic discussion with which I have no quarrel, and really gets into the semantics of CRM's underlying platform. 

    I have read the SDK article on Impersonation many times to-date, and my understanding stands as-is, because I feel that the article is both incomplete and confusing to the true nature of the underlying platform code.

    Where Daniel is absolutely correct, is "When the CRM service is instantiated with a user account other than the current user, it involves impersonation. Otherwise, it's not impersonation.".  We just have a different view of who that instantiated user account is.  The value of context.UserId generally contains this account, (unless specified to be impersonated by way of registration parameters).

    As I understand from both the SDK and my own experience, the value of context.UserId is the "SYSTEM " user in all but 2 cases:

    1.) The Plugin executes offline.  Because Cassini operates with the credentials of the account logged into the local machine, the context.UserId will reflect the current user; or

    2.) Impersonation defined at registration of the Plugin.  <-- this is the important one, because context.CreateCrmService(true) actually is impersonation, contrary to your statement regarding scenario 1.

    The SDK states that context.CreateCrmService(true) is equivalent to context.CreateCrmService(context.UserId) , which the SDK specifically states is an "impersonated" user ID.  Now, I differ from the SDK in that I do not define it "impersonation" when the user running the code submits itself to that call (e.g. the "SYSTEM " user), and therefore agree with your description of the 1st scenario to an extent, but disagree with the assertion that the call never involves impersonation.

    The polar opposite of the call, context.CreateCrmService(false) , disregards impersonation naturally, as explained by the SDK.  What the SDK does not state, however, is that this only results in a "SYSTEM " user context for online Plug-ins, and for offline plugins results in a local-account context.  This is why I disagree with your definition of the second scenario.  There will be no difference between the user context under which the code is executing, and the user context submitted to the new web-service call.

    The value of context.InitiatingUserId , on the other hand, is a special value provided by the platform to always reference the user account responsible for having clicked a button to start the action.  In no way does any code operate within the context or credential of context.InitiatingUserId , until it has been used in conjunction with context.CreateCrmService .  In this, I agree with your description of scenario 3 completely.

    An interesting and useful twist on scenarios 1 and 3, (from which scenario 2 is completely excluded), is the manual instantiation of a CrmService in a child-pipeline (via http://msdn.microsoft.com/en-us/library/cc151083.aspx ) which always uses either context.UserId or context.InitiatingUserId .  Here, passing false to the example code is not the same as passing false to the context.CreateCrmService method, but quite the opposite--it does involve impersonation (online), which would be unacceptable in an offline scenario, if it were possible for Cassini to be operating under a user account which was not identical to both context.UserId and context.InitiatingUserId.

    So, when it boils down to it, I define Impersonation as any delta from the AD account executing the code and the AD account calling it to be executed.  To truly grasp the nature of this beast, imagine the difference between the online and offline execution the following pseudocode (which assumes that no impersonation was defined for either Plugin 1 or Plugin 2 at registration):

    SCENARIO ALPHA

    1. User saves record A, thereby initiating an Update
    2. Plugin 1 in the "Update" message fires for record A, and triggers an Update on record B using context.CreateCrmService(true)
    3. Plugin 2 in the "Update" message fires for record B, and triggers an Update on record C using context.CreateCrmService(false)
    What will be the modifiedby value of both record B and record C?

    Answer:

    • In online mode, the value of modifiedby for record B will be the User in step 1, and record C will be "SYSTEM ".
    • In offline mode, the value of modifiedby for records B and C will be the User from step 1.

    Reason:

    Here's a breakdown of the various user contexts held at each step in online mode:

    ------------------------------

    Step 2: (Inside Plugin 1)

    • context.UserId:  <Step 1 User>
    • context.InitiatingUserId:  <Step 1 User>
    • Executing User:  "SYSTEM "
    • Calling crmContext.CreateCrmService(true) results in the impersonation of <Step 1 User> to call the "Update" operation of record B

    Step 3: (Inside Plugin 2)

    • context.UserId:  <Step 1 User>
    • context.InitiatingUserId:  <Step 1 User>
    • Executing User: "SYSTEM "
    • Calling crmContext.CreateCrmService(false) abandons impersonation for the "Update" operation of record C

    ------------------------------

    For offline execution, all contexts will be <Step 1 User>.

    Now, let's take that pseudocode again, but reverse the CreateCrmService calls:

    SCENARIO BETA

    1. User saves record A, thereby initiating an Update
    2. Plugin 1 in the "Update" message fires for record A, and triggers an Update on record B using context.CreateCrmService(false)
    3. Plugin 2 in the "Update" message fires for record B, and triggers an Update on record C using context.CreateCrmService(true)
    4. What will be the modifiedby value of both record B and record C?

    Answer:

    • In online mode, the value of modifiedby for records B and C will be "SYSTEM ".
    • In offline mode, the value of modifiedby for records B and C will be the User from step 1.

    Reason:

    Here's a breakdown of the various user contexts held at each step in online mode:

    ------------------------------

    Step 2: (Inside Plugin 1)

    • context.UserId:  <Step 1 User>
    • context.InitiatingUserId:  <Step 1 User>
    • Executing User:  "SYSTEM "
    • Calling crmContext.CreateCrmService(false) abandons impersonation for the "Update" operation of record B

    Step 3: (Inside Plugin 2)

    • context.UserId:  "SYSTEM "
    • context.InitiatingUserId:  "SYSTEM "
    • Executing User: "SYSTEM "
    • Calling crmContext.CreateCrmService(true) passes the value of context.UserId to "Update" operation of record C, this is not impersonation, however, since there is no difference between the AD account executing Plugin 2 and the user updating record C.

    ------------------------------

    Once again, for offline execution, all contexts will be <Step 1 User>.

    Now, let's complicate the scenario a bit more:

    Let's assume that Plugin 1 and Plugin 2 were registered with an impersonated user property of <Plugin User>.  How does this change things?

    For SCENARIO ALPHA the results are:

    Answer:

    • In online mode, the value of modifiedby for record B will be <Plugin User>, and record C will be "SYSTEM ".
    • In offline mode, the value of modifiedby for records B and C will be the User from step 1.

    Here's a breakdown of the various user contexts held at each step in online mode:

    ------------------------------

    Step 2: (Inside Plugin 1)

    • context.UserId:  <Plugin User>
    • context.InitiatingUserId:  <Step 1 User>
    • Executing User:  "SYSTEM "
    • Calling crmContext.CreateCrmService(true) results in the impersonation of <Plugin User> to call the "Update" operation of record B

    Step 3: (Inside Plugin 2)

    • context.UserId:  <Plugin User>
    • context.InitiatingUserId:  <Plugin User>
    • Executing User: "SYSTEM "
    • Calling crmContext.CreateCrmService(false) abandons impersonation for the "Update" operation of record C

    ------------------------------

    Once again, for offline execution, all contexts will be <Step 1 User>.

    For SCENARIO BETA the results are:

    Answer:

    • In online mode, the value of modifiedby for record B will be "SYSTEM " and C will be <Plugin User>.
    • In offline mode, the value of modifiedby for records B and C will be the User from step 1.

    Here's a breakdown of the various user contexts held at each step in online mode:

    ------------------------------

    Step 2: (Inside Plugin 1)

    • context.UserId:  <Plugin User>
    • context.InitiatingUserId:  <Step 1 User>
    • Executing User:  "SYSTEM "
    • Calling crmContext.CreateCrmService(false) abandons impersonation for the "Update" operation of record B

    Step 3: (Inside Plugin 2)

    • context.UserId:  <Plugin User>
    • context.InitiatingUserId:  "SYSTEM "
    • Executing User: "SYSTEM "
    • Calling crmContext.CreateCrmService(true) results in the impersonation of <Plugin User> to call the "Update" operation of record C

    ------------------------------

    Once again, for offline execution, all contexts will be <Step 1 User>.

    I hope that sufficiently illustrates what I mean by the proper use of the term "Impersonation".


    Dave Berry
    Thursday, July 08, 2010 7:16 PM
    Moderator