-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Client application specific scopes #469
Client application specific scopes #469
Conversation
class ScopesValidator < ActiveModel::Validator | ||
def validate(record) | ||
return unless record.scopes_string.present? | ||
unless Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(record.scopes_string, Doorkeeper.configuration.scopes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [117/80]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can extract the condition to a private method.
I think overall it's an interesting idea (one that I would personally like to use) that being said it doesn't seem like @tute wants to support this in Doorkeeper, which I can understand. I'd be interested to see if there was a way to put it out into a gem? The Admin panel isn't easily plugable from what I've seen, but I may just be doing it wrong. |
Nice feature, my project also has the same problem. |
Changing my mind about this feature. I wish OAuth spec was not so broad. :) Citing https://tools.ietf.org/html/rfc6749#section-10.3:
This implies that this PR should sooner or later land into Doorkeeper. @iangreenleaf your solution in #492 is more general, but in this case, given that section of the spec, we'll actually want to make client-specific scopes a first class citizen. Thank you all for your work. Will keep this in the roadmap. |
@@ -9,6 +9,7 @@ def self.configure(&block) | |||
@config = Config::Builder.new(&block).build | |||
enable_orm | |||
setup_application_owner if @config.enable_application_owner? | |||
setup_application_scopes if @config.enable_application_scopes? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need the config, it should always be enabled, as the spec expects this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file should remain mostly unchanged.
One thing that neither my PR nor this PR offers, but that probably should be implemented based on the spec, is the ability to ignore the scopes requested by the client and respond with a different set of scopes. That actually seems to be the preferred way of dealing with this, rather than throwing an error as we have been doing. |
I'd also still advocate for a more generic solution, based on this part of the spec:
To me, "based on the authorization server policy" casts a pretty wide net, so it would be nice to support scope limits based on a variety of different policies. |
excellent. i'll update this PR with your comments as soon as i can. |
@iangreenleaf it's pretty easy for the application server to modify the scopes in the authorizations controller without getting too deep. we already do this, even going as far as allowing the user to deny scopes that the client applications request. |
206e37a
to
b3f9172
Compare
other_array = other.present? ? other.all : [] | ||
self.class.from_array(self.all & other_array) | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra empty line detected at body end.
b3f9172
to
cca7c2c
Compare
other_array = other.present? ? other.all : [] | ||
self.class.from_array(self.all & other_array) | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra empty line detected at body end.
cca7c2c
to
41f4605
Compare
@@ -38,5 +39,6 @@ def generate_uid | |||
def generate_secret | |||
self.secret ||= UniqueToken.generate | |||
end | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra empty line detected at body end.
Left a few comments, let's also take all Hound comments into account. Thanks for your work! |
application | ||
end | ||
|
||
let(:client) { double :client, redirect_uri: 'http://tst.com/auth', application: application } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [98/80]
aa39f30
to
92094af
Compare
This is looking great, thanks for your work! Looking forward to merge it and release doorkeeper 2. |
@cpapazian regarding default behavior, I'll explain what I had in mind, and you please tell what what you have in mind until we solve it the best way. I think of a transparent "it's there if you need it" feature, where the application level scopes are blank (empty string) in the DB by default. If you decide to use them, in the admin for oauth apps you just define which scopes can an application use. In that case, you enable this functionality. Let's say I have an existing app, where I don't have this behavior yet (or even a new one which I'm now starting). I run the migrations, and, no matter what I configure as Doorkeeper scopes, the DB starts with blank scopes. I use everything, all works, then I decide to filter out The intersection, then, should happen if an application overrides the default empty string. To make this very clear from the code up to the admin interface, we could call the DB attribute The reason I prefer to avoid needing to always set the scopes is that both they have to be in sync with the configuration of Doorkeeper, which may change app per app; and one may forget to seed in correct values. What do you think of it? Thanks again for your work! |
Yup, that all makes sense, and is what I had in mind when I originally set this up as a configuration setting. I'll make the changes to what I have to fit your description. I I'd like to keep the database attribute as scopes so that I can reuse the mixin that |
All great!
Better an empty string, so we keep the same type everywhere and we avoid |
I see what you mean ... The issue I am having is that I'd like to differentiate between a client application disallowing all scopes from a client application that does not want to specify scopes (and let the config/server manage that). If you don't think that's important, then it'll be simple to use the empty string to mean that the client application will not restrict scopes. Or maybe you have some thoughts on how to achieve this another way. |
BTW, this is what I had in mind with nil application scopes: cpapazian#1 I'm keeping it out of this branch for now, as it required even more changes than expected, but it accomplishes the "it's there if you need it" requirement. Changing the default value of scopes on the access_grants and access_tokens table seems like a good thing, but there was quite a few hoops to jump through to handle nil scopes on application (to be fair, you did warn me). Anyway, curious your thoughts. |
Why would such application be defined in the provider? Could it perform any OAuth flow, if it rejects any scope? I think we are fine making empty string mean "accept all". |
@@ -0,0 +1,5 @@ | |||
class AddScopesToApplication < ActiveRecord::Migration | |||
def change | |||
add_column :oauth_applications, :scopes, :string, default: '' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot to mention: let's disallow NULL: null: false
.
|
Sounds good. I'll make the changes tomorrow. FWIW, It was pointed out to me (by @yozlet) that If a provider really wants this null scope behavior, they could define a "null" scope that does not grant any interesting permissions. |
if client.application.scopes.empty? | ||
Helpers::ScopeChecker.valid?(scope, server.scopes) | ||
else | ||
Helpers::ScopeChecker.valid?(scope, server.scopes & client.application.scopes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [88/80]
Looks great!
Soon to merge. Thanks! 👏 |
ab03577
to
8fe62b2
Compare
Added a line to CHANGELOG.md. Didn't see an UPGRADING.md, so I created one ... assuming you'll move that to the wiki? Rebased and sqaushed, too. |
If there no scopes (empty string) defined in the Doorkeeper::Application record, PreAuthorization should only compare scopes against the config/server scopes. If there are scopes on the Doorkeeper::Application record, the set of valid scopes is the intersection of the config/server and the Doorkeeper::Application record scopes.
8fe62b2
to
1c89cc5
Compare
Client application specific scopes
Thank you! |
in order to restrict scopes that applications can grant to clients: doorkeeper-gem/doorkeeper#469
in order to restrict scopes that applications can grant to clients: doorkeeper-gem/doorkeeper#469
@tute @cpapazian Just stumbled upon this and it's saved me so much time. I thought I had to do this manually. Is this documented anywhere? https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes Only mentions creating and using scopes, but not limiting per Application. I can write something in the Wiki about it unless it's documented somewhere else? |
Please do! Thank you. :) |
@tute Got around to adding this https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes#limiting-scopes-per-application Feel free to make your own changes. |
This PR attempts to address #317. We saw @tute's comments, but could not find a great way to implement this without either putting all of the logic into the authoriizations controller (doing an end run around the work that the
OAuth::PreAuthorizations
class does, or monkeypatching Doorkeeper a bit. So I created this PR in an attempt to implement this functionality in a way that fits with the rest of the Doorkeeper API.It works by adding a
scopes
field to theDoorkeeper::Application
model and validating the requested scopes against it during pre-authorization. Whenenable_application_scopes
is set, theDoorkeeper::Models::Scopes
mixin is added toDoorkeeper::Application
andvalidate_scopes
will check both the server/config scopes as well as the client application's scopes.Still TODO: adding support to the admin pages and testing with ORM's besides ActiveRecord
In the meantime, I would greatly appreciate some feedback.
thanks,
-chris