root / snf-astakos-app / astakos / oa2 / models.py @ e28a4841
History | View | Annotate | Download (4.1 kB)
1 |
import datetime |
---|---|
2 |
import urlparse |
3 |
|
4 |
from django.db import models |
5 |
from django.utils.translation import ugettext_lazy as _ |
6 |
from django.core.exceptions import ValidationError |
7 |
|
8 |
CLIENT_TYPES = ( |
9 |
('confidential', _('Confidential')), |
10 |
('public', _('Public')) |
11 |
) |
12 |
|
13 |
CONFIDENTIAL_TYPES = ['confidential']
|
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 |
|
22 |
|
23 |
class RedirectUrl(models.Model): |
24 |
client = models.ForeignKey('oa2.Client', on_delete=models.PROTECT)
|
25 |
is_default = models.BooleanField(default=True)
|
26 |
url = models.URLField(unique=True)
|
27 |
|
28 |
class Meta: |
29 |
ordering = ('is_default', )
|
30 |
unique_together = ('client', 'url',) |
31 |
|
32 |
|
33 |
class Client(models.Model): |
34 |
name = models.CharField(max_length=100)
|
35 |
identifier = models.CharField(max_length=255, unique=True) |
36 |
secret = models.CharField(max_length=255, null=True, default=None) |
37 |
url = models.CharField(max_length=255)
|
38 |
type = models.CharField(max_length=100, choices=CLIENT_TYPES,
|
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) |
46 |
|
47 |
def requires_auth(self): |
48 |
return self.type in CONFIDENTIAL_TYPES |
49 |
|
50 |
def get_default_redirect_uri(self): |
51 |
return self.redirecturl_set.get().url |
52 |
|
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
|
62 |
return self.redirecturl_set.filter(url=uri).count() > 0 |
63 |
|
64 |
def get_id(self): |
65 |
return self.identifier |
66 |
|
67 |
|
68 |
class AuthorizationCode(models.Model): |
69 |
user = models.ForeignKey('im.AstakosUser', on_delete=models.PROTECT)
|
70 |
code = models.TextField() |
71 |
redirect_uri = models.CharField(max_length=255)
|
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()) |
75 |
|
76 |
# not really useful
|
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)) |
93 |
|
94 |
|
95 |
class Token(models.Model): |
96 |
code = models.TextField() |
97 |
created_at = models.DateTimeField(default=datetime.datetime.now()) |
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)) |