Revision e28a4841 snf-astakos-app/astakos/oa2/models.py
b/snf-astakos-app/astakos/oa2/models.py | ||
---|---|---|
1 |
import datetime |
|
2 |
import urlparse |
|
3 |
|
|
1 | 4 |
from django.db import models |
2 | 5 |
from django.utils.translation import ugettext_lazy as _ |
3 |
|
|
4 |
from astakos.oa2 import settings |
|
6 |
from django.core.exceptions import ValidationError |
|
5 | 7 |
|
6 | 8 |
CLIENT_TYPES = ( |
7 | 9 |
('confidential', _('Confidential')), |
... | ... | |
10 | 12 |
|
11 | 13 |
CONFIDENTIAL_TYPES = ['confidential'] |
12 | 14 |
|
15 |
TOKEN_TYPES = (('Basic', _('Basic')), |
|
16 |
('Bearer', _('Bearer'))) |
|
17 |
|
|
18 |
GRANT_TYPES = (('authorization_code', _('Authorization code')), |
|
19 |
('password', _('Password')), |
|
20 |
('client_credentials', _('Client Credentials'))) |
|
21 |
|
|
13 | 22 |
|
14 | 23 |
class RedirectUrl(models.Model): |
15 |
client = models.ForeignKey('oa2.Client') |
|
16 |
default = models.BooleanField(default=True) |
|
24 |
client = models.ForeignKey('oa2.Client', on_delete=models.PROTECT)
|
|
25 |
is_default = models.BooleanField(default=True)
|
|
17 | 26 |
url = models.URLField(unique=True) |
18 | 27 |
|
19 | 28 |
class Meta: |
20 |
ordering = ('default', ) |
|
29 |
ordering = ('is_default', ) |
|
30 |
unique_together = ('client', 'url',) |
|
21 | 31 |
|
22 | 32 |
|
23 | 33 |
class Client(models.Model): |
24 | 34 |
name = models.CharField(max_length=100) |
25 | 35 |
identifier = models.CharField(max_length=255, unique=True) |
26 |
secret = models.CharField(max_length=255) |
|
36 |
secret = models.CharField(max_length=255, null=True, default=None)
|
|
27 | 37 |
url = models.CharField(max_length=255) |
28 | 38 |
type = models.CharField(max_length=100, choices=CLIENT_TYPES, |
29 | 39 |
default='confidential') |
40 |
is_trusted = models.BooleanField(default=False) |
|
41 |
|
|
42 |
def save(self, **kwargs): |
|
43 |
if self.secret is None and self.type == 'confidential': |
|
44 |
raise ValidationError("Confidential clients require a secret") |
|
45 |
super(Client, self).save(**kwargs) |
|
30 | 46 |
|
31 | 47 |
def requires_auth(self): |
32 | 48 |
return self.type in CONFIDENTIAL_TYPES |
... | ... | |
35 | 51 |
return self.redirecturl_set.get().url |
36 | 52 |
|
37 | 53 |
def redirect_uri_is_valid(self, uri): |
54 |
# ignore user specific uri part |
|
55 |
parts = list(urlparse.urlsplit(uri)) |
|
56 |
path = parts[2] |
|
57 |
pieces = path.rsplit('/', 3) |
|
58 |
parts[2] = '/'.join(pieces[:-3]) if len(pieces) > 3 else path |
|
59 |
uri = urlparse.urlunsplit(parts) |
|
60 |
|
|
61 |
# TODO: handle trailing slashes |
|
38 | 62 |
return self.redirecturl_set.filter(url=uri).count() > 0 |
39 | 63 |
|
40 | 64 |
def get_id(self): |
... | ... | |
42 | 66 |
|
43 | 67 |
|
44 | 68 |
class AuthorizationCode(models.Model): |
69 |
user = models.ForeignKey('im.AstakosUser', on_delete=models.PROTECT) |
|
45 | 70 |
code = models.TextField() |
46 | 71 |
redirect_uri = models.CharField(max_length=255) |
47 |
client_id = models.CharField(max_length=255, db_index=True) |
|
48 |
scope = models.TextField() |
|
72 |
client = models.ForeignKey('oa2.Client', on_delete=models.PROTECT) |
|
73 |
scope = models.TextField(null=True, default=None) |
|
74 |
created_at = models.DateTimeField(default=datetime.datetime.now()) |
|
49 | 75 |
|
50 | 76 |
# not really useful |
51 |
state = models.TextField() |
|
77 |
state = models.TextField(null=True, default=None) |
|
78 |
|
|
79 |
def client_id_is_valid(self, client_id): |
|
80 |
return self.client_id == client_id |
|
81 |
|
|
82 |
def redirect_uri_is_valid(self, redirect_uri, client): |
|
83 |
return (self.redirect_uri == redirect_uri and |
|
84 |
client.redirect_uri_is_valid(redirect_uri)) |
|
85 |
|
|
86 |
def __repr__(self): |
|
87 |
return ("Authorization code: %s " |
|
88 |
"(user: %s, client: %s, redirect_uri: %s, scope: %s)" % ( |
|
89 |
self.code, |
|
90 |
self.user.log_display, |
|
91 |
self.client.get_id(), |
|
92 |
self.redirect_uri, self.scope)) |
|
52 | 93 |
|
53 | 94 |
|
54 | 95 |
class Token(models.Model): |
55 | 96 |
code = models.TextField() |
97 |
created_at = models.DateTimeField(default=datetime.datetime.now()) |
|
56 | 98 |
expires_at = models.DateTimeField() |
99 |
token_type = models.CharField(max_length=100, choices=TOKEN_TYPES, |
|
100 |
default='Bearer') |
|
101 |
grant_type = models.CharField(max_length=100, choices=GRANT_TYPES, |
|
102 |
default='authorization_code') |
|
103 |
|
|
104 |
# authorization fields |
|
105 |
user = models.ForeignKey('im.AstakosUser', on_delete=models.PROTECT) |
|
106 |
redirect_uri = models.CharField(max_length=255) |
|
107 |
client = models.ForeignKey('oa2.Client', on_delete=models.PROTECT) |
|
108 |
scope = models.TextField(null=True, default=None) |
|
109 |
|
|
110 |
# not really useful |
|
111 |
state = models.TextField(null=True, default=None) |
|
112 |
|
|
113 |
def __repr__(self): |
|
114 |
return ("Token: %s (token_type: %s, grant_type: %s, " |
|
115 |
"user: %s, client: %s, scope: %s)" % ( |
|
116 |
self.code, self.token_type, self.grant_type, |
|
117 |
self.user.log_display, self.client.get_id(), self.scope)) |
Also available in: Unified diff