How to assign R/W ownership for two users/teams simultaneously - dynamics-crm

I am working on designing an approval system in CRM and need some inputs on the security design. The entity I am using has User/Team level R/W rights. The overall implementation is bit complex but to keep this question simple, consider the following two parties involved in the system:
Requester: Needs R/W access on requests created by him.
Approver Team: These are pre-defined teams whose users will approve/reject the request. Needs R/W access on requests which need their approval.
Question:
How can I handle providing R/W access for both - Requester and Approver Team at the same time? Since we can't have multiple owners of a record in CRM, the Owner field can only contain either of them (Requester or Approver Team) at one time.
I can think of two solutions to this using sharing functionality and wanted to confirm my understanding:
a. Set Requester as the record Owner and share the record with Approver Team programmatically. The problem with this approach is that even if I share the record with Approver Team, I won't be able to show the sharing details on the main form (which is a requirement).
b. Set Approver Team as the record Owner and programmatically share the record with Requester using Access Templates.
Is there any better solution to handle this requirement, in case I am missing any OOB possibilities?

Well I believe that you can make solution A working with a little bit of coding (I'm not sure if you don't mind coding, but we are on StackOverflow, so I think you should consider that).
First of all the design depends on the simple question - should this Request be shared with multiple teams, or only single team? Single team is simple - just add a lookup on the Request, that will point to a Team. When this team is filled in (I'm assuming that choice of this team is done somehow automatically, but it does not matter as in any scenario you would have to choose the team anyway somehow), you run a simple plugin that shares the record for this team. Sharing using SDK is really simple, just use the GrantAccessRequest:
var grantAccessRequest = new GrantAccessRequest
{
PrincipalAccess = new PrincipalAccess
{
AccessMask = AccessRights.ReadAccess | AccessRights.WriteAccess,
Principal = teamEntityReference
},
Target = requestReference
};
So on the form of the request you will keep the owner of the Request and will have a lookup pointing to a Team that is handling this request. Of course you can further pimp it up by for example un-sharing when the request is accepted or declined or the lookup on the request is changed etc. That would keep the POA table more happy as sharing huge amount of records can lead to fast grow of that table, so it's important to unshare records if sharing no longer needed.
If you want to share to multiple teams, you can still create a N:N relationship between your Request and Team and simply share your Request in a plugin on Associate message between Request and Team (this was a standard option before Access Teams were introduced for the users, remains still the only option for teams). This relationship can be show as a subgrid on Request form (it would look like an access team subgrid).
Of course to prevent users from Sharing the Request record on their own (in that case you will not have the Team in your lookup/subgrid) they should not have Sharing privilege. The plugin should do the sharing in admin context.
UPDATE:
As for the POA considerations from the comments: both solutions will make your POA grow, because for both solutions you will have to share the Request either with the team or with the user. If you will use access team you will still have one POA entry for each Request (so 100K entries per year). I believe that the most important thing here is what happens with the Request when it ends it's lifecycle. If it does not have to be visible to the Team, after it was accepted/rejected then you should simply have a mechanism (plugin or some custom app running on some timely manner) that would unshare all the Requests that no longer require sharing, keeping your POA table in reasonable size.
There is another way of handling your scenario that would not require that much sharing/unsharing logic. You can create a "Request Acceptation" entity in 1:N parental relationship with Request. Because it's parental relationship, user owning Request will see all the "Request Acceptation" and "Request Acceptation" will be owned by proper Team (so only this team will have access). Of course I don't know anything about the business logic, but I assume that "Request Acceptation" can contain only the information relevant to the Team which can be copied in a plugin or workflow.
UPDATE2: As I just saw that you cannot unshare the record at a later stage. But I'm assuming that at some point of time Request is done/accepted/finished/rejected or whatever. If at this point both Teams and User should have access to this Request, then maybe it's a good thing to create some kind of separate entity "Archived Requests", that would not be shared, simply cloned for all the principals that are interested in seeing this information and deleting original Request. There are many variations of this idea, I hope that you get it and can adapt it accordingly to your scenario

Your option a makes the most sense: Requester being the creator, should own the Request. Approver just acts on the Request, so it should be shared with.
About showing sharing details, you can put a subgrid in the form: https://www.microsoft.com/en-us/dynamics/crm-customer-center/create-a-team-template-and-add-to-an-entity-form.aspx
Add a team template to the entity form
Make sure you have the System Administrator security role or
equivalent permissions in Microsoft Dynamics 365.
Check your security role
[read more in the linked page]
Since Requester is a USER an Approver is a TEAM, OOB you can only do option b (assign to the team, share with the user via Access Team).
I can't think of any clean solution involving enumerating the team members and act on each of them, so I won't suggest it.

Related

Consent for sharing data with a third party [GDPR]

Do you need to obtain explicit affirmative user consent to send their data to a third party?
Currently we have a form on our website for users to fill out to register interest in our service. This data is then stored in our own database, but it is also sent to a sales service provider and a marketing service provider.
Do we need to get explicit consent from the user to send their details (personally identifiable, includes name and phone number) to these third party services?
Because the user has willingly given us this information is it OK to just send the data to third parties or do we need consent?
Is the third party acting on behalf of you and your core product which the customer has shown explicit consent in being contacted regarding?
If the third party is a Data Provider and handling the customer's details on your behalf, to provide a service that the customer has explicitly consented to, then my understanding is you will be ok.
If they aren't providing a service that the customer has consented to receive information on, or they are selling an unrelated service or product, you're going to be in big trouble.
Basically you are the Data Controller: you have procured the information directly from the client and it is all necessary to fulfill the task for which it is given, and any contact will only receive communication relating to it or that they expect. If you or the Data Provider breach this then you, the Data Controller, could be in trouble.
I know the topic is a bit old but, it is becoming more and more relevant due heavy fines now been issued throughout EU.
GDPR/CCPA is making a lot of people nervous, no doubt. I think most website owners have no clue about cookies or what it is used for. Due the inconsequential use of cookies (thus far), cookies were never subject of discussion.
My best advice is, before getting worked out over fines and implications, to get familiar with GDPR/CCPA regulations. Most importantly, before implementing a 3rd party tool, check if your website really needs it. There are not many free online tools which allows you to check your GDPR compliance status but, sites like https://www.gdpr-service.com/consult allows you to verify if you really need a major change in your website.
If you have 5 to 10 cookies containing no 3rd party, you might as well contract a programmer to build a popup acceptance module for you. Else, I'm afraid you will need to signup for some service which provides you with the cookie policy (including cookies group and description) in order to be compliant.

How to uniquely identity a pipedrive account?

We are trying to integrate our platform with Pipedrive. As far as we have researched, in a pipedrive account, there is one admin and he can add multiple users. And the users later can login in their respective accounts.
What we are trying to make sure is that once a Pipedrive account is integrated with our platform, the same account should not be integrated twice. So, I need a unique identifier, that lets me know whether the account has already been integrated.
My initial approach was to check the api key. But it was not successful, since every users in an account have different API Keys.
After a bit of research, I found out that there is an identifier called company_id which is common for all the users in an account. But I could not find anything regarding it in documentation. So, I am not 100% confident to go ahead and implement it in our code.
Does anyone have an idea about this?
Pipedrive support rep here.
The most sure-fire way to ensure this is to make a GET request against http://api.pipedrive.com/v1/users?api_token=your_token_here.
You are correct in assuming the company_id in the additional_data object in the response is static and won't change across any users on the account.
Note that a Pipedrive account may have more than one admin, and that non-admins (regular users) might have visibility (and editing) restrictions in place, which may cause some of your GET, PUT and DELETE requests to fail.
In case you're not doing this already, I'd thus advise filtering the data array from the abovementioned endpoint for user.is_you to equal true and check whether the is_admin property is set to 1 during "registration" to ensure the user setting up the integration is an admin.
Hope this helps!
I'm not quite sure what you're asking for. Are you looking for a unique identifier for each user?
Each user has an id, you can get all users by calling
https://api.pipedrive.com/v1/users?api_token=____
This will return a JSON Object with data on your users, including their names and associated IDs. Admins are just users with different privilege levels. All admins are users, but not all users are admins. All users are part of a company, the company is identified by the first part of the Pipedrive account url ie.
https://FooCompany.pipedrive.com
Are you trying to see if a certain company has been integrated already?

Design CRM for using with a company and its partners

I need to design a model for CRM by which all cases be centralized for the company as well as its partners. It's a particular need that the company prepare service for its partners, also for the customers of each partner. Therefore, individuals in partners can be contact (because its account and entitlement is needed) and user (because they should have access to CRM similar to the company's supporters) at the same time.
Have you ever faced this need, and do you know a design model which cover it?
The most general case would be to design your CRM-system around Contacts. You could then create a lookup from User to Contact, and create a workflow or plugin to ensure that a User always has a corresponding Contact created.
This way everyone is a Contact in the system, while some people also have User records.

Dynamics CRM in low-trust helpdesk scenario

Ok, so imagine a bank has a call-centre filled with low-trust staff. The staff need to provide basic service to customers over the phone. The call centre staff take calls from a customer, ask them certain security questions, and then service the accounts in some way.
Now, from the customer's point of view, the bank is verifying who they are by asking the security questions. This is subtly different from the bank's point of view: It is verifying that the call centre employee is talking to the customer.
Why is this difference important? The bank wants to restrict these low trust staff, so they cannot view any details of the accounts until the customer calls them. So a call centre employee can't browse account details of customers that haven't just contacted him and asked for service.
So the question is:
Is this sort of setup possible in Dynamics CRM 2011? How would one go about implementing it? Some level of customization would be OK, but a bespoke application driven from the CRM data is not.
I'm thinking that maybe it's possible to create a custom component that temporarily modifies the user's permissions to a record (and all its children) after answering some security questions. However, I'm not even sure that record-based security (beyond Ownership) is supported in CRM...? I guess one could temporarily assign ownership to the user. Is that wise?
Please note: Simply hiding views & find buttons from the GUI isn't the sort of level of security we're looking for here. We're looking to literally restrict the user from accesing the records in question.
I can see a couple of options:
Working within the permissions model. This could work. You could have access restricted by default, and then have another entity where you'd enter in the account details, a plugin would run and verify the details, and then share the record to the current user. I'd be a little concerned, however, on how the unsharing would work. What would trigger it? Would there be a process that just runs outside of CRM and unshares records periodically. What if that process fails? We've also had performance issues in the past with this type of model... CRM seems to do a lot of work under the hood every time an individual record's permissions are changed like this.
Reassigning the owner, as you suggest. Would multiple users ever need to look at the same data? Does the owner of the record need to be maintained for any other reason (e.g. This is Joe's account because he's the owner).
Working exclusively with plugins. You could have a plugin registered on Retrieve and RetrieveMultiple of a record. This plugin could filter out all the details you want to hide from the end user. When the user needs to view the rest of the data, they fill out a form or dialog or something with the data. This data is then included in the Retrieve call for the record. The plugin checks for the hidden data, verifies that it's there and correct, then strips it out and lets the request continue, only this time it retrieves all attributes, and the form populates as expected.
Disclaimer: this answer is based on plenty of CRM 4.0 experience and reading the release notes for 2011.
Short answer: no.
Long answer: yes, but the customisation would be major. The 'easiest' option that springs to mind, is that the authentication process is carried out as a bespoke asp.net page that either a) uses a service account to re-assign an entity to an individual and then returns them to the relevant CRM form, then a plug in that re-assigns it back on saving changes
or
b) has it's own set of forms to that update and retrieve information as a service account, and only do so after answering the security questions.
As an aside, any kind of 'scripted' form is almost impossible in CRM 4.0. I believe 2011 slightly improves on that, but what I've seen is still not encouraging. Using CRM in a contact centre for us has meant investing in a piece of third party form building software and creating bespoke forms that can be launched from CRM and return data via the web services (which are impressively flexible). We only use the CRM interface for viewing historic requests - even most updates trigger one of the bespoke forms.
If I was to implement such a scenario I would create a customer access record (new_custaccess) that is linked to the customer record (new_customer). For this example - keeping it simple - I'm going to assume that the customer has a simple access code they must provide before the bank employee (Operator) can access the record. The access code is stored on new_custaccess in a field (new_secretcode).
Security is that the Operator has no privileges to new_customer and read/update privileges to new_custaccess.
There is a single field (new_secretcodeoperator) on new_custaccess that the operator can update. All other fields are restricted from update (and, if appropriate, read) to the Operator.
When the Customer calls and the Operator searches for the appropriate new_custaccess record. Once they locate the record they enter the Customer provided secret code into the field new_secretcode and do a save.
A Pre-Update query executes on new_custaccess in the context of a user with full privileges (call it MASTER, for fun here.) That plug-in checks to see if the provided code matches the secret code. If it doesn't it throws an error and the Operator can retry. If it does match the plug-in strips the field new_secretcodeoperator from the record, to keep it from saving the value. It also shares appropriate permission on the record new_customer to the appropriate operator.
The Operator now has access to the Customer record (you'll have to decide whether to cascade permissions or share on each record - that decision is beyond this discussion.)
We now need to deal with rescinding permission on the Customer record. I would handle this by having an entity new_customeraccess that is generated by the previous plug-in whenever access is granted to a Customer record. A workflow should be triggered on Create of new_customeraccess that cause new_customeraccess to be updated every 20 minutes (or whatever time the client prefers.)
A plugin is registered on Update of new_customeraccess that fires when the field updated by the workflow is modified. This plug-in will determine - via whatever criteria is decided on by the business - whether to continue sharing or revoke sharing.
I would also create some javascript/html based pop-up from the new_customer ribbon to end sharing by updating a field on new_customeraccess. Provide the Operator with limited Update privs on new_customeraccess via field level security.
This should accomplish what you want without going outside the standard CRM customization model. Not exactly sure of where you draw the line on bespoke but this is probably as close as you'll get to OOTB. A few plug-ins are all the C# you'll need. And the only JavaScript will be for usability, not functionality.
Let me know if you have questions.

ASP.NET Membership - Is Switching the Application Name in the Web.Config a good idea?

I came up with an interesting way to solve the following problem and I want to know if there is a better way to achieve my objectives.
Basically, I'm creating a basic cms system users can register for their own microsite and have their own users. I'm using the asp.net membership api.
I wanted a way to isolate users of the various microsites from eachother so that a user authenticated with www.mysite.com/johns-site wouldn't also be authenticated with www.mysite.com/pauls-site.
I also wanted a way to associate a username with a microsite so that if a user is registered as bob on one site, it doesn't stop another user registering as bob for a different microsite.
To achieve this, I noticed that in the asp membership tables a user belongs to an application. Every time I receive a request, I have a method that switches the applicationName in the web.config based on the url.
This does meet my objectives in an easy way but feels a bit hacky. Is there an alternative way to switch applications for the membership provider?
It is possible to get/set the ApplicatioName property at run time however according to the below MSDN post it is not recommended as the property is not thread safe i.e. if multiple users are creating accounts for different applications at the same time it may not correctly allocate the ApplicationName per user.
Syntax:
Membership.ApplicationName = "MyAppName"
OR
Membership.ApplicationName = "MyAppName";
Further reading:
http://msdn.microsoft.com/en-us/library/system.web.security.membership.applicationname.aspx
Note:
You are updating the contents of the web.config file from the application code? If so this is most certainly "hacky". Plus editing the web.config will drop any active sessions (if your app uses session state of course).
I agree, it is a hack that will likely make you pay at some point.
The proper way to accomplish this would involve each virtual directory (or microsite as you say) each defining a <membership> element with the same connection string but different applicationName attribute.

Resources