Projet

Général

Profil

0002-add-redirects-uris-field-checking-14147.patch

Josué Kouka, 07 septembre 2017 15:42

Télécharger (8,91 ko)

Voir les différences:

Subject: [PATCH 2/2] add redirects uris field checking (#14147)

 fargo/oauth2/admin.py                          |  5 ++--
 fargo/oauth2/migrations/0001_initial.py        | 10 ++++++-
 fargo/oauth2/migrations/0002_oauth2tempfile.py | 23 ---------------
 fargo/oauth2/models.py                         | 28 ++++++++++++++----
 fargo/oauth2/views.py                          |  5 ++--
 tests/test_oauth2.py                           | 40 ++++++++++++++++++++------
 6 files changed, 70 insertions(+), 41 deletions(-)
 delete mode 100644 fargo/oauth2/migrations/0002_oauth2tempfile.py
fargo/oauth2/admin.py
20 20

  
21 21

  
22 22
class OAuth2ClientAdmin(admin.ModelAdmin):
23
    fields = ('client_name', 'client_id', 'client_secret')
24
    list_display = ['client_name', 'client_id', 'client_secret']
23
    fields = ('client_name', 'client_id', 'client_secret', 'redirect_uris')
24
    list_display = ['client_name', 'client_id', 'client_secret', 'redirect_uris']
25 25
    readonly_fields = ['client_id', 'client_secret']
26 26

  
27

  
27 28
admin.site.register(OAuth2Client, OAuth2ClientAdmin)
fargo/oauth2/migrations/0001_initial.py
29 29
                ('client_secret', models.CharField(default=fargo.oauth2.models.generate_uuid, max_length=255)),
30 30
                ('client_id', models.CharField(default=fargo.oauth2.models.generate_uuid, max_length=255)),
31 31
                ('client_name', models.CharField(max_length=255)),
32
                ('redirect_uri', models.TextField(default=b'')),
32
                ('redirect_uris', models.TextField(verbose_name='redirect URIs', validators=[fargo.oauth2.models.validate_https_url])),
33
            ],
34
        ),
35
        migrations.CreateModel(
36
            name='OAuth2TempFile',
37
            fields=[
38
                ('hash_key', models.CharField(max_length=128, serialize=False, primary_key=True)),
39
                ('filename', models.CharField(max_length=512)),
40
                ('document', models.ForeignKey(to='fargo.Document')),
33 41
            ],
34 42
        ),
35 43
    ]
fargo/oauth2/migrations/0002_oauth2tempfile.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4
from django.db import models, migrations
5

  
6

  
7
class Migration(migrations.Migration):
8

  
9
    dependencies = [
10
        ('fargo', '0013_document_mime_type'),
11
        ('oauth2', '0001_initial'),
12
    ]
13

  
14
    operations = [
15
        migrations.CreateModel(
16
            name='OAuth2TempFile',
17
            fields=[
18
                ('hash_key', models.CharField(max_length=128, serialize=False, primary_key=True)),
19
                ('filename', models.CharField(max_length=512)),
20
                ('document', models.ForeignKey(to='fargo.Document')),
21
            ],
22
        ),
23
    ]
fargo/oauth2/models.py
16 16

  
17 17
import uuid
18 18

  
19
from django.core.validators import URLValidator
20
from django.core.exceptions import ValidationError
19 21
from django.db import models
22
from django.utils.translation import ugettext_lazy as _
20 23

  
21 24
from fargo.fargo.models import Document, UserDocument
22 25

  
......
25 28
    return unicode(uuid.uuid4())
26 29

  
27 30

  
31
def validate_https_url(data):
32
    errors = []
33
    data = data.strip()
34
    if not data:
35
        return
36
    for url in data.split():
37
        try:
38
            URLValidator(schemes=['http', 'https'])(url)
39
        except ValidationError as e:
40
            errors.append(e)
41
    if errors:
42
        raise ValidationError(errors)
43

  
44

  
28 45
class OAuth2Authorize(models.Model):
29 46
    user_document = models.ForeignKey(UserDocument)
30 47
    access_token = models.CharField(max_length=255, default=generate_uuid)
......
39 56
    client_secret = models.CharField(max_length=255, default=generate_uuid)
40 57
    client_id = models.CharField(max_length=255, default=generate_uuid)
41 58
    client_name = models.CharField(max_length=255)
42
    redirect_uri = models.TextField(default='')
59
    redirect_uris = models.TextField(
60
        verbose_name=_('redirect URIs'),
61
        validators=[validate_https_url])
43 62

  
44 63
    def __repr__(self):
45 64
        return 'OAuth2Client name: %s with id: %s' % (self.client_name, self.client_id)
46 65

  
47 66
    def get_redirect_uris(self):
48
        return self.redirect_uri.split()
67
        return self.redirect_uris.split()
49 68

  
50
    def add_redirect_uri(self, redirect_uri):
51
        self.redirect_uri += ' %s' % redirect_uri
52
        self.save()
69
    def check_redirect_uri(self, redirect_uri):
70
        return redirect_uri in self.redirect_uris.strip().split()
53 71

  
54 72

  
55 73
class OAuth2TempFile(models.Model):
fargo/oauth2/views.py
54 54
            uri = self.error_redirect(redirect_uri, 'unsupported_response_type')
55 55
            return HttpResponseRedirect(uri)
56 56
        try:
57

  
58 57
            client = OAuth2Client.objects.get(client_id=client_id)
59
            client.add_redirect_uri(redirect_uri)
58
            if not client.check_redirect_uri(redirect_uri):
59
                uri = self.error_redirect(redirect_uri, 'invalid_redirect_uri')
60
                return HttpResponseRedirect(uri)
60 61
        except OAuth2Client.DoesNotExist:
61 62
            uri = self.error_redirect(redirect_uri, 'unauthorized_client')
62 63
            return HttpResponseRedirect(uri)
tests/test_oauth2.py
1 1
import pytest
2
import os
3
import base64
4 2
from urllib import quote
3
import urlparse
5 4

  
6 5
from django.core.files.base import ContentFile
7 6
from django.core.urlresolvers import reverse
......
14 13

  
15 14
pytestmark = pytest.mark.django_db
16 15

  
16

  
17 17
@pytest.fixture
18 18
def oauth2_client():
19
    return OAuth2Client.objects.create(client_name='test_oauth2')
19
    return OAuth2Client.objects.create(
20
        client_name='test_oauth2', client_id='client-id', client_secret='client-secret',
21
        redirect_uris='https://example.net/document https://doc.example.net/ https://example.com')
22

  
20 23

  
21 24
@pytest.fixture
22 25
def document():
......
25 28

  
26 29
    return Document.objects.get_by_file(content)
27 30

  
31

  
28 32
@pytest.fixture
29 33
def user_doc(document, john_doe):
30 34
    return UserDocument.objects.create(user=john_doe, document=document, filename='Baudelaire.txt')
31 35

  
36

  
37
def assert_error_redirect(url, error):
38
    assert urlparse.urlparse(url).query == 'error=%s' % error
39

  
40

  
32 41
def test_get_document_oauth2(app, john_doe, oauth2_client, user_doc):
33 42
    login(app, user=john_doe)
34 43
    url = reverse('oauth2-authorize')
35 44
    params = {
36
        'client_id': oauth2_client.client_id,
37 45
        'client_secret': oauth2_client.client_secret,
38
        'redirect_uri': 'https://example.com',
39 46
        'response_type': 'code',
40 47
        'state': 'achipeachope'
41 48
    }
42

  
43
    url += '?%s' % urlencode(params)
44
    resp = app.get(url)
49
    # test missing redirect_uri
50
    resp = app.get(url, params={}, status=400)
51
    assert resp.content == 'missing parameter redirect_uri'
52
    # test missing client id
53
    params['redirect_uri'] = 'https://toto.example.com'
54
    resp = app.get(url, params=params, status=302)
55
    assert_error_redirect(resp.url, 'invalid_request')
56
    # test invalid response type
57
    params['client_id'] = oauth2_client.client_id
58
    params['response_type'] = 'token'
59
    resp = app.get(url, params=params, status=302)
60
    assert_error_redirect(resp.url, 'unsupported_response_type')
61
    # test invalid redirect uri
62
    params['response_type'] = 'code'
63
    resp = app.get(url, params=params, status=302)
64
    assert_error_redirect(resp.url, 'invalid_redirect_uri')
65

  
66
    params['redirect_uri'] = 'https://example.com'
67
    resp = app.get(url, params=params)
45 68

  
46 69
    assert resp.status_code == 200
47 70
    assert len(resp.forms[0]['document'].options) == 2
......
123 146

  
124 147
    assert user_document.filename == 'Baudelaire.txt'
125 148

  
149

  
126 150
def test_confirm_put_document_file_exception(app, john_doe, user_doc):
127 151
    login(app, user=john_doe)
128 152
    oauth_tmp_file = OAuth2TempFile.objects.create(document=user_doc.document, filename=user_doc.filename)
129
-