Remove secret key on external apps
parent
9e9c302ada
commit
0ba2f6002a
|
@ -1,32 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
|
|
||||||
# Copyright (C) 2014-2016 Jesús Espino <jespinog@gmail.com>
|
|
||||||
# Copyright (C) 2014-2016 David Barragán <bameda@dbarragan.com>
|
|
||||||
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
from Crypto.PublicKey import RSA
|
|
||||||
from jwkest.jwk import SYMKey
|
|
||||||
from jwkest.jwe import JWE
|
|
||||||
|
|
||||||
|
|
||||||
def encrypt(content, key):
|
|
||||||
sym_key = SYMKey(key=key, alg="A128KW")
|
|
||||||
jwe = JWE(content, alg="A128KW", enc="A256GCM")
|
|
||||||
return jwe.encrypt([sym_key])
|
|
||||||
|
|
||||||
|
|
||||||
def decrypt(content, key):
|
|
||||||
sym_key = SYMKey(key=key, alg="A128KW")
|
|
||||||
return JWE().decrypt(content, keys=[sym_key])
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.2 on 2016-09-14 14:13
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('external_apps', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='application',
|
||||||
|
name='key',
|
||||||
|
),
|
||||||
|
]
|
|
@ -40,8 +40,6 @@ class Application(models.Model):
|
||||||
|
|
||||||
next_url = models.TextField(null=False, blank=False, verbose_name=_("Next url"))
|
next_url = models.TextField(null=False, blank=False, verbose_name=_("Next url"))
|
||||||
|
|
||||||
key = models.TextField(null=False, blank=False, verbose_name=_("secret key for ciphering the application tokens"))
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = "application"
|
verbose_name = "application"
|
||||||
verbose_name_plural = "applications"
|
verbose_name_plural = "applications"
|
||||||
|
@ -71,10 +69,6 @@ class ApplicationToken(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{application}: {user} - {token}".format(application=self.application.name, user=self.user.get_full_name(), token=self.token)
|
return "{application}: {user} - {token}".format(application=self.application.name, user=self.user.get_full_name(), token=self.token)
|
||||||
|
|
||||||
@property
|
|
||||||
def cyphered_token(self):
|
|
||||||
return services.cypher_token(self)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def next_url(self):
|
def next_url(self):
|
||||||
return "{url}?auth_code={auth_code}".format(url=self.application.next_url, auth_code=self.auth_code)
|
return "{url}?auth_code={auth_code}".format(url=self.application.next_url, auth_code=self.auth_code)
|
||||||
|
|
|
@ -48,4 +48,4 @@ class AuthorizationCodeSerializer(serializers.LightSerializer):
|
||||||
|
|
||||||
|
|
||||||
class AccessTokenSerializer(serializers.LightSerializer):
|
class AccessTokenSerializer(serializers.LightSerializer):
|
||||||
cyphered_token = Field()
|
token = Field()
|
||||||
|
|
|
@ -23,8 +23,6 @@ from taiga.base.api.utils import get_object_or_404
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from . import encryption
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
def get_user_for_application_token(token:str) -> object:
|
def get_user_for_application_token(token:str) -> object:
|
||||||
|
@ -46,11 +44,3 @@ def authorize_token(application_id:int, user:object, state:str) -> object:
|
||||||
token.state = state
|
token.state = state
|
||||||
token.save()
|
token.save()
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
|
||||||
def cypher_token(application_token:object) -> str:
|
|
||||||
content = {
|
|
||||||
"token": application_token.token
|
|
||||||
}
|
|
||||||
|
|
||||||
return encryption.encrypt(json.dumps(content), application_token.application.key)
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ class ApplicationValidator(validators.ModelValidator):
|
||||||
|
|
||||||
|
|
||||||
class ApplicationTokenValidator(validators.ModelValidator):
|
class ApplicationTokenValidator(validators.ModelValidator):
|
||||||
cyphered_token = serializers.CharField(source="cyphered_token", read_only=True)
|
token = serializers.CharField(source="token", read_only=True)
|
||||||
next_url = serializers.CharField(source="next_url", read_only=True)
|
next_url = serializers.CharField(source="next_url", read_only=True)
|
||||||
application = ApplicationValidator(read_only=True)
|
application = ApplicationValidator(read_only=True)
|
||||||
|
|
||||||
|
@ -46,9 +46,9 @@ class AuthorizationCodeValidator(validators.ModelValidator):
|
||||||
|
|
||||||
|
|
||||||
class AccessTokenValidator(validators.ModelValidator):
|
class AccessTokenValidator(validators.ModelValidator):
|
||||||
cyphered_token = serializers.CharField(source="cyphered_token", read_only=True)
|
token = serializers.CharField(source="token", read_only=True)
|
||||||
next_url = serializers.CharField(source="next_url", read_only=True)
|
next_url = serializers.CharField(source="next_url", read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.ApplicationToken
|
model = models.ApplicationToken
|
||||||
fields = ("cyphered_token", )
|
fields = ("token", )
|
||||||
|
|
|
@ -560,7 +560,6 @@ class ApplicationFactory(Factory):
|
||||||
model = "external_apps.Application"
|
model = "external_apps.Application"
|
||||||
strategy = factory.CREATE_STRATEGY
|
strategy = factory.CREATE_STRATEGY
|
||||||
|
|
||||||
key = "testingkey"
|
|
||||||
|
|
||||||
class ApplicationTokenFactory(Factory):
|
class ApplicationTokenFactory(Factory):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -115,7 +115,6 @@ def test_application_tokens_validate(client, data):
|
||||||
|
|
||||||
data = json.dumps({
|
data = json.dumps({
|
||||||
"application": data.token.application.id,
|
"application": data.token.application.id,
|
||||||
"key": data.token.application.key,
|
|
||||||
"auth_code": data.token.auth_code,
|
"auth_code": data.token.auth_code,
|
||||||
"state": data.token.state
|
"state": data.token.state
|
||||||
})
|
})
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
from taiga.external_apps import encryption
|
|
||||||
from taiga.external_apps import models
|
from taiga.external_apps import models
|
||||||
|
|
||||||
|
|
||||||
|
@ -116,9 +115,7 @@ def test_token_validate(client):
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
token = models.ApplicationToken.objects.get(id=token.id)
|
token = models.ApplicationToken.objects.get(id=token.id)
|
||||||
decyphered_token = encryption.decrypt(response.data["cyphered_token"], token.application.key)[0]
|
assert response.data["token"] == token.token
|
||||||
decyphered_token = json.loads(decyphered_token.decode("utf-8"))
|
|
||||||
assert decyphered_token["token"] == token.token
|
|
||||||
|
|
||||||
|
|
||||||
def test_token_validate_validated(client):
|
def test_token_validate_validated(client):
|
||||||
|
|
Loading…
Reference in New Issue