-
Notifications
You must be signed in to change notification settings - Fork 13.9k
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
Implement permission request/approve flow. #1095
Conversation
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.
Looks neat!
name=datasource_name) | ||
}} | ||
</h4> | ||
<div id="app"> |
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.
no need for id="app"
afaict
{% block title %}{{ _("No Access!") }}{% endblock %} | ||
{% block body %} | ||
{% include "caravel/flash_wrapper.html" %} | ||
<h4> |
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.
wrap the whole thing in a <div class="container">
to get a nice left and right margin
@@ -1181,6 +1186,10 @@ def refresh_datasources(self): | |||
if datasource not in config.get('DRUID_DATA_SOURCE_BLACKLIST'): | |||
DruidDatasource.sync_to_db(datasource, self) | |||
|
|||
@property |
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.
oh this should now be in master now
return self.table | ||
|
||
@property | ||
def datasource_url(self): |
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.
Rename to datasource_link
I'd except a link to be a <a>
and a url to be http://...
list_columns = [ | ||
'username', 'user_roles', 'datasource_url', | ||
'roles_with_datasource', 'created_on'] | ||
order_columns = [ |
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.
nit: would fit on one line
models.DatasourceAccessRequest.druid_datasource_id == | ||
druid_datasource_id, | ||
) | ||
).all() |
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.
NIT: it works here, but .all()
could be aligned with .filter(
) | ||
).all() | ||
|
||
if len(duplicates) > 0: |
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.
Empty lists evals as False
, so you can simply if duplicates:
.filter_by(id=request_access_id).first() | ||
) | ||
# check if you can approve | ||
if (self.all_datasource_access() or |
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 endpoint and model related perms should be added to the admin role only (check the cil's init function), then we don't need anything else than @has_access
.
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.
Done and covered in the unit tests
"danger") | ||
return redirect('/accessrequestsmodelview/list/') | ||
|
||
db.session.delete(access_request) |
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.
Not needed but there could be a need to cleanup here. If I asked access to 12 tables and you grant a single role that gives access to all 8 tables, you could clean up the other 7 requests, but let's leave this out for v1.
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.
Yep, will do it in separate PR
@mistercrunch - please take another look |
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.
Sorry for the "close to the finish line" changes in requirements, tell me what you think.
"danger") | ||
return redirect('/accessrequestsmodelview/list/') | ||
|
||
db.session.delete(access_request) |
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.
I should have caught this before, but it's critical that we keep an audit trail of who granted access to what/who/when. One way to do this is to not delete the request, and flag it as resolved instead (add a state field to the model, a fk to the userid who granted access, timestamp when it was granted, and maybe the resolution that was applied).
Another option is to store the operation in another model.
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.
@log_this
- tackles it now
).all() | ||
) | ||
|
||
|
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.
nit: one too many black line
'Security', | ||
'UserDBModelView', | ||
'SQL Lab <span class="label label-danger">alpha</span>', | ||
'AccessRequestsModelView', |
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 probably need a new role for people who can grant rights to others that are not admin. It doesn't have to be part of this PR, your call.
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.
agree, separate PR
id = Column(Integer, primary_key=True) | ||
|
||
table_id = Column(Integer, ForeignKey('tables.id')) | ||
druid_datasource_id = Column(Integer, ForeignKey('datasources.id')) |
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 probably want to follow the new pattern of datasource_id
and datasource_type
that was introduced in the Yahoo PR
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.
Updated
"""ORM model for the access requests for datasources and dbs.""" | ||
__tablename__ = 'access_request' | ||
id = Column(Integer, primary_key=True) | ||
|
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.
related to my other comment about auditing who granted what to who, I'd add:
state as ('requested', 'granted' and maybe eventually 'denied')
processed_by_userid Integer
processed_on Datetime
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.
I've refactored the code in a way that @log_this
will have all needed information
@mistercrunch - please take one more look on the PR, couple new features
|
flash(USER_MISSING_ERR, "alert") | ||
return json_error_response(USER_MISSING_ERR) | ||
|
||
requests = (session.query(models.DatasourceAccessRequest).filter( |
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.
optional: indent is inconsistent with other queries, looks like maybe sublime auto-indented that.
Sometimes when I have long strings that get referenced a lot in a small section of code, I create a shortcut as in DAR = models.DatasourceAccessRequest
.
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.
Done, thanks
LGTM. This is an awesome feature, great work! It's lowering friction around obtaining access, granting access, and addressing the lack of auditing around access, all this is super impactful. Follow up, related items:
|
Hello, I don't see any information on how to activate this feature. I don't see it in the latest release of superset, 0.37.2. Does anyone know if it can be activated in that version? |
Found the setting the full example config file: https://github.com/apache/incubator-superset/blob/master/superset/config.py
|
After enabling this feature, I'm getting "NOT FOUND". Is there something else that needs to be activated in order to get this feature to work? |
This PR implements the basic request permissions flow: #1049
For the 1st iteration it is pretty simple flow:
Potential future improvements:
Reviewers:
Screenshots