-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
74db13e
commit dce2744
Showing
5 changed files
with
234 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
{ | ||
"title": "Admin access key", | ||
"$id": "/profiles/access_key.json", | ||
"$schema": "https://json-schema.org/draft/2020-12/schema", | ||
"required": [], | ||
"additionalProperties": false, | ||
"mixinProperties": [ | ||
{ | ||
"$ref": "mixins.json#/schema_version" | ||
}, | ||
{ | ||
"$ref": "mixins.json#/uuid" | ||
}, | ||
{ | ||
"$ref": "mixins.json#/submitted" | ||
}, | ||
{ | ||
"$ref": "mixins.json#/modified" | ||
} | ||
], | ||
"type": "object", | ||
"properties": { | ||
"schema_version": { | ||
"default": "1" | ||
}, | ||
"status": { | ||
"title": "Status", | ||
"type": "string", | ||
"default": "current", | ||
"enum": [ | ||
"current", | ||
"deleted" | ||
] | ||
}, | ||
"user": { | ||
"title": "User", | ||
"comment": "Only admins are allowed to set this value.", | ||
"type": "string", | ||
"linkTo": "User" | ||
}, | ||
"description": { | ||
"title": "Description", | ||
"type": "string", | ||
"formInput": "textarea" | ||
}, | ||
"access_key_id": { | ||
"title": "Access key ID", | ||
"comment": "Only admins are allowed to set this value.", | ||
"type": "string", | ||
"uniqueKey": true | ||
}, | ||
"secret_access_key_hash": { | ||
"title": "Secret access key Hash", | ||
"comment": "Only admins are allowed to set this value.", | ||
"type": "string" | ||
}, | ||
"expiration_date": { | ||
"Title": "Expiration Date", | ||
"comment": "Only admins are allowed to set this value.", | ||
"type": "string", | ||
"permission": "restricted_fields" | ||
} | ||
}, | ||
"facets": { | ||
"user.display_title": { | ||
"title": "User Name" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
"""Access_key types file.""" | ||
|
||
from pyramid.view import view_config | ||
from pyramid.security import ( | ||
Allow, | ||
Deny, | ||
Authenticated, | ||
Everyone, | ||
) | ||
from pyramid.settings import asbool | ||
import datetime | ||
from .base import ( | ||
Item, | ||
DELETED_ACL, | ||
ONLY_ADMIN_VIEW_ACL, | ||
) | ||
from ..authentication import ( | ||
generate_password, | ||
generate_user, | ||
CRYPT_CONTEXT, | ||
) | ||
from snovault import ( | ||
collection, | ||
load_schema, | ||
) | ||
from snovault.crud_views import ( | ||
collection_add, | ||
item_edit, | ||
) | ||
from snovault.validators import ( | ||
validate_item_content_post, | ||
) | ||
from snovault.util import debug_log | ||
|
||
@collection( | ||
name='access-keys', | ||
unique_key='access_key:access_key_id', | ||
properties={ | ||
'title': 'Access keys', | ||
'description': 'Programmatic access keys', | ||
}, | ||
acl=[ | ||
(Allow, Authenticated, 'add'), | ||
(Allow, 'group.admin', 'list'), | ||
(Allow, 'group.read-only-admin', 'list'), | ||
(Allow, 'remoteuser.INDEXER', 'list'), | ||
(Allow, 'remoteuser.EMBED', 'list'), | ||
(Deny, Everyone, 'list'), | ||
]) | ||
class AccessKey(Item): | ||
"""AccessKey class.""" | ||
ACCESS_KEY_EXPIRATION_TIME = 90 # days | ||
item_type = 'access_key' | ||
schema = load_schema('encoded:schemas/access_key.json') | ||
name_key = 'access_key_id' | ||
embedded_list = [] | ||
|
||
STATUS_ACL = { | ||
'current': [(Allow, 'role.owner', ['view', 'edit'])] + ONLY_ADMIN_VIEW_ACL, | ||
'deleted': DELETED_ACL, | ||
} | ||
|
||
@classmethod | ||
def create(cls, registry, uuid, properties, sheets=None): | ||
""" Sets the access key timeout 90 days from creation. """ | ||
properties['expiration_date'] = (datetime.datetime.utcnow() + datetime.timedelta( | ||
days=cls.ACCESS_KEY_EXPIRATION_TIME)).isoformat() | ||
return super().create(registry, uuid, properties, sheets) | ||
|
||
def __ac_local_roles__(self): | ||
"""grab and return user as owner.""" | ||
owner = 'userid.%s' % self.properties['user'] | ||
return {owner: 'role.owner'} | ||
|
||
def __json__(self, request): | ||
"""delete the secret access key has from the object when used.""" | ||
properties = super(AccessKey, self).__json__(request) | ||
del properties['secret_access_key_hash'] | ||
return properties | ||
|
||
def update(self, properties, sheets=None): | ||
"""smth.""" | ||
# make sure PUTs preserve the secret access key hash | ||
if 'secret_access_key_hash' not in properties: | ||
new_properties = self.properties.copy() | ||
new_properties.update(properties) | ||
properties = new_properties | ||
# set new expiration | ||
properties['expiration_date'] = (datetime.datetime.utcnow() + datetime.timedelta( | ||
days=self.ACCESS_KEY_EXPIRATION_TIME)).isoformat() | ||
self._update(properties, sheets) | ||
|
||
class Collection(Item.Collection): | ||
pass | ||
|
||
|
||
# access keys have view permissions for update so readonly admin and the like | ||
# can create access keys to download files. | ||
@view_config(context=AccessKey.Collection, request_method='POST', | ||
permission='add', | ||
validators=[validate_item_content_post]) | ||
@debug_log | ||
def access_key_add(context, request): | ||
"""smth.""" | ||
crypt_context = request.registry[CRYPT_CONTEXT] | ||
|
||
if 'access_key_id' not in request.validated: | ||
request.validated['access_key_id'] = generate_user() | ||
|
||
if 'user' not in request.validated: | ||
request.validated['user'], = [ | ||
principal.split('.', 1)[1] | ||
for principal in request.effective_principals | ||
if principal.startswith('userid.') | ||
] | ||
|
||
password = None | ||
if 'secret_access_key_hash' not in request.validated: | ||
password = generate_password() | ||
request.validated['secret_access_key_hash'] = crypt_context.hash(password) | ||
|
||
result = collection_add(context, request) | ||
|
||
if password is None: | ||
result['secret_access_key'] = None | ||
else: | ||
result['secret_access_key'] = password | ||
|
||
result['access_key_id'] = request.validated['access_key_id'] | ||
result['description'] = request.validated.get('description', "") | ||
return result | ||
|
||
|
||
@view_config(name='reset-secret', context=AccessKey, | ||
permission='add', | ||
request_method='POST', subpath_segments=0) | ||
@debug_log | ||
def access_key_reset_secret(context, request): | ||
"""smth.""" | ||
request.validated = context.properties.copy() | ||
crypt_context = request.registry[CRYPT_CONTEXT] | ||
password = generate_password() | ||
new_hash = crypt_context.hash(password) | ||
request.validated['secret_access_key_hash'] = new_hash | ||
result = item_edit(context, request, render=False) | ||
result['access_key_id'] = request.validated['access_key_id'] | ||
result['secret_access_key'] = password | ||
return result | ||
|
||
|
||
@view_config(context=AccessKey, permission='view_raw', request_method='GET', | ||
name='raw') | ||
@debug_log | ||
def access_key_view_raw(context, request): | ||
"""smth.""" | ||
if asbool(request.params.get('upgrade', True)): | ||
properties = context.upgrade_properties() | ||
else: | ||
properties = context.properties.copy() | ||
del properties['secret_access_key_hash'] | ||
return properties |