Creating Shared Sharepoint Sites - c#

I’m working with the .NET Microsoft Graph SDK, and I had a question about the best way to create a Sharepoint Site that is accessible by all members that are part of a tenant. I’m currently creating a Group and using the Group's root Site:
GraphServiceClient client = GetGraphClient();
Group group = await client.Groups.Request().AddAsync(new Microsoft.Graph.Group
{
DisplayName = "A display name",
Description = "Description",
MailEnabled = false,
MailNickname = "a_mail_nickname",
SecurityEnabled = false,
GroupTypes = new[]{"Unified"}
});
Site site = await client.Groups[groupId.ToString()].Sites["root"].Request().GetAsync();
//create file using site.Id as the target
Will taking this approach prevent other members of the Sharepoint tenant from being able to access the Site? Thank you for the help!

To programmatically access the group, below mentioned permission is needed.
As per the documentation, to access the team site for a group, below mentioned permission is needed.

Related

Service Account - Must be a G Suite domain user

This is my team's first foray into implementing functionality with Google Cloud and GSuite. After searching issues and the community I have not yet found what seems to be the proper path forward, or at least have not managed to get the desired functionality.
Background
We have a device/display that shows calendar and event information for a given/specific GSuite Room resource.
As part of displaying information regarding a specific event, we want to display attendee/invitee names.
Implementation
We are successfully calling the Calendar API using a service account. But, when the event information comes back, the attendee information only includes the attendee e-mail address.
The implementation is using the .NET Client libraries for Google.
We found a post directing that we then need to make follow up calls to get more attendee information to the People API.
When querying the People API utilizing the same service account we receive the error Must be a G Suite domain user.
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.6.1",
"title": "An error occured while processing your request.",
"status": 500,
"detail": "Google.Apis.Requests.RequestError\nMust be a G Suite domain user. [400]\nErrors [\n\tMessage[Must be a G Suite domain user.] Location[ - ] Reason[failedPrecondition] Domain[global]\n]\n",
"traceId": "|6007b977-42e9ca34c40a6cb0."
}
Below is the current hacked together code simply trying to make a successful query against the People Service API
public async Task<IList<Person>> GetAttendees(string tenant, string spaceEmail)
{
var serviceAccount = _redisCache.GoogleTenantCredentials.StringGet(tenant).ToString();
var svcDto = JsonConvert.DeserializeObject<ServiceAccountDto>(serviceAccount);
if (!string.IsNullOrEmpty(serviceAccount))
{
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(svcDto.ClientEmail)
{
Scopes = new[] { PeopleServiceService.Scope.DirectoryReadonly }
}.FromPrivateKey(svcDto.PrivateKey));
var svc = new PeopleServiceService(new BaseClientService.Initializer { HttpClientInitializer = credential });
var request = svc.People.ListDirectoryPeople();
request.ReadMask = "names,emailAddresses";
request.Sources = PeopleResource.ListDirectoryPeopleRequest.SourcesEnum
.DIRECTORYSOURCETYPEDOMAINPROFILE;
var result = await request.ExecuteAsync();
return result.People;
}
return null;
}
Researching the error, we found references to allowing a service account domain-wide delegation. Attempting to follow the documentation we have the setup below.
We spent some time with Google Support today and they directed us to Stack Overflow with the tag below.
Not sure where we are going wrong. Since this is a test/sandbox Google environment, one thing that has been our minds is if the GSuite domain is properly linked to the Cloud side, but we have been novices in attempting to verify that is correct as well.
You need to set up domain wide delegation to the service account this is the best documentation i am aware of. Perform G Suite Domain-Wide Delegation of Authority
Beyond that make sure you have delegated to a user.
var gsuiteUser = "user#YourDomain.com";
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(svcDto.ClientEmail)
{
User = gsuiteUser,
Scopes = new[] { PeopleServiceService.Scope.DirectoryReadonly }
}.FromPrivateKey(svcDto.PrivateKey));
To read from the people api you need a person whos data you are reading or you are just going to be reading the service accounts data of which it doesnt have any.

How to get/set custom Azure Active Directory B2C user attributes in ASP.NET MVC?

I have added a custom Organization field as a User Attribute in my Azure Active Directory B2C tenant, like so:
I am using the Microsoft Graph .NET Client Library to manage users in Azure Active Directory B2C and would like to use something similar to the following code to set the user's custom Organization field and the user's built-in Email Addresses field.
await graphClient.Users[user.Id].Request().UpdateAsync(new User()
{
Email Addresses = new StringCollection("myemail#mydomain.com")
Organization = "Microsoft"
});
Two questions:
How do I set a Built-in field, like the Email Addresses?
How do I set a Custom field, like Organization?
This documentation shows how to create a custom attribute but does not tell how to access or use that attribute using the Graph Client.
This documentation shows how to create custom attributes and edit the Relying Party (RP) file.
Is there an easier way? And what is the graphClient code to then get/set these custom user attributes?
It is a bit confusing about whether the Microsoft Graph API, and hence the Microsoft Graph Client, supports the extension properties that are registered with an Azure AD B2C tenant.
When I query a user object using the Azure AD Graph API, then the custom attributes (e.g. "CreatedTime") are returned.
https://graph.windows.net/{tenant}/users/{objectId}
returns:
{
"odata.metadata": "https://graph.windows.net/{tenant}/$metadata#directoryObjects/Microsoft.DirectoryServices.User/#Element",
"odata.type": "Microsoft.DirectoryServices.User",
"objectType": "User",
...
"extension_917ef9adff534c858b0a683b6e6ec0f3_CreatedTime": 1518602039
}
When I query the same object using the Microsoft Graph API, then the custom attributes aren't returned.
https://graph.microsoft.com/v1.0/users/{id}/extensions
returns:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('{id}')/extensions",
"value": []
}
Unless you receive a better answer, then I suggest you use the Azure AD Graph API, and optionally the Azure AD Graph Client, to get and set the extension properties for the Azure AD B2C users.
Examples of getting and setting the extension properties for users can be found at Announcing Azure AD Graph API Client Library 2.0
You are able to do this with the Micorsoft Graph API SDK.
See this example, UserService.CreateUserWithCustomAttribute() https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/4-WebApp-your-API/4-2-B2C
To update a custom property:
var updateUser = new User();
updateUser.AdditionalData = new Dictionary<string, object>();
updateUser.AdditionalData["extension_{app id}_{property name}"] = "new value";
var result = await graphClient.Users["{id}"].Request().UpdateAsync(updateUser);
The {app id} in the code above is the id of the app created by default with the name b2c-extensions-app. Do not modify. Used by AADB2C for storing user data. However the "-" are all removed.
In addition to Aaron Hoffman's answer on how to set a custom attribute I use the following snippet to get my attribute:
var graphClient = new GraphServiceClient(authenticationProvider)
{
BaseUrl = "https://graph.microsoft.com/beta"
};
var user = await graphClient
.Users["{id}"]
.Request()
.GetAsync();
var field = user.AdditionalData["extension_{app id}_{property name}"];
So first step is to find in your custom policy:
<TechnicalProfile Id="AAD-Common">...<Item Key="ClientId">57ff56e7-40a0-43fd-a9a3-8d6c1544bcf4a</Item>
Custom attributes are named extension_attributename.
To get it trough graphql you will require it like this extension_{client id of the app NO DASHES responasble for storing extensions }_{attributename}
e.g. extension_57ff56e740a043fda9a38d6c1544bcf4a_mycoolattribute as you can see this is done also in the code:
https://github.com/Azure-Samples/ms-identity-dotnetcore-b2c-account-management/blob/master/src/Helpers/B2cCustomAttributeHelper.cs#L7-L20
example for graph call: https://graph.microsoft.com/v1.0/users/3545c38b-3f6b-4a4b-8820-e7f954a86e1e?$select=extension_57ff56e740a043fda9a38d6c1544bcf4a_mycoolattribute
https://graph.microsoft.com/v1.0/users/{user-objectid}?$select=extension_57ff56e740a043fda9a38d6c1544bcf4a_mycoolattribute,extension_57ff56e740a043fda9a38d6c1544bcf4a_myotherattribute,etc

How to pass credentials to use ResourceManagementClient to get all resources from azure resource group c#?

I have install nuget Microsoft.Azure.Management.ResourceManager and have following code to get all existing resources based on Resource Group Name
var resouceManagementClient = new ResourceManagementClient(credentials) { SubscriptionId = "mySubscriptionId" };
var listResources =
resouceManagementClient.ResourceGroups.ListResources("Demo-ResourceGroup");
I'm not sure from where I can get credentials parameter value.
I do not have Azure Active Directory access , I think its must , can
we bypass azure AD?.
In my azure portal I have create a Resource Group - Demo-ResourceGroup
and have many resources created.
I want only list of all existing resources using c# code.
One way is by grabbing an access token from Azure AD and passing it in to a TokenCredentials class.
var authContext = new AuthenticationContext(string.Format("https://login.windows.net/{0}", tenantId));
var credential = new ClientCredential(applicationId, password);
AuthenticationResult token = authContext.AcquireTokenAsync("https://management.core.windows.net/", credential).Result;
var credentials = new TokenCredentials(token.AccessToken);
The set of credentials you use to request the acces token (in this case clientId/secret) will determine whether the application has the appropriate rights to enumerate the resources. This is a good MS docs page on how to register your application with AAD. In the example above, applicationId and password come from the application registration in AAD
Microsoft has a page describing other ways you can get tokens from AAD.

BOX: Add Collaboration to a folder using AppUser user token

I am building an integration between my organization back-end systems and BOX.
One of the scenarios is that when certain event is happening inside my organization there is a need to create a folder in BOX and add collaboration objects to that folder (connect groups to the folder).
I have no problem to create the folder but when trying to create the collaboration I am getting the following error:
Box.V2.Exceptions.BoxException: Bearer realm="Service", error="insufficient_scope", error_description="The request requires higher privileges than provided by the access token."
I am using BOX SDK for .Net to interact with BOX.
The application I created in BOX is assigned to use AppUser User Type and I provided all the scopes that BOX allows me (All scopes except "Manage enterprise" which is disabled).
The code that fails is (C#):
var privateKey = File.ReadAllText(Settings.JwtPrivateKeyFile);
var boxConfig = new BoxConfig(Settings.ClientID, Settings.ClientSecret, Settings.EnterpriseID, privateKey, Settings.JwtPrivateKeyPassword, Settings.JwtPublicKeyID);
var jwt = BoxJWTAuth(boxConfig);
var token = jwt.AdminToken();
var client = jwt.AdminClient(token);
var addRequest = new BoxCollaborationRequest(){
Item = new BoxRequestEntity() {
Id = folderId,
Type = BoxType.folder
},
AccessibleBy = new BoxCollaborationUserRequest(){
Type = BoxType.#group,
Id = groupId
},
Role = "viewer"
};
var api = client.CollaborationsManager;
var task = api.AddCollaborationAsync(addRequest);
task.Wait();
When running this code but replacing the Admin Token with Developer Token generated from the Box Applicaiton Edit Page it works.
Any help is appreciated
OK, I had long discussion with BOX Technical team and here is the conclusion: Using AppUser is not the right choice for my scenario because it is limited only to the folders it creates. There is no way to bypass it.
The solution is:
1. Configure the Application to use standard user
2. Create User with administrative rights that will be used by the API to do activities in BOX. I named this user "API User"
3. Follow the oAuth 2 tutorial to generate access token and refresh token that the API .Net application can use instead of generating token for the AppUser. the oAuth 2 tutorial can be found at https://www.box.com/blog/get-box-access-tokens-in-2-quick-steps/
If the app user is a member of the group(s) you want to be able to access the folder then you shouldn't need to set up a collaboration, the users should just have access.

Google Apis v3 in ASP.Net - "Unauthorized client or scope in request"

Maybe I am simply not getting "it", with "it" being the overall setup needed to make this work.
I have a website that scrapes other sites for sporting events. I want to automatically create Google Calendar events from the results, so I want to give my Web Application Read/Write access on a Calendar in my GMail account.
I have been trying to wrap my head around this for a week now, but I can't get it to work and it is crushing my self-esteem as a developer.
The way I "understand" it is that I need a Google API v3 Service Account, because I don't need an API key for a particular user. Or do I need a Simple API key (instead of oAuth)?
Anyways, I went with the Service Account.
In my HomeController I am trying to GET a Calendar so I know it all works.
public void Calendar()
{
string serviceAccountEmail = "...#developer.gserviceaccount.com";
var certificate = new X509Certificate2(
Server.MapPath("~") + #"\App_Data\key.p12",
"notasecret",
X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential =
new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[]
{
CalendarService.Scope.Calendar
},
User = "MY-GMAIL-EMAIL" // Is this correct?
}
.FromCertificate(certificate));
BaseClientService.Initializer initializer = new BaseClientService.Initializer();
initializer.HttpClientInitializer = credential;
initializer.ApplicationName = "CALENDAR NAME"; // Correct?
var service = new CalendarService(initializer);
var list = service.CalendarList.List().Execute().Items; // Exception :-(
}
The error I am getting:
An exception of type 'Google.Apis.Auth.OAuth2.Responses.TokenResponseException' occurred in Google.Apis.dll but was not handled in user code
Additional information: Error:"unauthorized_client", Description:"Unauthorized client or scope in request.", Uri:""
So I tried a bunch of things in Google Calendar, like making it public, adding the service account email as a READ/WRITE user.
What do I need to do to authorize my Web Application so it can create events on my behalf?
I have done this with the service account in a similar post. I changed a bit of my code and got it working to list my calendars by switching a few things around. I can create events as well. I didn't add a user as you have done in the initializer, and under application name, it is the name of the application in the dev console. Make sure you name your application. Make sure your service account is shared with your account.
I slightly changed the list part of your code to this in mine and got back the my list of calendars.
var list = service.CalendarList.List();
var listex = list.Execute();
Check out my example at Google API Calender v3 Event Insert via Service Account using Asp.Net MVC

Categories