2017-12-08 22:05:59 +00:00
|
|
|
""" Manages app specific tokens for the current user. """
|
|
|
|
|
|
|
|
import logging
|
2017-12-12 22:51:54 +00:00
|
|
|
import math
|
2017-12-08 22:05:59 +00:00
|
|
|
|
2017-12-12 22:51:54 +00:00
|
|
|
from datetime import timedelta
|
2017-12-08 22:05:59 +00:00
|
|
|
from flask import request
|
|
|
|
|
|
|
|
import features
|
|
|
|
|
2017-12-12 22:51:54 +00:00
|
|
|
from app import app
|
2017-12-08 22:05:59 +00:00
|
|
|
from auth.auth_context import get_authenticated_user
|
|
|
|
from data import model
|
|
|
|
from endpoints.api import (ApiResource, nickname, resource, validate_json_request,
|
|
|
|
log_action, require_user_admin, require_fresh_login,
|
2017-12-12 22:51:54 +00:00
|
|
|
path_param, NotFound, format_date, show_if, query_param, parse_args,
|
|
|
|
truthy_bool)
|
|
|
|
from util.timedeltastring import convert_to_timedelta
|
2017-12-08 22:05:59 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2017-12-12 22:51:54 +00:00
|
|
|
|
2017-12-08 22:05:59 +00:00
|
|
|
def token_view(token, include_code=False):
|
|
|
|
data = {
|
|
|
|
'uuid': token.uuid,
|
|
|
|
'title': token.title,
|
|
|
|
'last_accessed': format_date(token.last_accessed),
|
|
|
|
'created': format_date(token.created),
|
|
|
|
'expiration': format_date(token.expiration),
|
|
|
|
}
|
|
|
|
|
|
|
|
if include_code:
|
|
|
|
data.update({
|
|
|
|
'token_code': token.token_code,
|
|
|
|
})
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
2017-12-12 22:51:54 +00:00
|
|
|
|
|
|
|
# The default window to use when looking up tokens that will be expiring.
|
|
|
|
_DEFAULT_TOKEN_EXPIRATION_WINDOW = '4w'
|
|
|
|
|
|
|
|
|
2017-12-08 22:05:59 +00:00
|
|
|
@resource('/v1/user/apptoken')
|
|
|
|
@show_if(features.APP_SPECIFIC_TOKENS)
|
|
|
|
class AppTokens(ApiResource):
|
|
|
|
""" Lists all app specific tokens for a user """
|
|
|
|
schemas = {
|
|
|
|
'NewToken': {
|
|
|
|
'type': 'object',
|
|
|
|
'required': [
|
|
|
|
'title',
|
|
|
|
],
|
|
|
|
'properties': {
|
|
|
|
'title': {
|
|
|
|
'type': 'string',
|
|
|
|
'description': 'The user-defined title for the token',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
@require_user_admin
|
|
|
|
@nickname('listAppTokens')
|
2017-12-12 22:51:54 +00:00
|
|
|
@parse_args()
|
|
|
|
@query_param('expiring', 'If true, only returns those tokens expiring soon', type=truthy_bool)
|
|
|
|
def get(self, parsed_args):
|
2017-12-08 22:05:59 +00:00
|
|
|
""" Lists the app specific tokens for the user. """
|
2017-12-12 22:51:54 +00:00
|
|
|
expiring = parsed_args['expiring']
|
|
|
|
if expiring:
|
|
|
|
expiration = app.config.get('APP_SPECIFIC_TOKEN_EXPIRATION')
|
|
|
|
token_expiration = convert_to_timedelta(expiration or _DEFAULT_TOKEN_EXPIRATION_WINDOW)
|
|
|
|
seconds = math.ceil(token_expiration.total_seconds() * 0.1) or 1
|
|
|
|
soon = timedelta(seconds=seconds)
|
|
|
|
tokens = model.appspecifictoken.get_expiring_tokens(get_authenticated_user(), soon)
|
|
|
|
else:
|
|
|
|
tokens = model.appspecifictoken.list_tokens(get_authenticated_user())
|
|
|
|
|
2017-12-08 22:05:59 +00:00
|
|
|
return {
|
|
|
|
'tokens': [token_view(token, include_code=False) for token in tokens],
|
2017-12-12 22:51:54 +00:00
|
|
|
'only_expiring': expiring,
|
2017-12-08 22:05:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@require_user_admin
|
|
|
|
@require_fresh_login
|
|
|
|
@nickname('createAppToken')
|
|
|
|
@validate_json_request('NewToken')
|
|
|
|
def post(self):
|
|
|
|
""" Create a new app specific token for user. """
|
|
|
|
title = request.get_json()['title']
|
|
|
|
token = model.appspecifictoken.create_token(get_authenticated_user(), title)
|
|
|
|
|
|
|
|
log_action('create_app_specific_token', get_authenticated_user().username,
|
|
|
|
{'app_specific_token_title': token.title,
|
|
|
|
'app_specific_token': token.uuid})
|
|
|
|
|
|
|
|
return {
|
|
|
|
'token': token_view(token, include_code=True),
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@resource('/v1/user/apptoken/<token_uuid>')
|
|
|
|
@show_if(features.APP_SPECIFIC_TOKENS)
|
|
|
|
@path_param('token_uuid', 'The uuid of the app specific token')
|
|
|
|
class AppToken(ApiResource):
|
|
|
|
""" Provides operations on an app specific token """
|
|
|
|
@require_user_admin
|
|
|
|
@require_fresh_login
|
|
|
|
@nickname('getAppToken')
|
|
|
|
def get(self, token_uuid):
|
|
|
|
""" Returns a specific app token for the user. """
|
|
|
|
token = model.appspecifictoken.get_token_by_uuid(token_uuid, owner=get_authenticated_user())
|
|
|
|
if token is None:
|
|
|
|
raise NotFound()
|
|
|
|
|
|
|
|
return {
|
|
|
|
'token': token_view(token, include_code=True),
|
|
|
|
}
|
|
|
|
|
|
|
|
@require_user_admin
|
|
|
|
@require_fresh_login
|
|
|
|
@nickname('revokeAppToken')
|
|
|
|
def delete(self, token_uuid):
|
|
|
|
""" Revokes a specific app token for the user. """
|
2018-01-23 16:40:51 +00:00
|
|
|
token = model.appspecifictoken.revoke_token_by_uuid(token_uuid, owner=get_authenticated_user())
|
2017-12-08 22:05:59 +00:00
|
|
|
if token is None:
|
|
|
|
raise NotFound()
|
|
|
|
|
|
|
|
log_action('revoke_app_specific_token', get_authenticated_user().username,
|
|
|
|
{'app_specific_token_title': token.title,
|
|
|
|
'app_specific_token': token.uuid})
|
|
|
|
|
|
|
|
return '', 204
|