Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / oa2 / models.py @ 72bb411a

History | View | Annotate | Download (6 kB)

1 64a45988 Sofia Papagiannaki
# Copyright 2013 GRNET S.A. All rights reserved.
2 64a45988 Sofia Papagiannaki
#
3 64a45988 Sofia Papagiannaki
# Redistribution and use in source and binary forms, with or
4 64a45988 Sofia Papagiannaki
# without modification, are permitted provided that the following
5 64a45988 Sofia Papagiannaki
# conditions are met:
6 64a45988 Sofia Papagiannaki
#
7 64a45988 Sofia Papagiannaki
#   1. Redistributions of source code must retain the above
8 64a45988 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
9 64a45988 Sofia Papagiannaki
#      disclaimer.
10 64a45988 Sofia Papagiannaki
#
11 64a45988 Sofia Papagiannaki
#   2. Redistributions in binary form must reproduce the above
12 64a45988 Sofia Papagiannaki
#      copyright notice, this list of conditions and the following
13 64a45988 Sofia Papagiannaki
#      disclaimer in the documentation and/or other materials
14 64a45988 Sofia Papagiannaki
#      provided with the distribution.
15 64a45988 Sofia Papagiannaki
#
16 64a45988 Sofia Papagiannaki
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 64a45988 Sofia Papagiannaki
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 64a45988 Sofia Papagiannaki
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 64a45988 Sofia Papagiannaki
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 64a45988 Sofia Papagiannaki
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 64a45988 Sofia Papagiannaki
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 64a45988 Sofia Papagiannaki
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 64a45988 Sofia Papagiannaki
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 64a45988 Sofia Papagiannaki
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 64a45988 Sofia Papagiannaki
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 64a45988 Sofia Papagiannaki
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 64a45988 Sofia Papagiannaki
# POSSIBILITY OF SUCH DAMAGE.
28 64a45988 Sofia Papagiannaki
#
29 64a45988 Sofia Papagiannaki
# The views and conclusions contained in the software and
30 64a45988 Sofia Papagiannaki
# documentation are those of the authors and should not be
31 64a45988 Sofia Papagiannaki
# interpreted as representing official policies, either expressed
32 64a45988 Sofia Papagiannaki
# or implied, of GRNET S.A.
33 64a45988 Sofia Papagiannaki
34 e28a4841 Sofia Papagiannaki
import datetime
35 e28a4841 Sofia Papagiannaki
import urlparse
36 e28a4841 Sofia Papagiannaki
37 3fc7fd80 Kostas Papadimitriou
from django.db import models
38 3fc7fd80 Kostas Papadimitriou
from django.utils.translation import ugettext_lazy as _
39 e28a4841 Sofia Papagiannaki
from django.core.exceptions import ValidationError
40 3fc7fd80 Kostas Papadimitriou
41 3fc7fd80 Kostas Papadimitriou
CLIENT_TYPES = (
42 3fc7fd80 Kostas Papadimitriou
    ('confidential', _('Confidential')),
43 3fc7fd80 Kostas Papadimitriou
    ('public', _('Public'))
44 3fc7fd80 Kostas Papadimitriou
)
45 3fc7fd80 Kostas Papadimitriou
46 3fc7fd80 Kostas Papadimitriou
CONFIDENTIAL_TYPES = ['confidential']
47 3fc7fd80 Kostas Papadimitriou
48 e28a4841 Sofia Papagiannaki
TOKEN_TYPES = (('Basic', _('Basic')),
49 e28a4841 Sofia Papagiannaki
               ('Bearer', _('Bearer')))
50 e28a4841 Sofia Papagiannaki
51 e28a4841 Sofia Papagiannaki
GRANT_TYPES = (('authorization_code', _('Authorization code')),
52 e28a4841 Sofia Papagiannaki
               ('password', _('Password')),
53 e28a4841 Sofia Papagiannaki
               ('client_credentials', _('Client Credentials')))
54 e28a4841 Sofia Papagiannaki
55 d3bb95d3 Sofia Papagiannaki
ACCESS_TOKEN_TYPES = (('online', _('Online token')),
56 d3bb95d3 Sofia Papagiannaki
                      ('offline', _('Offline token')))
57 d3bb95d3 Sofia Papagiannaki
58 3fc7fd80 Kostas Papadimitriou
59 3fc7fd80 Kostas Papadimitriou
class RedirectUrl(models.Model):
60 e28a4841 Sofia Papagiannaki
    client = models.ForeignKey('oa2.Client', on_delete=models.PROTECT)
61 e28a4841 Sofia Papagiannaki
    is_default = models.BooleanField(default=True)
62 3fc7fd80 Kostas Papadimitriou
    url = models.URLField(unique=True)
63 3fc7fd80 Kostas Papadimitriou
64 3fc7fd80 Kostas Papadimitriou
    class Meta:
65 e28a4841 Sofia Papagiannaki
        ordering = ('is_default', )
66 e28a4841 Sofia Papagiannaki
        unique_together = ('client', 'url',)
67 3fc7fd80 Kostas Papadimitriou
68 3fc7fd80 Kostas Papadimitriou
69 3fc7fd80 Kostas Papadimitriou
class Client(models.Model):
70 3fc7fd80 Kostas Papadimitriou
    name = models.CharField(max_length=100)
71 3fc7fd80 Kostas Papadimitriou
    identifier = models.CharField(max_length=255, unique=True)
72 e28a4841 Sofia Papagiannaki
    secret = models.CharField(max_length=255, null=True, default=None)
73 3fc7fd80 Kostas Papadimitriou
    url = models.CharField(max_length=255)
74 3fc7fd80 Kostas Papadimitriou
    type = models.CharField(max_length=100, choices=CLIENT_TYPES,
75 3fc7fd80 Kostas Papadimitriou
                            default='confidential')
76 e28a4841 Sofia Papagiannaki
    is_trusted = models.BooleanField(default=False)
77 e28a4841 Sofia Papagiannaki
78 e28a4841 Sofia Papagiannaki
    def save(self, **kwargs):
79 e28a4841 Sofia Papagiannaki
        if self.secret is None and self.type == 'confidential':
80 e28a4841 Sofia Papagiannaki
            raise ValidationError("Confidential clients require a secret")
81 e28a4841 Sofia Papagiannaki
        super(Client, self).save(**kwargs)
82 3fc7fd80 Kostas Papadimitriou
83 3fc7fd80 Kostas Papadimitriou
    def requires_auth(self):
84 3fc7fd80 Kostas Papadimitriou
        return self.type in CONFIDENTIAL_TYPES
85 3fc7fd80 Kostas Papadimitriou
86 3fc7fd80 Kostas Papadimitriou
    def get_default_redirect_uri(self):
87 3fc7fd80 Kostas Papadimitriou
        return self.redirecturl_set.get().url
88 3fc7fd80 Kostas Papadimitriou
89 3fc7fd80 Kostas Papadimitriou
    def redirect_uri_is_valid(self, uri):
90 e28a4841 Sofia Papagiannaki
        # ignore user specific uri part
91 e28a4841 Sofia Papagiannaki
        parts = list(urlparse.urlsplit(uri))
92 e28a4841 Sofia Papagiannaki
        path = parts[2]
93 e28a4841 Sofia Papagiannaki
        pieces = path.rsplit('/', 3)
94 e28a4841 Sofia Papagiannaki
        parts[2] = '/'.join(pieces[:-3]) if len(pieces) > 3 else path
95 e28a4841 Sofia Papagiannaki
        uri = urlparse.urlunsplit(parts)
96 e28a4841 Sofia Papagiannaki
97 e28a4841 Sofia Papagiannaki
        # TODO: handle trailing slashes
98 3fc7fd80 Kostas Papadimitriou
        return self.redirecturl_set.filter(url=uri).count() > 0
99 3fc7fd80 Kostas Papadimitriou
100 3fc7fd80 Kostas Papadimitriou
    def get_id(self):
101 3fc7fd80 Kostas Papadimitriou
        return self.identifier
102 3fc7fd80 Kostas Papadimitriou
103 3fc7fd80 Kostas Papadimitriou
104 3fc7fd80 Kostas Papadimitriou
class AuthorizationCode(models.Model):
105 e28a4841 Sofia Papagiannaki
    user = models.ForeignKey('im.AstakosUser', on_delete=models.PROTECT)
106 3fc7fd80 Kostas Papadimitriou
    code = models.TextField()
107 252eb705 Sofia Papagiannaki
    redirect_uri = models.CharField(max_length=255, null=True, default=None)
108 e28a4841 Sofia Papagiannaki
    client = models.ForeignKey('oa2.Client', on_delete=models.PROTECT)
109 e28a4841 Sofia Papagiannaki
    scope = models.TextField(null=True, default=None)
110 e28a4841 Sofia Papagiannaki
    created_at = models.DateTimeField(default=datetime.datetime.now())
111 3fc7fd80 Kostas Papadimitriou
112 d3bb95d3 Sofia Papagiannaki
    access_token = models.CharField(max_length=100, choices=ACCESS_TOKEN_TYPES,
113 d3bb95d3 Sofia Papagiannaki
                                    default='online')
114 d3bb95d3 Sofia Papagiannaki
115 3fc7fd80 Kostas Papadimitriou
    # not really useful
116 e28a4841 Sofia Papagiannaki
    state = models.TextField(null=True, default=None)
117 e28a4841 Sofia Papagiannaki
118 e28a4841 Sofia Papagiannaki
    def client_id_is_valid(self, client_id):
119 e28a4841 Sofia Papagiannaki
        return self.client_id == client_id
120 e28a4841 Sofia Papagiannaki
121 e28a4841 Sofia Papagiannaki
    def redirect_uri_is_valid(self, redirect_uri, client):
122 e28a4841 Sofia Papagiannaki
        return (self.redirect_uri == redirect_uri and
123 e28a4841 Sofia Papagiannaki
                client.redirect_uri_is_valid(redirect_uri))
124 e28a4841 Sofia Papagiannaki
125 e28a4841 Sofia Papagiannaki
    def __repr__(self):
126 e28a4841 Sofia Papagiannaki
        return ("Authorization code: %s "
127 e28a4841 Sofia Papagiannaki
                "(user: %s, client: %s, redirect_uri: %s, scope: %s)" % (
128 e28a4841 Sofia Papagiannaki
                    self.code,
129 e28a4841 Sofia Papagiannaki
                    self.user.log_display,
130 e28a4841 Sofia Papagiannaki
                    self.client.get_id(),
131 e28a4841 Sofia Papagiannaki
                    self.redirect_uri, self.scope))
132 3fc7fd80 Kostas Papadimitriou
133 3fc7fd80 Kostas Papadimitriou
134 3fc7fd80 Kostas Papadimitriou
class Token(models.Model):
135 3fc7fd80 Kostas Papadimitriou
    code = models.TextField()
136 e28a4841 Sofia Papagiannaki
    created_at = models.DateTimeField(default=datetime.datetime.now())
137 3fc7fd80 Kostas Papadimitriou
    expires_at = models.DateTimeField()
138 e28a4841 Sofia Papagiannaki
    token_type = models.CharField(max_length=100, choices=TOKEN_TYPES,
139 e28a4841 Sofia Papagiannaki
                                  default='Bearer')
140 e28a4841 Sofia Papagiannaki
    grant_type = models.CharField(max_length=100, choices=GRANT_TYPES,
141 e28a4841 Sofia Papagiannaki
                                  default='authorization_code')
142 e28a4841 Sofia Papagiannaki
143 e28a4841 Sofia Papagiannaki
    # authorization fields
144 e28a4841 Sofia Papagiannaki
    user = models.ForeignKey('im.AstakosUser', on_delete=models.PROTECT)
145 e28a4841 Sofia Papagiannaki
    redirect_uri = models.CharField(max_length=255)
146 e28a4841 Sofia Papagiannaki
    client = models.ForeignKey('oa2.Client', on_delete=models.PROTECT)
147 e28a4841 Sofia Papagiannaki
    scope = models.TextField(null=True, default=None)
148 d3bb95d3 Sofia Papagiannaki
    access_token = models.CharField(max_length=100, choices=ACCESS_TOKEN_TYPES,
149 d3bb95d3 Sofia Papagiannaki
                                    default='online')
150 e28a4841 Sofia Papagiannaki
151 e28a4841 Sofia Papagiannaki
    # not really useful
152 e28a4841 Sofia Papagiannaki
    state = models.TextField(null=True, default=None)
153 e28a4841 Sofia Papagiannaki
154 e28a4841 Sofia Papagiannaki
    def __repr__(self):
155 e28a4841 Sofia Papagiannaki
        return ("Token: %s (token_type: %s, grant_type: %s, "
156 e28a4841 Sofia Papagiannaki
                "user: %s, client: %s, scope: %s)" % (
157 e28a4841 Sofia Papagiannaki
                    self.code, self.token_type, self.grant_type,
158 e28a4841 Sofia Papagiannaki
                    self.user.log_display, self.client.get_id(), self.scope))