diff --git a/lemur/api_keys/schemas.py b/lemur/api_keys/schemas.py index 32fabf47..30c41c58 100644 --- a/lemur/api_keys/schemas.py +++ b/lemur/api_keys/schemas.py @@ -5,21 +5,27 @@ :license: Apache, see LICENSE for more details. .. moduleauthor:: Eric Coan """ +from flask import g from marshmallow import fields from lemur.common.schema import LemurInputSchema, LemurOutputSchema +from lemur.users.schemas import UserNestedOutputSchema, UserInputSchema + + +def current_user_id(): + return {'id': g.current_user.id, 'email': g.current_user.email, 'username': g.current_user.username} class ApiKeyInputSchema(LemurInputSchema): name = fields.String(required=False) - user_id = fields.Integer() + user = fields.Nested(UserInputSchema, missing=current_user_id, default=current_user_id) ttl = fields.Integer() class ApiKeyRevokeSchema(LemurInputSchema): - id = fields.Integer(required=False) + id = fields.Integer(required=True) name = fields.String() - user_id = fields.Integer(required=False) + user = fields.Nested(UserInputSchema, required=True) revoked = fields.Boolean() ttl = fields.Integer() issued_at = fields.Integer(required=False) @@ -37,7 +43,7 @@ class ApiKeyOutputSchema(LemurOutputSchema): class ApiKeyDescribedOutputSchema(LemurOutputSchema): id = fields.Integer() name = fields.String() - user_id = fields.Integer() + user = fields.Nested(UserNestedOutputSchema) ttl = fields.Integer() issued_at = fields.Integer() revoked = fields.Boolean() diff --git a/lemur/api_keys/views.py b/lemur/api_keys/views.py index 0a1a22e5..8986afdc 100644 --- a/lemur/api_keys/views.py +++ b/lemur/api_keys/views.py @@ -28,6 +28,7 @@ api = Api(mod) class ApiKeyList(AuthenticatedResource): """ Defines the 'api_keys' endpoint """ + def __init__(self): super(ApiKeyList, self).__init__() @@ -123,16 +124,17 @@ class ApiKeyList(AuthenticatedResource): :statuscode 403: unauthenticated """ if not ApiKeyCreatorPermission().can(): - if data['user_id'] != g.current_user.id: - return dict(message="You are not authorized to create tokens for: {0}".format(data['user_id'])), 403 + if data['user']['id'] != g.current_user.id: + return dict(message="You are not authorized to create tokens for: {0}".format(data['user']['username'])), 403 - access_token = service.create(name=data['name'], user_id=data['user_id'], ttl=data['ttl'], - revoked=False, issued_at=int(datetime.utcnow().timestamp())) + access_token = service.create(name=data['name'], user_id=data['user']['id'], ttl=data['ttl'], + revoked=False, issued_at=int(datetime.utcnow().timestamp())) return dict(jwt=create_token(access_token.user_id, access_token.id, access_token.ttl)) class ApiKeyUserList(AuthenticatedResource): """ Defines the 'keys' endpoint on the 'users' endpoint. """ + def __init__(self): super(ApiKeyUserList, self).__init__() @@ -231,7 +233,7 @@ class ApiKeyUserList(AuthenticatedResource): return dict(message="You are not authorized to create tokens for: {0}".format(user_id)), 403 access_token = service.create(name=data['name'], user_id=user_id, ttl=data['ttl'], - revoked=False, issued_at=int(datetime.utcnow().timestamp())) + revoked=False, issued_at=int(datetime.utcnow().timestamp())) return dict(jwt=create_token(access_token.user_id, access_token.id, access_token.ttl)) @@ -272,11 +274,14 @@ class ApiKeys(AuthenticatedResource): :statuscode 403: unauthenticated """ access_key = service.get(aid) + if access_key is None: return dict(message="This token does not exist!"), 404 + if access_key.user_id != g.current_user.id: if not ApiKeyCreatorPermission().can(): return dict(message="You are not authorized to view this token!"), 403 + return dict(jwt=create_token(access_key.user_id, access_key.id, access_key.ttl)) @validate_schema(api_key_revoke_schema, api_key_output_schema) @@ -319,9 +324,11 @@ class ApiKeys(AuthenticatedResource): access_key = service.get(aid) if access_key is None: return dict(message="This token does not exist!"), 404 + if access_key.user_id != g.current_user.id: if not ApiKeyCreatorPermission().can(): return dict(message="You are not authorized to update this token!"), 403 + service.update(access_key, name=data['name'], revoked=data['revoked'], ttl=data['ttl']) return dict(jwt=create_token(access_key.user_id, access_key.id, access_key.ttl)) @@ -358,9 +365,11 @@ class ApiKeys(AuthenticatedResource): access_key = service.get(aid) if access_key is None: return dict(message="This token does not exist!"), 404 + if access_key.user_id != g.current_user.id: if not ApiKeyCreatorPermission().can(): return dict(message="You are not authorized to delete this token!"), 403 + service.delete(access_key) return {'result': True} @@ -404,11 +413,15 @@ class UserApiKeys(AuthenticatedResource): if uid != g.current_user.id: if not ApiKeyCreatorPermission().can(): return dict(message="You are not authorized to view this token!"), 403 + access_key = service.get(aid) + if access_key is None: return dict(message="This token does not exist!"), 404 + if access_key.user_id != uid: return dict(message="You are not authorized to view this token!"), 403 + return dict(jwt=create_token(access_key.user_id, access_key.id, access_key.ttl)) @validate_schema(api_key_revoke_schema, api_key_output_schema) @@ -451,11 +464,14 @@ class UserApiKeys(AuthenticatedResource): if uid != g.current_user.id: if not ApiKeyCreatorPermission().can(): return dict(message="You are not authorized to view this token!"), 403 + access_key = service.get(aid) if access_key is None: return dict(message="This token does not exist!"), 404 + if access_key.user_id != uid: return dict(message="You are not authorized to update this token!"), 403 + service.update(access_key, name=data['name'], revoked=data['revoked'], ttl=data['ttl']) return dict(jwt=create_token(access_key.user_id, access_key.id, access_key.ttl)) @@ -492,11 +508,14 @@ class UserApiKeys(AuthenticatedResource): if uid != g.current_user.id: if not ApiKeyCreatorPermission().can(): return dict(message="You are not authorized to view this token!"), 403 + access_key = service.get(aid) if access_key is None: return dict(message="This token does not exist!"), 404 + if access_key.user_id != uid: return dict(message="You are not authorized to delete this token!"), 403 + service.delete(access_key) return {'result': True} @@ -545,9 +564,11 @@ class ApiKeysDescribed(AuthenticatedResource): access_key = service.get(aid) if access_key is None: return dict(message="This token does not exist!"), 404 + if access_key.user_id != g.current_user.id: if not ApiKeyCreatorPermission().can(): return dict(message="You are not authorized to view this token!"), 403 + return access_key diff --git a/lemur/static/app/angular/api_keys/api_key/api_key.js b/lemur/static/app/angular/api_keys/api_key/api_key.js index 28542818..a0b3fa1c 100644 --- a/lemur/static/app/angular/api_keys/api_key/api_key.js +++ b/lemur/static/app/angular/api_keys/api_key/api_key.js @@ -1,50 +1,18 @@ 'use strict'; angular.module('lemur') - .controller('ApiKeysCreateController', function ($scope, $uibModalInstance, PluginService, ApiKeyService, LemurRestangular, toaster) { + .controller('ApiKeysCreateController', function ($scope, $uibModalInstance, PluginService, ApiKeyService, UserService, LemurRestangular, toaster) { $scope.apiKey = LemurRestangular.restangularizeElement(null, {}, 'keys'); + $scope.origin = window.location.origin; + $scope.save = function (apiKey) { ApiKeyService.create(apiKey).then( function (responseBody) { toaster.pop({ type: 'success', title: 'Success!', - body: 'Successfully Created JWT!' - }); - $scope.jwt = responseBody.jwt; - }, function (response) { - toaster.pop({ - type: 'error', - title: apiKey.name || 'Unnamed Api Key', - body: 'lemur-bad-request', - bodyOutputType: 'directive', - directiveData: response.data, - timeout: 100000 - }); - }); - }; - - $scope.cancel = function () { - $uibModalInstance.dismiss('cancel'); - }; - - $scope.close = function() { - $uibModalInstance.close(); - }; - }) - .controller('ApiKeysEditController', function ($scope, $uibModalInstance, ApiKeyService, LemurRestangular, toaster, editId) { - LemurRestangular.one('keys', editId).customGET('described').then(function(apiKey) { - $scope.apiKey = apiKey; - }); - - $scope.save = function (apiKey) { - ApiKeyService.update(apiKey).then( - function (responseBody) { - toaster.pop({ - type: 'success', - title: 'Success', - body: 'Successfully updated JWT!' + body: 'Successfully Created API Token!' }); $scope.jwt = responseBody.jwt; }, function (response) { @@ -66,4 +34,45 @@ angular.module('lemur') $scope.close = function() { $uibModalInstance.close(); }; + + $scope.userService = UserService; + }) + .controller('ApiKeysEditController', function ($scope, $uibModalInstance, ApiKeyService, UserService, LemurRestangular, toaster, editId) { + LemurRestangular.one('keys', editId).customGET('described').then(function(apiKey) { + $scope.apiKey = apiKey; + $scope.selectedUser = apiKey.user; + }); + + $scope.origin = window.location.origin; + + $scope.save = function (apiKey) { + ApiKeyService.update(apiKey).then( + function (responseBody) { + toaster.pop({ + type: 'success', + title: 'Success', + body: 'Successfully updated API Token!' + }); + $scope.jwt = responseBody.jwt; + }, function (response) { + toaster.pop({ + type: 'error', + title: apiKey.name || 'Unnamed API Key', + body: 'lemur-bad-request', + bodyOutputType: 'directive', + directiveData: response.data, + timeout: 100000 + }); + }); + }; + + $scope.cancel = function () { + $uibModalInstance.dismiss('cancel'); + }; + + $scope.close = function() { + $uibModalInstance.close(); + }; + + $scope.userService = UserService; }); diff --git a/lemur/static/app/angular/api_keys/api_key/api_key.tpl.html b/lemur/static/app/angular/api_keys/api_key/api_key.tpl.html index 8c94f7be..948b8940 100644 --- a/lemur/static/app/angular/api_keys/api_key/api_key.tpl.html +++ b/lemur/static/app/angular/api_keys/api_key/api_key.tpl.html @@ -1,10 +1,13 @@ -
+
- +

You must enter an API Key User ID.

@@ -34,15 +40,19 @@ TTL
- +

You must enter an API Key TTL.

-
-

Successfully exported!

-

Your Token is:
{{ jwt }}

+