How can I implement user permissions on operations in Azure API Management? - azure

I have created a .NET Core 2.0 API and published it to Azure. I have an API Management (APIM) instance fronting that API and doing all the wonderful things that it does. However, there is one thing I cannot seem to wrap my head around or find any documentation for. Authorization on operations. (Not to be confused with authentication, which I have working very well).
My API is a simple RESTful service with CRUD actions. Let's take a read operation for example:
GET /api/owner/{ownerid}/thing/{thingid}
In this case, what I want to be able to do is to grant users permissions to READ THINGS within a specific OWNER. The same user may not have read permissions with a different owner. If the user has permissions, 200 OK; otherwise, 403 Forbidden.
Leaving this completely carte blanche, what are some suggestions for implementing this? I assume an inbound policy for each operation within APIM is where the action will take place? If so, how?
Update 1
I was informed of the possibility of using the same validate-jwt policy at the individual operation levels to append to the validate-jwt policy at the root. The idea is that the root policy validates that the user is authenticated while the operation policy checks for specific claims. This appears to work well, but is that the correct method, or just a hack?
Update 2
For the validate-jwt option to work, the permission model would need to align well with roles and groups; otherwise, it's just as much work as setting up your own custom database wherein at least you benefit from your own rules. In the end, I put the permissions in an Azure Storage Account table (any database will do) and used a send-request (with appropriate caching) to gather permissions based on the current operation and user. It works well, but "feels wrong". I am happy to share details to anyone who wants. In the meantime, I'll leave this open for now in case someone has a better idea.

Ultimately the only way to do so is by using policies at operation level. you can use validate-jwt to check for specific claims, you can check some other credentials that are passed to you as a part of request. Or you can use send-request to call some other service and ask for user permissions. In APIM itself there is no place to store any user related data besides some basic info, thus it is required for such authorization information to come from outside of APIM.

In the end it appears that there is no built-in solution. Rolling your own permission model and then validating it yourself is the way to go.
However...
This can still be done in APIM. As I mentioned in my second update, I was able to make a custom solution work. The way it was done was to use an inbound policy at the "all operations" level to retrieve permissions. (A caching mechanism was used so as not to retrieve the permissions on every single call.) Then, each operation determines if the user has permission to that specific operation based on the parameters that were passed in. (That is also cached.)
The result is that the root API has no authentication or authorization built-in, but APIM does and the appropriate behavior is observed.
Still, the preference would be an RBAC approach. For example, imagine the individual operations being seen as services as in this role definition:
{
"Name": "{rolename}",
"Id": "{roleid}",
"IsCustom": true,
"Description": "{roledescription}",
"Actions": [
"GET {myapi}/owner/{ownerid}/*",
"POST {myapi}/owner/{ownerid}/*",
],
"NotActions": [],
"DataActions": [],
"NotDataActions": [],
"AssignableScopes": [
"/subscriptions/{subscriptionid}"
]
}
If that were possible, we could create roles, assign them to users/groups at the subscription level, then have the claims automatically passed to APIM where they can be evaluated like any other claim.

Related

Suggestion required on how to implement a better permission system

I have a user permission system in place where i have a set of permissions within the database, for example
id
Permission
1
POST:CreateBooking
2
GET:AllBookings
And i have another table (junction table) where i put dependent permissions such as
if i want to create a Booking, i need to fetch Package details and so POST:CreateBooking requires the user to also have GET:AllPackages permission.
There's a template system in place as well, where the users can group multiple permissions together and once that template is assigned to any employee, that employee will get THAT set of permissions and it's dependent permissions.
What my nodejs system does is that when user logs in, it fetches all permissions from DB and puts it in a redis set from where on each request, the permission is checked against user id.
Is there any tool from where i can do exactly this but in an intuitive and better way?
I tried keycloak but i don't know how to cover my needs mentioned above.
Thank you
if I'm understanding correctly and trying to generify your scenario, you have a classical situation where:
You have groups which can have multiple permissions assigned;
groups can be created dinamically;
each permission correspond to a specific functionality.
So, implementing the OIDC (Open Id Connect) protocol might fit you needs. As you suggested youself you might be interested in a OpenID provider (do not reinvent the wheel) keycloak is good, you can give a look also to Vault Hashicorp.
So assuming that your backend have an already existing framework to handle security and permissions (eg. Spring Security) you can produce JWT token with the OpenId provider and check throught PreAuthorize claims (permissions) inside the token.
At the end your security layer it's just an annotation you need to insert before your method controller or before you class controller.
Behind the scenes, instead, this is what will happen:
Your user connect to your app;
User insert username and password -> the Open Id provider gives you a JWT
Your Front End app everytime it make a REST req will send also the JWT
The back end controller method called it's under authorization
Given the public keys of the OpenId provider, the validity of the token it's enstablished
If the specific permission claim it's found inside the token, the request can be elaborated else a 403 Forbidden it's returned.
OIDC - as the conceptual model/backdrop to any tool of choice, is certainly a popular/good choice, but as long as you're willing to deal with an element of complexity - the understanding required to implement an OIDC arrangement (- think of it as a possible investment - effort up front with hopefully the rewards tricking-in over time); e.g. OIDC is an ideal choice for supporting SSO (Single Sign On), especially when it comes to supporting/allowing for authentication/login via providers such as Facebook, LinkedIn & Google, etc (- as well as more Corporate OPs (OIDC Providers) including AAD/Azure AD).
Try to first step-back, and consider the possible bigger/future picture, before selecting a tool based upon only your starting/current requirements.

How to expose some API methods without subscription while keeping subscription for others?

I am using Azure API Management to proxy requests from Internet to our backend systems. I have a Product entry on Azure Portal and an API entry associated with the product. Generally access to the API must be by subscription, but I would like the method returning OpenAPI specification (as well as probably few other methods) to be accessible without subscription (freely).
I see "Requires subscription" checkbox on the Product level as well as on API level, but not on a method's level. So I need either:
bypass subscription check for certain methods while keeping access by subscription for others, or:
same but vice versa: keep the access free for API, but enforce subscription check for certain methods (not preferable, as this fraction is greater).
I checked the list of policies and did not find anything applicable for my case. Moreover this link states:
Subscriptions can be associated with various scopes: product, all
APIs, or an individual API.
Is there a way I can workaround this limitation?
I mean that, maybe you wanna some of the methods(less amount) in an Api can be called without a subscription while the left need. And I searched the ms document but failed to find such policy.
The link you provided also intended that. From my point of view,
how about trying to add a separated Api containing those methods that
don't need subscription?

Best practice to check user permission in RESTful API

I am developing an internal Management System for my company. Some API route will be check for the user's role, and the rest of routes will check for the user's permission.
Currently, how am I doing is storing user's permission in JWT token
{
"user": {
"name": "Oyster Lee",
"role": "root",
"image": ""
},
"OMS": 2147483647,
"WMS": 4095,
"iat": 1566536007,
"exp": 1567140807,
"iss": "Test"
}
My permission is using a bitwise operator. But it can only use up to 31 types of permission in each system. I have more than 31 so the bitwise operator will need to be replaced.
Besides that, after I assign the user new permission or role, he has to log out and log in again and again.
I am thinking should I check the database for user's permission each time they are sending a request to the route. Will it cause the application heavier? Are there any pros and cons? By the way, I am MySQL as our database.
Front-end also need to render conditionally base on user's permission or role.
I am using Nuxt.js SPA as front-end.
The system you are building is suffering from multiple problems:
first of all it will lead to role explosion / permission explosion. Right now you've thought of several roles and permissions. But there could be more in the future. Would you have to redesign your permissions?
Secondly, you cannot elegantly handle relationships (what if access is based on the fact the user and the object are in the same department / region?)
Thirdly, you're hardcoding your own logic using My permission is using a bitwise operator. But it can only use up to 31 types of permission in each system. I have more than 31 so the bitwise operator will need to be replaced. That just won't scale
Lastly, you are forced to log in / log out for changes to take effect.
What you need is decouple and externalize authorization logic from the Internal Management System API. There is a pattern called attribute-based access control (ABAC) that achieves just that. With ABAC, you have an interception-based model whereby a Policy Enforcement Point (PEP) intercepts the call to your API and checks against a Policy Decision Point (PDP) whether the caller (Alice) should be allowed to get access to whatever they are requesting (a document, a record...).
The PDP is configured with policies that use attributes to describe what can or cannot happen. For instance:
A user with role == "manager" can do action == "view" on object of type == "record" if user.department == record.department.
There are two standards to write such policies: alfa and xacml. There are several implementations of the ABAC architecture both open source (AuthZForce, AT&T...) and commercial (Axiomatics). Do check them out. I've also written a lot on this issue in other SO posts such as this one.

Are "Cross Application Queries" possible using the Azure API format for app insights?

I'm trying to make a query to Application Insights using the Azure API format to retrieve data on multiple applications. I can successfully make queries for any application without a join.
I have previously done this using the Public API format, following the documentation for making "cross-application queries" successfully. Under the Azure API schema, however, once I add a second application to a query - either using the implicit or explicit mechanisms described in the documentation - I get an error of type InsufficientAccessError with the message: "The provided credentials have insufficient access to perform the requested operation".
If there are sufficient permissions to access either table individually, I would expect there to be sufficient to do a join. Is there a separate permission required to make these queries, or is it an issue with the API itself?
For reference, the Azure AD application has delegated permissions for:
user_impersonation
Directory.Read.All
Group.Read.All
User.Read
User.ReadBasic.All
User.ReadWrite
The user which is making the requests has the Owner role on all relevant applications.
And the final request has a JSON body (with the blanks filled in):
{
"query": "requests \n| summarize avgRequestDuration=avg(duration) by bin(timestamp, 1h)",
"applications": [
"/subscriptions/<subscriptionId>/resourceGroups/<resourceGroup>/providers/microsoft.operationalinsights/components/<applicationName>"
],
"timespan": "P1D"
}
Edit: I've tried this query using different forms of the resource identifiers as mentioned in the documentation, including the recommended "/providers/microsoft.operationalinsights/applications/" and "/providers/microsoft.operationalinsights/components/".
Based on a couple of things I've discovered, I believe it is impossible to do a cross-resource query in the Azure API URL format.
All experimentation with adding different roles to users and experimenting with permissions failed to find anything that worked.
The Go SDK uses the Azure API URL format and does not allow cross-resource queries, the .NET SDK uses the Public API URL format and does allow cross-resource queries, indicating that the feature set is different for the two APIs.
I would be happy to be proven wrong or to have this proven correct with a better reference.

Azure Active Directory Object Permissions

I have an Azure Active Directory Application (and associated Service Principal). That Service Principal needs to be able to add and remove members from an Azure Active Directory Group...so I have added Read and write directory data under Application Permissions:
And I have code that uses the Client ID and Client Secret to get an Authentication Token an perform these operations using the Azure Graph API.
However, this permission is far too broad. I need the Application/Service Principal to only have the ability to add and remove members from specific groups (not all)...and not the ability to perform other types of operations.
Is there a way to do this?
Thank you.
There is a preview feature that partly fits your requirement: "Group.ReadWrite.All". It lets your principal create and update groups and their navigation properties (incl. members). It does not however reduce the permissions to modify only certain groups.
AAD permission scopes are described here: https://msdn.microsoft.com/Library/Azure/Ad/Graph/howto/azure-ad-graph-api-permission-scopes
Preview features may be subject to change and you'll have to agree to reduced service terms etc.: https://azure.microsoft.com/en-us/services/preview/

Resources