Openapi-specification: Allow Roles/Privileges

Created on 12 Nov 2017  路  24Comments  路  Source: OAI/OpenAPI-Specification

endpoints need to have ROLES and Privileges associated with them. Since tokens and security are always part of the architecture and will be included at all points of the architecture (proxy, MQ, API server), they will also need to be checked at all places the Open Api is checked.

You need to provide something similar to 'I/O State that can be shared and syncronized:

        "URI": {
            "list":{
                "METHOD":"GET",
                "DESCRIPTION":"List Hook",
                "ROLES":["ROLE_ADMIN","ROLE_ARCH"],
                "BATCH":["ROLE_ADMIN","ROLE_ARCH"],
                "REQUEST": {
                    "permitAll":[]
                },
                "RESPONSE": {
                    "permitAll":["id","version","user","name","url","format","service"]
                }
            },

Most helpful comment

@handrews Your upvote of a comment declaring a failure to understand is perfectly acceptable response in my opinion. In an online world it is never easy to convey sentiment, therefore we must "assume the best" when interpreting every comment.

@orubel We've had this conversation before. I am convinced you have a lot to contribute to this community, but you need to find a way to communicate your ideas in language that your target audience can grok. I have repeatedly tried to parse what you are saying and I have failed. That may be completely my fault, but we both lose if you cannot convey your ideas successfully.

What is not acceptable is making belittling comments such as "This may be a bit over your head". Everyone in this community is held to a higher standard than that.

I'm going to close this issue so that this whole thread can be relegated to the past. If you wish to start a fresh one about how you feel an authorization framework could be layered on top of OpenAPI, you are welcome to do so. However, before you do so, could you spend a bit more time familiarizing yourself with how OpenAPI works, as your comments on the x- extensions seem to indicate that you have misunderstood what they are.

All 24 comments

Operations that are secured using OAuth2 can have scopes assigned to them. This is similar to privileges, if I understand your model correctly. Having pre-defined roles might be something that is useful for services to define but I'm not sure it is in scope of the OpenAPI spec.

It should be. At RestFest, I pointed this out as a shortcoming of the OpenAPI project and how it fails in a distributed architecture as a result because it can fall out of sync, escalate privileges, etc.

Allowing privileges to be set (even permitAll) allows for a framework for that data. Not even having a framework means their is a severe hole in OpenAPI in which data associated with endpoints is not being set.

Roles/Privileges are associated with endpoints; they are data as much as 'Get, Put, Post, Delete' or even the path (ie 'get/post'). But by not having this, you are not consolidating the I/O data that needs to be synchronized at the PROXY, MQ, API Server, etc.

Thus you are helping to create an architectural cross cutting concern.
https://developers.redhat.com/blog/2017/10/12/new-api-pattern/

Luckily there is an extension mechanism in OpenAPI that allows you to add on whatever metadata you wish in order to support your choice of framework for building distributed applications.

And you are correct that roles/privileges are data just like HTTP methods. The difference is that roles and privileges are not standardized in the HTTP specification. We are not in the business of creating a meta data description for a generalized distributed application framework. We are in the business of describing HTTP APIs using the semantics described by the HTTP specification and those related to it.

You have our encouragement and support to build a better distributed computing framework and use OpenAPI and extensions to drive it. If in the future it becomes a ubiquitous standard, as HTTP is, then we will be happy to update the core spec to follow it.

It doesn't need to be standardized. It's just data. You merely pass the roles. This is something API Blueprint and RAML are already doing and have incorporated.

For example:
"show": {
"METHOD":"GET",
"DESCRIPTION":"Show Hooks",
"ROLES":["ROLE_ADMIN","ROLE_ARCH"],
"BATCH":["ROLE_ADMIN","ROLE_ARCH"],
"REQUEST": {
"permitAll":[]
"ROLE_ADMIN":["user_id"]
},
"RESPONSE": {
"permitAll":["id","version","user","name","url","format","service"]
}
},

The above example shows upon REQUEST, 'permitAll' states users do not need to send an ID (because it will use the id from their token) but 'ROLE_ADMIN' states those with that role need to send a user_id (even if it is their own) to do this lookup.

This way this one CACHED resource can be use different ways depending on the ROLE without changing the functionality.

And this data can be shared and synchronized in all services in the architecture thus avoiding the architectural cross cutting concern and guaranteeing 100% uptime.

So, does this work for you?

openapi: 3.0.0
paths:
  /show:
    get:
      description: Show hooks
      x-roles: ["ROLE_ADMIN","ROLE_ARCH"]
      x-batch: ["ROLE_ADMIN","ROLE_ARCH"]
      x-request-permitAll: []
      x-request-ROLE_ADMIN: ["user_id"]
      responses:
        200:
          description: List of hooks
          x-permitAll: ["id","version","user","name","url","format","service"]

Perhaps you can show how this is represented in Blueprint or RAML because to be honest, I really don't understand the semantics of the example you are giving.

No. The point is to have a single file in which all data can be
SYNCHRONIZED for the endpoints. Data separate from function.

In this, you are defining 'headers'. Headers do not always transfer (see 'redirect').

This data needs to be the same and synchronized across all services that
share the I/O (request/response). If you send via the header, you can
EASILY push bad data that doesn't synchronize with the 'central version of
truth' which in this case is the API Server (where the request/response
meet). The DATA associated with the endpoints may not sync with the data
being pushing with the headers.

You need ONE SINGLE version of truth that can be synchronized to all
services. So if OpenAPI intends to be that DATA, it needs to act like it.

Right now as is, it acts like a centralized architecture approach... not a
distributed approach. Because it cannot be synchronized, it does not secure
its endpoints... it still pushes the architectural cross cutting concern in
the original API pattern rather than trying to separate DATA from FUNCTION.


The main problem is that you are basing your assumption on the fact that you can 'push through' the data linearly with the request. But the 'central version of truth' is at the endpoints in the API service.

So if you attempt to 'push' bad headers/data from api gateway to api service to MQ, etc, they will either get rejected or possibly elevate privileges (depending on how the functionality works).

EX You are pushing the Data like so:
[API Gateway] >> [API Service] >> [MQ]

This is the way the request and response works but NOT how we synchronize the data from the endpoints. We synchronize the data from the endpoints like we do neurons in a neural network
EX
[API Gateway] << [API Service] >> [MQ]

Thus we synchronize from the point of truth and all data for the endpoints stay in sync every time they change.

What you are proposing above continues to exacerbate the issue of the API Pattern as a Centralized Architecture Pattern being used in Distributed Architectures.

Those are not header definitions, those are Specification Extensions as defined by the spec. @darrelmiller simply translated your example to something that can be represented with OAS3.

@webron My apologies. Thats right. I'm thinking xref and this is for frontend javascript usage.

Still, you wouldn't need a frontend specific designation since this wouldn't be checking ROLES on the frontend; frontend is final output once roles have been checked

Feel free to correct me if I am wrong again. ;)

Not really sure how we got to talk about frontend now.

@webron Also keep in mind, just as you allow for one cached resource to be requested different ways through doifferent ROLES, you will also want to return it different ways via the ROLE as well

"REQUEST": {
"permitAll":[]
"ROLE_ADMIN":["user_id"]
},
"RESPONSE": {
"permitAll":["id","version","name","url","format","service"]
"ROLE_ADMIN":["user"]
}
},

Above implies everyone gets returned ["id","version","name","url","format","service"] but only ROLE_ADMIN gets returned 'user'

This allows for ONE OBJECT/RESOURCE to be requested/returned a variety of ways and to built functionality only ONE WAY (ie grab,cache, parse object). ROLE merely tells you:

  • who has access
  • what data to expect
  • what data to return from cached object.

@webron The 'x-variable' specification is commonly used for passing variables in javascript is it not??? I have never seen this anywhere else. Isn't that a defined mime-type
https://www.npmjs.com/package/mime

No, it's just a way to extend a specification. It can be used by the front end, back end, nothing at all, everything. It's just extra metadata that's not directly supported by the specification. We've seen various examples of those out there.

As for what you're suggesting, that won't get in before we solve the issue of filtering fields from models in general. It also seems that you're trying to describe a very specific implementation and this is not a general solution used across by various API producers out there (unlike known authorization schemes). As @darrelmiller mentioned before, this does not make it a good candidate to be incorporated directly into the specification.

@webron Ok well I've never had to use it until Node. Python, Ruby, Java, Perl, PHP don't need this

I would have to say, you are choosing the delivery mechanism for the end user rather than just defining data; if you want the platform to remain generic, don't do that. Let the end user choose the delivery mechanism.

A generic platform leaves the options open for people to implement.

Again, no idea what you're referring to.

@webron I'm doing my best to explain, bear with me.
@handrews nice community you have here. Way to built it up

Above in your declaration, you are stating this has to be used as a mimetype and declared using the naming convention:

  x-roles, x-batch, x-request-permitAll, x-request-ROLE_ADMIN

Should there be overlap, they do not have options.
Should they not wish to use a mime-type, they do not have options.
Should they wish to transfer data using the default framework/language methodology, they don't have the option.

You are forcing the delivery mechanism for the data upon them.

Does that make more sense?

With the following:
"ROLES":["ROLE_ADMIN","ROLE_ARCH"],
"BATCH":["ROLE_ADMIN","ROLE_ARCH"],
"REQUEST": {
"permitAll":[]
"ROLE_ADMIN":["user_id"]
},

All thats being stated is:

  • these are the declared role data
  • this is the request data associated the the role data
  • this is the response data associated with the role data

There is no formatting declared like you have. I don't declare JSON, XML or a MIME-TYPE; that is functionality/formatting... not data.

@webron Its not a specific implementation. This is one that APIGee, Mulesoft, Apple, Google, AWS, and 90% of enterprises support everyday. Its the API in a distributed architecture. Most of those I just listed called me in to help with these issues and Redhat and others have asked me to write about it.

So I'm struggling the best I can to explain this and I'm at a loss for why a the synchronization of I/O state in a distributed architecture is something that is not understood since thats what this file is meant to do.

UNLESS... Swagger intends this specification simply for centralized architectures. Then it makes sense.

@webron well I guess thats the issue then. This may be a bit over your head

heres some reading for the future. I also gave this talk at API World https://developers.redhat.com/blog/2017/10/12/new-api-pattern/

@orubel Thank you for making this community an unsafe place for people.

I've been amazed at how level-headed the team has been trying to work with you, and now you've opted to be just plain insulting.

I understand that it is frequently challenging to make oneself understood, I have that problem often. But the onus is on _you_ to be understandable when proposing enhancements.

@nelz9999 excuse me? Since when is someone upvoting 'Again, no idea what you're referring to' level headed. That's upvoting passive aggression. And please explain how I made this (in your words) "unsafe"?

Regardless it's ok. People at RestFest, APIWorld, APIDays, and enterprises like Amazon AWS team, Netflix, Apple, Cisco (and yes, VMWare too) understood this and agreed it was an issue.

If this is something that OpenAPI has trouble grasping, I won't share anymore.

Besides you have not just been passively rude, you are now open about it

So I'll gladly leave. You won't have me sharing with you anymore or trying to help you improve the spec. Trust me.

Since when is someone upvoting 'Again, no idea what you're referring to' level headed. That's upvoting passive aggression.

I am the one who upvoted that (I just checked to make sure no one else had). I did so because I am also confused and wanted to indicate that more people who are reading this thread may be confused. I did not have anything worth saying on the actual thread so I did not say anything. And my name is on it either way, so I am accountable whether I post a comment or not.

And in that vein, if such an upvote was against community standards or preferences, then I apologize for not considering that beforehand. I'm leaving it there so the conversation continues to make sense, but I am also happy to remove it or address any problems in whatever way is preferred by the project. Also, I am fine with the admins deleting this comment if they wish as it does not contribute to the primary discussion.

However, since my upvote was called out, I felt that I should explain my intent, even if it did not land as intended.

Regardless, explaining an architectural cross cutting concern is 'unsafe'.
I won't share anymore

@handrews Your upvote of a comment declaring a failure to understand is perfectly acceptable response in my opinion. In an online world it is never easy to convey sentiment, therefore we must "assume the best" when interpreting every comment.

@orubel We've had this conversation before. I am convinced you have a lot to contribute to this community, but you need to find a way to communicate your ideas in language that your target audience can grok. I have repeatedly tried to parse what you are saying and I have failed. That may be completely my fault, but we both lose if you cannot convey your ideas successfully.

What is not acceptable is making belittling comments such as "This may be a bit over your head". Everyone in this community is held to a higher standard than that.

I'm going to close this issue so that this whole thread can be relegated to the past. If you wish to start a fresh one about how you feel an authorization framework could be layered on top of OpenAPI, you are welcome to do so. However, before you do so, could you spend a bit more time familiarizing yourself with how OpenAPI works, as your comments on the x- extensions seem to indicate that you have misunderstood what they are.

@darrelmiller Wasn't meant as belittling. Some people do have issue with understanding
the paradigm. Others don't. This was what was meant and nothing more.

Talking about this to Netflix, AWS team and at multiple conferences, I have
seen the confusion caused by people who cannot get past the API pattern as
it was originally written for centralized architectures and binds
communication logic to business logic causing a crass cutting concern in
the architecture (a AOP principle).

If this is over your head, don't take insult. Try to understand rather than
tell the person they create an 'unsafe' environment

Truly the subject matter does go over people's heads

I stepped away from the computer for a while, and got back to this.

@handrews while may seem biased, there's nothing wrong with your upvote nor your comment. I do wish you didn't have to write the comment, but completely understand why you felt the need to do so.

There's something to be said about code of conduct and how people treat each other in a community. In fact, we're working on formalizing and adding a code of conduct to this projects to set some basic expectations.

As a community, we all make mistakes, some more severe than others. I'd be the first to admit of making such mistakes and will probably make them again.

@orubel - you were jumping to conclusions with regard to what was suggested to you. You assumed you understand what we're talking about, and went to completely wrong directions. So yes, when we're talking about the ability to declare model field filtering inside the spec, and you jump to talk about specific development languages (even though the spec is language-agnostic), you should expect people to not follow. My question wasn't passive-aggressive. Given that you repeatedly jumped between things, I thought it was pretty clear that it's difficult to follow.

You obviously also didn't take time to read the spec and see what it offers. This is based on your suggestions and reactions to our suggestions. Now, you can claim that we didn't take the time to read the ideas you provided in the link that you provided. You'd be right, except it is you who are trying to introduce something new to this spec, and not the other way around. As such, if you bring up an idea, which we very much appreciate, it is on you to explain it. Sure, I'd go and read the link at some point, but maybe I don't have time to do that right now (and I don't). You want to continue the discussion? That's fine. Take the time to make sure your message is clear.

You are not doing us a favor by suggesting new features. If you want to help the community, then do it. Our (the TSC's) job is to go through feature suggestions, read feedback from users, try to make proposals ourselves and decide whether it fits and makes sense to put into the spec based on some criteria. It is _not_ our job to be experts in all-things-API.

Now, as much as I'd rather we all be nice, I don't see that as a requirement. I don't mind when people provide terse responses that may seem rude. I don't mind when people challenge my opinions/suggestions (and yes, I've been wrong numerous times). However, there are lines that should not be crossed. and you crossed it. I'm sorry if you don't see, but it's obvious that others on this thread did. This is not because your comment was directed at me (because, let's face it, you don't even know me to be able to make such a comment). I would have closed the ticket just like @darrelmiller did, if it were directed to anyone else.

I had a hard time deciding whether to write this at all or let it go. However, I believe there's room to take a clear stance on these things. All of us who work here, whether the TSC or the community itself, do so voluntarily and there's absolutely no reason to accept such interactions.

I'm going to do something I generally avoid doing, and lock this thread. I do encourage people to think about these things, and fully accept not everyone is going to agree with what was said, by either side. However, further active discussion here may lead to more toxicity which should be avoided.

If anyone wants to bring up the same issue at the original post and have a productive discussion, please file a new ticket and we can start over.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

john1452 picture john1452  路  5Comments

nomadtechie picture nomadtechie  路  4Comments

aedart picture aedart  路  4Comments

niquola picture niquola  路  5Comments

rocchisanijl picture rocchisanijl  路  5Comments