-
Notifications
You must be signed in to change notification settings - Fork 110
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
Adding group attribute to credentials #289
Changes from all commits
af60c13
7504048
b7ba9e6
e1b5b2b
1600761
2c6906d
e9703b9
77ce22c
e9b0250
7e57226
5b64932
735330f
b760ece
2d23faf
969cc6d
d54455e
3fc761a
5c42671
fb42943
059f440
8ba1be5
8dee816
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2,6 +2,7 @@ | |||||||||||||
import logging | ||||||||||||||
import datetime | ||||||||||||||
import random | ||||||||||||||
import grp | ||||||||||||||
|
||||||||||||||
import yaml | ||||||||||||||
from six.moves.urllib.parse import urlparse | ||||||||||||||
|
@@ -113,13 +114,24 @@ def set_expiration(self): | |||||||||||||
max_expiration = now + datetime.timedelta(seconds=max_lifetime) | ||||||||||||||
session['max_expiration'] = max_expiration | ||||||||||||||
|
||||||||||||||
def set_current_user(self, email, first_name=None, last_name=None): | ||||||||||||||
def set_current_user(self, email, first_name=None, last_name=None, username=None): | ||||||||||||||
if email is None or email == '': | ||||||||||||||
raise errors.UserUnknownError('No email provided') | ||||||||||||||
|
||||||||||||||
session['user'] = { | ||||||||||||||
'email': email, | ||||||||||||||
'first_name': first_name, | ||||||||||||||
'last_name': last_name, | ||||||||||||||
'groups': [] | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
if username is None: | ||||||||||||||
username = email.strip().split('@')[0] | ||||||||||||||
|
||||||||||||||
if app.config.get('USE_GROUPS'): | ||||||||||||||
all_groups = grp.getgrall() | ||||||||||||||
session['user']['groups'] = [g.gr_name for g in all_groups if email in g.gr_mem] | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be good if fetching groups was something modular, as it's possible that some folks will get the user's group from a SAML assertion, some will get it from a header, and others may want to use unix groups like this. |
||||||||||||||
|
||||||||||||||
def current_email(self): | ||||||||||||||
ret = self.current_user()['email'].lower() | ||||||||||||||
# when migrating from 2 -> 3, the session email object may be bytes | ||||||||||||||
|
@@ -131,6 +143,13 @@ def current_first_name(self): | |||||||||||||
def current_last_name(self): | ||||||||||||||
return self.current_user()['last_name'] | ||||||||||||||
|
||||||||||||||
def current_groups(self): | ||||||||||||||
groups = self.current_user().get('groups') | ||||||||||||||
if groups is None: | ||||||||||||||
return [] | ||||||||||||||
else: | ||||||||||||||
return groups | ||||||||||||||
Comment on lines
+147
to
+151
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
def redirect_to_index(self): | ||||||||||||||
return redirect(flask.url_for('index')) | ||||||||||||||
|
||||||||||||||
|
@@ -251,6 +270,7 @@ def current_user(self): | |||||||||||||
'email': 'unauthenticated user', | ||||||||||||||
'first_name': 'unauthenticated', | ||||||||||||||
'last_name': 'user', | ||||||||||||||
'groups': [] | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
def is_authenticated(self): | ||||||||||||||
|
@@ -299,22 +319,27 @@ def assert_headers(self): | |||||||||||||
def current_user(self): | ||||||||||||||
self.assert_headers() | ||||||||||||||
|
||||||||||||||
info = { | ||||||||||||||
'email': request.headers[self.email_header], | ||||||||||||||
|
||||||||||||||
# TODO: should we use a string like "unknown", fall back to the | ||||||||||||||
# email/username, ...? | ||||||||||||||
'first_name': '', | ||||||||||||||
'last_name': '', | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
first_name = None | ||||||||||||||
if self.first_name_header and self.first_name_header in request.headers: | ||||||||||||||
info['first_name'] = request.headers[self.first_name_header] | ||||||||||||||
first_name = request.headers[self.first_name_header] | ||||||||||||||
|
||||||||||||||
last_name = None | ||||||||||||||
if self.last_name_header and self.last_name_header in request.headers: | ||||||||||||||
info['last_name'] = request.headers[self.last_name_header] | ||||||||||||||
|
||||||||||||||
return info | ||||||||||||||
last_name = request.headers[self.last_name_header] | ||||||||||||||
|
||||||||||||||
username = None | ||||||||||||||
if self.username_header and self.username_header in request.headers: | ||||||||||||||
username = request.headers[self.username_header] | ||||||||||||||
|
||||||||||||||
# Set current user on every request to ensure that the user's group | ||||||||||||||
# list is updated (TODO: caching?) | ||||||||||||||
self.set_current_user( | ||||||||||||||
request.headers[self.email_header], | ||||||||||||||
first_name = first_name, | ||||||||||||||
last_name = last_name, | ||||||||||||||
username = username | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. first_name and last_name here are changing their defaults from '' to None. Will this cause typing issues anywhere? |
||||||||||||||
) | ||||||||||||||
return session['user'] | ||||||||||||||
|
||||||||||||||
def is_authenticated(self): | ||||||||||||||
"""Any user that is able to make requests is authenticated""" | ||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,15 @@ | |
<label for="credentialEnabled">Credential Enabled</label> | ||
<span editable-checkbox="credential.enabled" id="credentialEnabled">{{ credential.enabled }}</span> | ||
</div> | ||
<div class="form-group"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since there's a server-side setting for whether groups are enabled or not, it would be good to only display this section if it's enabled. You can send the configuration option back to the client via the client config (https://github.com/lyft/confidant/blob/master/confidant/routes/identity.py#L127-L138). You can access the client config in the view and controller. It's already pulled into the scope; see this for example: https://github.com/lyft/confidant/blob/master/confidant/public/modules/resources/controllers/CredentialDetailsCtrl.js#L52-L53 |
||
<label for="credentialGroup">Credential Group</label> | ||
<span editable-select="credential.group" | ||
e-ng-options="x for x in groups( {{user.groups}} )" | ||
id="credentialGroupInput"> | ||
{{ credential.group || 'No group set' }} | ||
</span> | ||
<span ng-show="credential.id && !credential.authorized">YOU ARE NOT AUTHORIZED TO VIEW OR MODIFY THIS CREDENTIAL'S DETAILS</span> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We return permission hints from individual resource level endpoints, for ACL checks; see: https://lyft.github.io/confidant/api.html#get--v1-credentials-(id) |
||
</div> | ||
<div class="form-group"> | ||
<label for="credentialPairInputs">Credential Pairs <span class="glyphicon glyphicon-lock"></span></label> | ||
<div class="well well-sm" id="credentialPairInputs"> | ||
|
@@ -148,7 +157,7 @@ | |
</div> | ||
|
||
<div class="buttons has-margin-bottom-lg"> | ||
<button type="button" class="btn btn-default" ng-click="editableForm.$show()" ng-show="!editableForm.$visible">Edit</button> | ||
<button type="button" class="btn btn-default" ng-click="editableForm.$show()" ng-show="!editableForm.$visible && credential.authorized">Edit</button> | ||
<span ng-show="editableForm.$visible"> | ||
<button type="submit" class="btn" ng-disabled="editableForm.$waiting">Save</button> | ||
<button type="button" class="btn btn-alternate" ng-disabled="editableForm.$waiting" ng-click="editableForm.$cancel()">Cancel</button> | ||
|
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 should be implemented as an ACL check against actions of a resource: https://lyft.github.io/confidant/acls.html