List of ALL Class Assignments using Graph API Beta - microsoft-graph-edu

I have been asked to retrieve all Class Assignments from Teams for education using the Graph API.
I have taken info from educationClass Methods to list all classes, members, etc. in my ASP core console app. but I cannot get assignments due to access permissions.
It appears that the method 'List assignments' does not support the 'Application' permission type.
I then created an ASP Core Web app with Azure authentication, wired up the Graph API and was able to see a handful of assignments whilst authenticated as myself.
If I log in as a 'test' teacher then I can see their class assignments, which makes me wonder whether I could do this automatically for all teachers? Could you somehow get class assignments on behalf of a user? Ideally, this will be a console app running on a server.
I have very little experience using Graph so I am wondering whether there is a way to get the information I need. I am an O365 administrator and I was hoping this would give me access to everything I needed.
Any advise is much appreciated as I'm not sure how best to approach this task
John

Related

WebAPI 2 Authorize Roles with MSAL

I'm in throws of moving our security architecture from ASP.NET Core Identity to Azure AD V2 with MSAL.js. We used a lot of Roles with the ASP.NET Core Identity implementation and the information was managed in the database using the web application. The pattern I'm abandoning is similar to this one.
https://www.dotnetcurry.com/aspnet-core/role-based-security
Azure AD with MSAL is working. The tokens are being created and passed and the local Web API Endpoints decorated with the generic [Authorize] attribute are being honored as you would expect. Web API Endpoints decorated with [Authorize(Roles= "Fee, Foo, Fi, Fum")] are throwing a 401 unauthorized error.
I'm not sure where to go from here. Do I write a CustomAuthorize attribute override for Web API and go back to the database and grab the roles. (probably match the DB defined roles to the user based on email address)
OR
Is there a way to implement roles natively with Azure AD V2?
I'm not sure whats the best course of action from here. Documentation and Code samples seem limited. It would sure be nice to just throw a AD User in a Group and have the Group be respected as a Role in the Web API. On the other hand, It's nice to have Role delegation handled within the confines of the Web Application.
Any advice, experience or interest would be greatly appreciated.
Answer
Follow up to my question. #Marc , You're correct, after looking at the token the Roles are not present. Adding Roles to the token seems pretty straight forward. You need to Patch the graph schema to include them, Configure the roles and assign them to users as needed thru AAD.
Or that's how it looks at first glance. After digging a deeper, it requires a P1 or P2 Enterprise license which only costs an additional 6$ per month per user. This will literally double the cost of hosting email in the cloud for us.
Alternatively I wrote a CustomAuthAttribute for WebAPI and tied User & Roles together on the server backend. Roles can still be managed via the web application and users can still login using Active Directory Credentials.
I recall that the id token returned in implicit flow (the one you use with JS) does not include app roles (or groups). I cannot find any docs confirming that but see others who got around the issue (so the issue must be there) by using Graph to get the roles (or groups).
You can capture the token you receive from AAD and view it using https://jwt.ms to see whether roles are included in it.

Integrate laravel app with MS Active Directory but restrict users who can access

I have a custom application for internal use only where currently users are created by a super admin. Some of the users are from within the business and some external e.g. suppliers/customers.
I'm looking for a way to integrate MS Active Directory as a login option but want to be able to restrict which users from the business can actually use this method.
I have search through all the MS docs and have all the documentation on the different oauth approaches but not sure which one would be suitable for my needs.
I am thinking that perhaps i need to give the admin a way to browse the AD and select the users that can login which then creates inactive user accounts in the mysql database with some sort of MS user ID. Then provide a 'Sign in with MS' button that does the usual auth redirection process to MS and back to the site. At that point I can check an ID and if that matches an allowed user account and if so, sync the rest of the data e.g. name, email, phone etc..
Links I've already found:
https://learn.microsoft.com/en-gb/azure/active-directory/develop/authentication-scenarios
https://learn.microsoft.com/en-gb/graph/tutorials/php
https://github.com/microsoftgraph/msgraph-training-phpapp/tree/master/Demos/03-add-msgraph
Your first order of business is enabling a user to sign in to the Laravel-based app. For this, I strongly recommend not trying to re-invent the wheel (at least not completely), and make use of an existing Laravel package. Laravel Socialite is probably the best place to start, since it has a long list of existing community-provided Socialite providers, including three which work with Azure AD already: Microsoft, Microsoft-Graph and Microsoft-Azure. (Note: Though I haven't tested any of these myself, the first two seem to be the most promising, as they use the newer v2 endpoint.)
When it comes to authorization (controlling access), you have two options:
Control at Azure AD
Once you've got the app integrated with Azure AD, you can configure the app in Azure AD to require user assignment, and then control access to the app by assigning (or not) users to the app. Users who are not assigned won't even make it past the sign-in page.
You can use Azure AD's existing experiences for managing user and role assignment for the app, or you could go all-out and build this experience directly into the Laravel-based app itself, making use of the Azure AD Graph API to create the [app role assignments](https://learn.microsoft.com/en-us/previous-versions/azure/ad/graph/api/entity-and-complex-type-reference#approleassignment-entity and user picker experience.
Hint: In either case, remember that you can make the app "superuser" an "owner" of the app in Azure AD (Azure AD > Enterprise apps > (app) > Owners), which will allow them to assign users without needing to give them any additional privileges in Azure AD.
Control at the app
In this approach, you allow all users to sign in to the app with Azure AD, but then you use your app's own authorization logic to decide who makes it any further, and what roles they get in the app.
In reality, you will most likely find the best approach is to use a combination of the two, with some of the authorization enforced by Azure AD and the next level enforced by the app itself.
If you would do it in this way, it will be necessary that the super-admin has always this permissions in the AAD. From my point of view it is less practical.
I would perfer such app-assigments with help of Service Principal. You assign a role (look for app roles) to the user and then your business logic must decide which permissions the user has. If you would use the app roles feature, then you can restrict access to the role with it's help. All the user can login, but only users with a specific role would be able to see a content of the app.
I hope this hints can help to find a right direction, but there is no silver bullet solution... :/

How to request Domain-wide Delegation through a consent screen, on G Suite

I need to have access to Calendar information from a company's G Suite accounts, to synchronize data with the company system through a API.
When I need to provide access to my own data, there is a fairly simple way to do it. Using Oauth2, through a login window the user allows the API to access the requested data.
But in the G Suite documentation, the path indicated when involving the administrator and company data, involves the administrator accessing admin.google.com, go to the security-related session, and manually register my API, listing the scopes that he wants to grant me access.
To make a parallel, in Microsoft Graph there is a way to request consent from the domain administrator, where only a user consent / admin consent screen is displayed using Oauth2.
I wonder if there is a way to get this type of access in G Suite without requiring the end user to take such complicated steps to make my API work properly.
UPDATE:
This question was originally posted in 2019, does anyone aware if something was changes since then?
You should use the Marketplace SDK for this. This allows you to publish an application to the Google Workspace Marketplace where company admins can choose to install it for their domain.
There are a couple things to keep in mind:
There's an expectation that your application will have some sort of user facing presence (e.g. add-on, link to web app, etc).
Google will review your app before publishing. Since you're not using Gmail or Drive scopes (for these, Google requires a 3rd party security review), this process should not be too difficult. But plan for it to take some time, and follow the best practices so it's done right the first time.
You also mentioned synchronizing calendars. If that means mainly reading, no problem, but if you're writing (a lot at once), be mindful of calendar use limits. These are per user and for all activity by that user (not just your app).

Combining Azure AD (b2c) custom ClaimsIdentity

I have an ASP.NET 5 (RC1) application for which I am trying to set up authentication and authorization. However I am confused and overwhelmed by all the varying authentication and authorization information online in as it pertains to this platform. Much of it seems either hopelessly out of date or simply doesn't seem to apply in this particular usage scenario. Right now, I'm not even sure what the right 'terminology' to use for the question I am trying to ask, but I digress.
What I am trying to accomplish is a system whereby users are authenticated/authorized via Azure AD (B2C?), with additional user profile information stored in a database. However, the user context in the controllers is accessed in a consistent way using what I presume would be a custom ClaimsPrincipal/ClaimsIdentity? I would imagine this should be as simple as adding an 'authorize' attribute or something similar and accessing the ClaimsPrinciple.Current.Claims.
I have used ASP.NET Identity in the past, but many of the examples I have found aren't using that. Most are simply using the UseOpenIdConnectAuthentication middle-ware. I see that ASP.NET Identity is still available but I'm not sure it applies in this scenario. I also found a couple posts on here suggesting using a custom ClaimsIdentity to accomplish this, but I am having trouble finding useful up to date examples. BTW, I realize that much of this "profile" information can be stored as custom attributes in azure ad but the way some of the information is used within the application prohibits all of it from being in azure (i.e. EF linq joins and such).
Please, tell me if I am even close on some of this. I know this is a fairly new platform and the information is sparse, but certainly I'm not the only one asking these questions.
Just calling out an excellent article Identity management for multitenant applications in Microsoft Azure.
A lot of your questions are answered there.
e.g. you can augment the claim in the OWIN middleware AuthenticationValidated event.
ASP.NET Identity is claims-based in that the attributes are delivered as claims but authentication is on the DB, not via external IDP like Azure AD.
B2C is a special case in Azure AD - used for many (millions!) external users who can self-register and self-manage e.g. SSPR.
B2C uses a separate tenant to the normal Azure AD one and the users have no access to things like O365 or any SaaS applications.

ASP.NET MVC3: Do I need to use a MembershipProvider?

I am building a multi-tenant site with MVC3. Prior to this project I had never touched either the .NET stack or web development in general, so as you can imagine my domain knowledge is somewhat lacking.
I'm still using the default AccountController architecture, but I pretty quickly determined that I didn't want to use aspnetdb.mdf for authentication, as its design is pretty different from my requirements. I do want role-based authentication, so I ultimately wrote custom User and Role classes as code-first Entity classes and used this tutorial to set up a custom MembershipProvider and RoleProvider.
Everything works fine at the moment, but as I'm building the multi-tenancy functionality it's getting messier. Based on this example, I am using a custom extension of Controller which keeps track of which tenant is using this session, and all my controllers extend this class instead of the base Controller class.
All tenants are using the same database. Each entity has a Tenant property that identifies who it belongs to.
So, here's the problem:
Usernames do not need to be globally unique. Only the combination of username and tenant must be unique. Thus, ValidateUser needs to know the username, password, and tenant. Since my custom MembershipProvider is not a Controller, it doesn't know which tenant is using the session, and the ValidateUser method only accepts username and password so I can't pass it that information.
Furthermore, pretty much everything MembershipProvider does besides ValidateUser is already implemented in a UserRepository class, which that tutorial told me to make. I'm rather fond of the Repository pattern, and it's way more convenient than adhering to MembershipProvider's interface, but now there's a massive conflict of interest between UserRepository and MembershipProvider.
So, my question:
Do I need to use MembershipProvider, or even Membership, at all?
It seems like everything MembershipProvider does would be performed more conveniently by my repository class. At this point all I'd have to do is write a new Authorize attribute that doesn't rely on Membership, and everything should work without any MembershipProvider at all, right? If I don't drop Membership I'm forced to completely mutilate my MembershipProvider implementation to the point that it barely resembles the original interface anyway.
...Either that or Membership does a ton of things I'm unaware of and removing it is blatant stupidity. That is also a distinct possibility.
No, you don't need to use Membership, but consider for a moment exactly what Membership is. Membership does not involve your users names, or addresses, or other information. Membership is strictly related to the login account of the system. It only handles details with creating, validating, updating, or deleting the information needed to login. That's it.
Likewise, the Role system is only assigning a role name to the user.
Ultimately, Membership and Roles are just implementations of the IPrincipal interface. While FormsAuthentication is an implementation of the IIdentity interface. These work together so that you can utlize the built-in ASP.NET Authorization and Authentication system.
Membership actually does have the concept of multiple tennants. This functionality is accomplished via the "ApplicationNane" field of the aspnet_users table (also settable in the Membership class itself)
From the documentation on the Membership class:
The ApplicationName is used to identify users specific to an application. That is, the same user name can exist in the database for multiple ASP.NET applications that specify a different ApplicationName. This enables multiple applications to use the same database to store user information without running into duplicate user name conflicts. Alternatively, multiple ASP.NET applications can use the same user database by specifying the same ApplicationName. The ApplicationName can be set programmatically or declaratively in the configuration for the Web application.
Now, this is designed to typically be set in the Web.Config and stay the same for the life of the app, but I see no reason why you can't use it to specify which tennant you want.
The only issue here is that Membership.ApplicationName is static, which means it's shared by all threads running in the App Pool. However, if you use some kind of lock around accessing it, then this shouldn't be a huge issue (though it could affect scalability at some level).
This would basically allow you to use the standard, out of the box membership provider without any changes. You just have ot make sure to guard the access calls.
You don't have to use the membership provider at all. Its simply provided as a quick and consistent way to get up and running. Some choose it because it supports multiple databases (universal membership providers include azure as well as sql ce, express, and full) but for others trying to map it to your applications rules can be more difficult than the <5 lines of code it takes to authenticate and issue your own forms auth ticket.
With that said I'm assuming you are using forms authentication. You can simply issue the ticket yourself. I would still program against an interface for this which the default MVC template should have, so simply add in a new tenant id.
With that said, I'd consider having unique names. It ensures you don't 'forget' to do an additional tenant check somewhere else in the app and tenant1\userBip and tenant2\userBip surprisingly end up stomping on each others record at some point.
True, testing should uncover this - if testing is complete : )

Resources