Dynamics 365 share request working inconsistently - dynamics-crm

I have written a plugin that grants access to a user for an account record as below
GrantAccessRequest grantAccessRequest = new GrantAccessRequest
{
PrincipalAccess = new PrincipalAccess
{
AccessMask = AccessRights.ReadAccess | AccessRights.WriteAccess | AccessRights.AppendAccess | AccessRights.AppendToAccess,
Principal = consultant
},
Target = new EntityReference(account.LogicalName, account.Id)
};
The problem is this only works sometimes. When I check the audit log on records it does not work on, it says that the record has been shared with the correct user, however the user still cannot see the record.
Has anyone else run into this inconsistency with sharing records? If so how did you solve it?

Related

Microsoft Graph update user profile using Xamarin

I have been stuck on this for hours now.
I have the following code:
string[] scopes = new string[] {
"User.ReadWrite"
};
IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder
.Create(OAuthSettings.ApplicationId)
.Build();
InteractiveAuthenticationProvider authProvider = new InteractiveAuthenticationProvider(publicClientApplication, scopes);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var user = new User
{
Country = "ZA"
};
await graphClient.Me
.Request()
.UpdateAsync(user);
Yet every time I execute this I get the following error:
Code: generalException
Message: An error occurred sending the request
What am I doing wrong?
Updating user info is very limited unfortunately. Updating the country with delegated auth isn't possible. It should be doable with app-only auth and the User.ReadWrite.All permission. This is (admittedly) not well explained.
From the information here:
User.ReadWrite and User.Readwrite.All delegated permissions allow the app to update the following profile properties for work or school accounts:
aboutMe
birthday
hireDate
interests
mobilePhone
mySite
pastProjects
photo
preferredName
responsibilities
schools
skills
There are some other gotchas as well (such as if the user is an admin, etc.).

Authorization needed for classroom.profile.emails

I'm working on a web app in Google Apps Script, and I'm having some trouble understanding how the authorization is handled. When accessing the web app as the user using the app, it prompts for authorization, and everything appears okay. However, I'm call userProfiles.get and looking for student email addresses, and it returns the profile without the email.
function classRosters() {
var teacher = Classroom.UserProfiles.get(Session.getActiveUser().getEmail());
var classList = Classroom.Courses.list({teacherId: teacher.id}).courses;
var classes = [];
for (i in classList) {
if (classList[i].courseState != 'ACTIVE') {
continue;
}
var class = classList[i];
var classId = classList[i].id;
var className = classList[i].name;
classes.push([className]);
var teacherId = Classroom.Courses.Teachers.get(classId, classList[i].ownerId).userId;
var teacherEmail = Classroom.UserProfiles.get(teacherId);
var title = Classroom.Courses.get(classId).name;
var students = Classroom.Courses.Students.list(classId).students;
var studentArray = [];
if (students) {
for (j in students) {
var currStudent = students[j];
var email = Classroom.UserProfiles.get(currStudent.userId).emailAddress;
var email = Classroom.Courses.Students.get(classId, currStudent.userId).profile.emailAddress;
studentArray.push(email);
Logger.log(email);
}
}
for (j in classes) {
if (className.indexOf(classes[j]) > -1) {
var classIndex = +j;
classes[classIndex].push(studentArray);
}
}
}
return classes;
}
I've played with the API explorer, and it shows that classroom.profile.email is required, but that's not included in the scopes. When I use the API explorer, I can authorize, and it works, and my web app will work as well until the authorization from the explorer expires.
Is there any method to prompt for authorization in the GAS library for the Classroom advanced service? I can't find anything much that's specific to GAS and not part of the overall API.
Thanks,
James
Unfortunately Apps Script doesn't allow you to request additional scopes for your advanced services. The email and photos scopes aren't required to execute the method, but are required to return email and photo data in the response. You can follow issue 3070 for progress on this problem.
Update 2015-08-17:
We just implemented a workaround, which is that the Classroom advanced service now always prompts for the following fixed set of scopes:
https://www.googleapis.com/auth/classroom.courses
https://www.googleapis.com/auth/classroom.rosters
https://www.googleapis.com/auth/classroom.profile.emails
https://www.googleapis.com/auth/classroom.profile.photos
This provides access to emails, but does mean that the scopes requested for a given script may be more than it actually needs. We hope this unblocks admins that are trying to use Apps Script to manage their Classroom data, while we work on a longer-term solution for dealing with optional scopes in Apps Script.

WebApi 2 Change from Google Authentication OpenID -> oAuth2 - Changes Security handle

When I started out on my project Google allowed to use OpenID where no real registration was needed..
This is now going away, and I have ported the project to the new meths.. BUT
The issue is that the Users will get a new Security token and therefor see the user as a new user.
Has any of you solved that so that I do not need to ask all users to create new accounts, and then for me to link the old accounts with the new accounts?
I decided that the Google email could be my link to the existing users.
If you are using the standard implementation of Identity in ASP.NET/WEBAPI then change: AccountControler.cs - ExternalLoginCallback
What this does is to looked up the email if the Google user did not exist and add a Login to the existing user like this:
// Sign in the user with this external login provider if the user already has a login
var user = await UserManager.FindAsync(loginInfo.Login);
Insert:
//Google Migration. If not existing then check if the Google email exists and if it does the change the LoginProvider key and try to login again
if (user == null && loginInfo.Login.LoginProvider == "Google" && email != "")
{
xxxEntities db = new xxxEntities();
var existingUser = db.user_profiles.Where(e => e.eMail == (string)email).Where(p => p.created_from == "Google");
if (existingUser.Count() > 0)
{
var existingID = existingUser.Single().userFK;
var result = await UserManager.AddLoginAsync(existingID, loginInfo.Login);
if (result.Succeeded)
{
//Now retry the check if the user with this external login provider if the user already has a login
user = await UserManager.FindAsync(loginInfo.Login);
}
}
}
To here:
//Now for the normal Check
if (user != null)
{
Please note that the lookup is some internal Objects I have, it can be done in a OOTB implementation by adding email lookup to the UserManager, or just do like I do and look it up in your own user admin object

RavenDB Service Session.Query not returning results

I have a RavenDB Service instance set up on localhost:8080 and am using the OAuth plugin to store a simple user document for authentication. I am using a guid for the id and the users email as the name. The following code is functioning properly to store the user
public AccountUserDocument CreateUser(RegisterModel model)
{
using (IDocumentSession session = DataDocumentStore.Instance.OpenSession())
{
Guid userId = Guid.NewGuid();
session.Store(new AccountUserDocument
{
Name = model.Email,
Id = String.Format("Raven/Users/{0}", userId),
AllowedDatabases = new[] { "*" },
Email = model.Email,
FirstName = model.FirstName,
LastName = model.LastName,
FacebookId = 0,
Expires = DateTime.Now.AddMonths(1),
AccessToken = string.Empty
}.SetPassword(model.Password));
session.SaveChanges();
return session.Load<AccountUserDocument>
(String.Format("Raven/Users/{0}", userId));
}
}
and returns a valid user object. However, when i call
return session.Query<AccountUserDocument>()
.Customize(x => x.WaitForNonStaleResults())
.Where(x => x.Name == email)
.SingleOrDefault();
I get nothing. It had been working a week ago but now it just doesn't. If I open up RavenDB studio, I can see the user and the name is exactly how I am entering it (i have even copy and pasted it into the text field).
I have tried stopping and restarting the service hoping that would solve the problem but it did not.
I was wondering if someone could point me in the direction of how I might debug what is going on here. The full code repository can be found here
https://github.com/jamesamuir/MVC_Facebook_Auth
if anyone is inclined to download it.
Thanks in advance.
Well, I see a lot of things wrong with the code sample you provided - such as mismatched versions of client and server. Also, the Authentication Bundle was a 1.0 feature that has been deprecated in 2.0 which is almost final, so you're writing code you will eventually have to replace.
But to answer your question, the specific reason that you can't get results from your query is that you chose to use a document key starting with "Raven/", which is the convention for RavenDB system documents - which don't get indexed.
If you remove "Raven/" from your id, it will work.
Also, you should not be using .WaitForNonStaleResults() - that's only for unit tests, and is dangerous in production. If you really feel like you need to wait, use .WaitForNonStaleResultsAsOfNow() - which is safer because it provides a cutoff.

How do I get the displayname of the logged in user in EWS?

Exchange Autodiscovery will give me the user's Display Name via the UserSettingName.UserDisplayName property.
However, in cases where autodiscovery fails and connection needs to be done manually I can't figure out how to get the DisplayName.
I tried this, but I just get the users' email address:
_service = new ExchangeService();
_service.Credentials = new System.Net.NetworkCredential(exchangeSettings.EmailAddress, exchangeSettings.Password);
_service.Url = new Uri(exchangeSettings.ExternalEwsUrl);
NameResolutionCollection resolvedNames = _service.ResolveName(exchangeSettings.EmailAddress);
exchangeSettings.UserDisplayName = resolvedNames.First().Mailbox.Name;
Thanks
If you are going to use ResolveName and you want the displayName then you should use the overload to specify that the operation should return the AD contact information. Then you can just use the DisplayName property.
NameResolutionCollection ncCol =
service.ResolveName("user#domain.com",ResolveNameSearchLocation.DirectoryOnly,true);
Console.WriteLine(ncCol[0].Contact.DisplayName);

Resources