Granting access to a particular user Web API 2 - sql-server

I'm building a small CRM SPA application using Angular 2 (front-end) and Web API 2 as back-end with ASP.Net Identity and OWIN for token based authentication.
I've got ASPNetUsers, ASPNetRoles and I'm able to grant access to users based on roles but I don't understand how to grant access to a certain user. For example:
a user logs-in with role 'Manager' and loads a page that makes a request for some resource that belongs to this Manager. This request reaches an API controller. How this controller method will know whether to grant access to this user or not? Is this user the owner of a ..say some Client. /api/Client/1
Is there a simple way of finding out (with EntityFramework) up the hierarchy of relations if a Client (or another resource) belongs to a current ASPNetUser or not?
This is how I plan the db relations will look like:
In the end the goal is to give user access to resources that he owns, and restrict other users to load them - sort of a personal account.

Related

Grant Admin Consent programmatically on newly created app registration

TL;DR
To grant admin consent to a newly created single-tenant app I need to know its Service Principal Id. Is there a way of getting the Service Principal Id of a newly created app registration when it is not listed in the results from a call to the MS Graph API ServicePrincipals endpoint?
I am using the Microsoft Graph Beta SDK to add functionality that enables users of our application to create and maintain SDS Sync Profiles.
I have a multi-tenant app registration which, given user consent, enables me to create a single-tenant app registration in the user's tenant using the graphClient.Applications.Request().AddAsync({application}) method. The process I have works fine and the single-tenant app registration is created with the necessary permissions but these require admin consent. Currently I am sending users to the adminconsent endpoint: (https://login.microsoftonline.com/{tenantId}/adminconsent) where the user can grant the necessary permissions. This is also working fine but it requires the user to log in again, having already logged in once to grant consent to the multi-tenant app. This is clearly not great from a UX point of view so I would like to avoid the necessity of the user having to log in again if possible.
I came across this post: https://winsmarts.com/how-to-grant-admin-consent-to-an-api-programmatically-e32f4a100e9d which explains how to grant the admin consent programmatically . This involves creating an oAuth2PermissionGrant object with the scopes listed that admin consent is required for.
The issue I have is that in order to add the oAuth2PermissionGrant I need to know the Service Principal Id of the single-tenant app registration just created. However, when I make a call to the Graph API to list the Service Principals (graphClient.ServicePrincipals.Request().GetAsync()) the single tenant app registration is not listed, so I have no way of getting the Service Principal Id and thus cannot create the oAuth2PermissionGrant.
Once I grant admin consent to the permissions on the single-tenant app registration, either manually in Azure AD or via the adminconsent endpoint, the single-tenant app registration shows in the results from the call to ServicePrincipals endpoint.
Additionally, if I haven't granted admin consent, and just make a call to any Graph endpoint, and, when (having logged in again) the grant permissions page is shown, I don't tick the "consent for my organization" box, the permissions remain (as expected) in "require admin consent" status, however the single-tenant app registration now shows amongst the Service Principals list.
Sorry for the long question but any advice would be most appreciated.
Thanks
David.
However, when I make a call to the Graph API to list the Service Principals (graphClient.ServicePrincipals.Request().GetAsync()) the single tenant app registration is not listed, so I have no way of getting the Service Principal Id and thus cannot create the oAuth2PermissionGrant.
That's because a service principal is not created automatically when you create an application through the APIs or with PowerShell. Azure Portal creates it for you at the same time when using it for convenience, but the raw APIs don't do that. You need to create the service principal, the only mandatory parameter is the appId (your app id/client id) if I recall correctly. Here is the documentation page for that: https://learn.microsoft.com/en-us/graph/api/serviceprincipal-post-serviceprincipals?view=graph-rest-1.0&tabs=http
Once the service principal has been created, you should be able to create the oauth2PermissionGrant objects that grant the permissions you want for all users in your directory.

Include Roles from external database in the Access Token

I am doing login from Azure AD.Client is SPA(angular using MSAL). If user is not Authenticated, it redirect to Microsoft Login Screen (using MSAL). On successful login, it return an access token.
My roles will be stored in a database. I need to add the roles of that user as part of claim in access token. I am not finding the way to do it.
I do not want to make another call from SPA to API to get the DB roles.
Please suggest some good approach.
Any links explaining the approach will also be very helpful.
I am still in design phase but not able to find the best approach.
In one microsoft site, i found that we can fetch the roles from DB but details were not there.
most of the places, it is written that we need to provide roles in Azure AD users menifest file.
In regular Azure AD, the "roles" claim is exclusively sourced from app role assignments for the signed-in user (or groups the user is a member of), to the app roles for the app the user is signing in to.
There's no feature currently in Azure AD which will connect to an arbitrary database, make a database query in the appropriate form, and include the results in the roles claim in the resulting ID Token.
I can think of three options to achieve your scenario:
After sign-in, call an API to retrieve the roles. Though you mention this is not desirable, it's probably the simplest approach, so it's worth listing. As a result of the user's sign-to you app, you app will usually obtain an access token to an API. If you set up your API to be secured with Azure AD (directly, or through Azure API Management), your SPA could simply get the necessary access token as part of sign-in, and at that point it's trivial to make a REST call to retrieve the role details for the user (and possibly other information useful to rendering your app).
Synchronize (or copy) your role information from your database to Azure AD. For each role, create an app role in the Azure AD app registration. For each user-role association, either create an app role assignment to directly assign the user (user -> app role), or assign a group to the app role and add the user to the group (user -> group -> app role. Keeping this in sync is probably not trivial, so if your scenario allow to move the role information to Azure AD app role assignment, you can forget the database entirely (making Azure AD the authoritative location). Of course, this might not work for your specific case.
Use Azure AD B2C and a custom sign-in policy. You could create an Azure AD B2C tenant, set up a custom sign-in policy to use your (regular) Azure AD tenant as the identity provider, and configure the policy to enhance the claims by calling a REST API to retrieve your roles. In this approach, you still need to have a REST API which can provide the role information, so rather than doing the setup and migrating your app, you may prefer simply calling the API from your SPA (option 1, in this list).

IdentityServer role/permissions in AngularJS and WebAPI

I have and AngularJS application that talks to WebAPI. Both login using Identity Server 3. I have an Admin role, but I want to expand on this so I can hide certain admin functionality in the front end from some admin users. So I need to check user permissions for admin users. What's the best way to do this? Do I just create a table in my database and assign permssions to users there? Or is there something in identity server I should do to assign permissions.
It's my understanding that application permissions would be tracked in your application specific database. In that database, you could track permissions by role (rather than user). Then, you could use the role claim(s) that come back in the token to look up the proper permissions. However, that's just one method...
This is a really great post on the subject written by Dominick Baier, one of the authors of Identity Server: Identity vs. Permissions

Why do i need to create a Multi-Tenant App?

I have been doing some R&D on using the MicrosoftGraphAPI to fetch the skus subscribed by my organization.
I have created an app as described in the documentation. I did all the steps in the above link except 'Assign application to role'.
Using postman am able to get the oauth2 token by sending a post request using the link
https://login.microsoftonline.com/<mytenantid>/oauth2/token
with the client_id, client_secret, resource(https://graph.microsoft.com) and grant_type(client_credentials) parameters.
After this token is obtained I can fire a get request https://graph.microsoft.com/v1.0/subscribedSkus with the Authorization header set as Bearer {token} which will return the SKUs subscribed by my organization.
So far so good. :-)
Now the requirement is I need to fetch the subscribed SKUs by one of the client (let's say having the azure ad tenant id 'ABCDEFG') of my organization.
I can successfully do that by registering an app in the client's tenant 'ABCDEFG' with the same steps as above.
This approach is fine if my organization has say 1 or 2 clients.
However, if the client numbers are more than say 30 this approach of registering an application in each Azure AD instance is not feasible.
If the application that I registered in my organizations AAD was multi-tenant then how should it help me?
What will be the steps needed to obtain the access token for each tenant?
Can somebody assist with some detailed explanation?
Since you need application-level access, you would assign one of the Application permissions listed in the documentation for getting SKUs: https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/subscribedsku_list.
Directory.Read.All, Directory.ReadWrite.All
In this case you should require the Read Directory Data (Directory.Read.All) application permission.
Then you mark your app as multi-tenanted.
Now then in order for another org to use your app, they will have to be on-boarded.
You will need some kind of page where their administrator can click a button/link to start using your app.
This should redirect the admin to:
https://login.microsoftonline.com/common/oauth2/authorize?client_id=your-client-id&prompt=admin_consent&response_type=code+id_token&redirect_uri=url-where-to-send-user-back
Once they sign in, they will be presented with a consent screen, where they can approve the permissions that your app requires.
If and when they do that, they will be redirected back to your app (to the URL you specified) and you can use the Id token to know which Azure AD tenant registered.
During this process a service principal for your app is created in their tenant, and the required permission is granted to it.
This means you can then get an access token for their tenant from: (using the same credentials)
https://login.microsoftonline.com/their-tenant-id/oauth2/token
Remember that access tokens are specific to an Azure AD tenant, so you will have to get an access token for each tenant.
One thing I would like to point out is that you should instead try to use delegated permissions if possible.
The application permission given here gives quite large access to your app, and some admins might not use your service for that reason alone.
Delegated permissions are more complex to handle, but allow your app to act on behalf of a user instead of purely as itself.

Connect a salesforce user to another salesforce user in another org without any user intervention

We would like to connect a salesforce user to another salesforce user in another org without any user intervention from a service.
We have tried SAML Bearer Flow (using Remote Access Application) to connect to salesforce to retreive Access Token for one of our product. We are referring to the follwoing article.
http://help.salesforce.com/help/doc/en/remoteaccess_oauth_SAML_bearer_flow.htm
As referred by the SF article for this flow, it uses a previous user authorization to connect and retreive Token. In case the user (for whom Token is requested) has not already authorized the App, SF takes you to the Authorization page first and app will get the access token once app is authorized. This is working fine too. However it has this painful step of users authorizing the app before we can use this flow for the product. It would be good and simplified if this step can be done once for an org and the article does mentions that either User or Admin can authorize the app. However I am not able to find how an Admin can authorize the remote access application.
Does anyone knows and can guide how can an Admin authorize an App or is thre any other way we can achieve our requirement. Any thoughts will be really appreciated.
OAuth1 and OAuth2 require user intervention by design. Anything you do to defeat this would be circumspect and not best practice. You could make it easy on the user, but you will always have the initial "Authorize this app" message.
If you are trying to make it easy for the user to login to either org, then you may want to consider a hub-and-spoke SSO solution. See this doc.
If you are trying to pass information between two Salesforce instances, then you may want to consider Salesforce2Salesforce, or outbound workflow. However, this is done at system context, not user context.
If you want to maintain user context and security, you should consider the new Salesforce Canvas API. Canvas allows you to call an outbound service, and pass credentials to the service so that it can communicate back. There is no reason the foreign service could not be a Salesforce instance.

Resources