Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / oa2 / models.py @ 698016f7

History | View | Annotate | Download (5.9 kB)

1
# Copyright 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
import datetime
35

    
36
from django.db import models
37
from django.utils.translation import ugettext_lazy as _
38
from django.core.exceptions import ValidationError
39

    
40
CLIENT_TYPES = (
41
    ('confidential', _('Confidential')),
42
    ('public', _('Public'))
43
)
44

    
45
CONFIDENTIAL_TYPES = ['confidential']
46

    
47
TOKEN_TYPES = (('Basic', _('Basic')),
48
               ('Bearer', _('Bearer')))
49

    
50
GRANT_TYPES = (('authorization_code', _('Authorization code')),
51
               ('password', _('Password')),
52
               ('client_credentials', _('Client Credentials')))
53

    
54
ACCESS_TOKEN_TYPES = (('online', _('Online token')),
55
                      ('offline', _('Offline token')))
56

    
57

    
58
class RedirectUrl(models.Model):
59
    client = models.ForeignKey('oa2.Client', on_delete=models.PROTECT)
60
    is_default = models.BooleanField(default=True)
61
    url = models.URLField(unique=True)
62

    
63
    class Meta:
64
        ordering = ('is_default', )
65
        unique_together = ('client', 'url',)
66

    
67

    
68
class Client(models.Model):
69
    name = models.CharField(max_length=100)
70
    identifier = models.CharField(max_length=255, unique=True)
71
    secret = models.CharField(max_length=255, null=True, default=None)
72
    url = models.CharField(max_length=255)
73
    type = models.CharField(max_length=100, choices=CLIENT_TYPES,
74
                            default='confidential')
75
    is_trusted = models.BooleanField(default=False)
76

    
77
    def save(self, **kwargs):
78
        if self.secret is None and self.type == 'confidential':
79
            raise ValidationError("Confidential clients require a secret")
80
        super(Client, self).save(**kwargs)
81

    
82
    def requires_auth(self):
83
        return self.type in CONFIDENTIAL_TYPES
84

    
85
    def get_default_redirect_uri(self):
86
        return self.redirecturl_set.get().url
87

    
88
    def redirect_uri_is_valid(self, uri):
89
        for redirect_uri in self.redirecturl_set.values_list('url', flat=True):
90
            if uri == redirect_uri:
91
                return True
92
            elif uri.startswith(redirect_uri.rstrip('/') + '/'):
93
                return True
94
        return False
95

    
96
    def get_id(self):
97
        return self.identifier
98

    
99

    
100
class AuthorizationCode(models.Model):
101
    user = models.ForeignKey('im.AstakosUser', on_delete=models.PROTECT)
102
    code = models.TextField()
103
    redirect_uri = models.CharField(max_length=255, null=True, default=None)
104
    client = models.ForeignKey('oa2.Client', on_delete=models.PROTECT)
105
    scope = models.TextField(null=True, default=None)
106
    created_at = models.DateTimeField(default=datetime.datetime.now())
107

    
108
    access_token = models.CharField(max_length=100, choices=ACCESS_TOKEN_TYPES,
109
                                    default='online')
110

    
111
    # not really useful
112
    state = models.TextField(null=True, default=None)
113

    
114
    def client_id_is_valid(self, client_id):
115
        return self.client_id == client_id
116

    
117
    def redirect_uri_is_valid(self, redirect_uri, client):
118
        return (self.redirect_uri == redirect_uri and
119
                client.redirect_uri_is_valid(redirect_uri))
120

    
121
    def __repr__(self):
122
        return ("Authorization code: %s "
123
                "(user: %r, client: %r, redirect_uri: %r, scope: %r)" % (
124
                    self.code,
125
                    self.user.log_display,
126
                    self.client.get_id(),
127
                    self.redirect_uri, self.scope))
128

    
129

    
130
class Token(models.Model):
131
    code = models.TextField()
132
    created_at = models.DateTimeField(default=datetime.datetime.now())
133
    expires_at = models.DateTimeField()
134
    token_type = models.CharField(max_length=100, choices=TOKEN_TYPES,
135
                                  default='Bearer')
136
    grant_type = models.CharField(max_length=100, choices=GRANT_TYPES,
137
                                  default='authorization_code')
138

    
139
    # authorization fields
140
    user = models.ForeignKey('im.AstakosUser', on_delete=models.PROTECT)
141
    redirect_uri = models.CharField(max_length=255)
142
    client = models.ForeignKey('oa2.Client', on_delete=models.PROTECT)
143
    scope = models.TextField(null=True, default=None)
144
    access_token = models.CharField(max_length=100, choices=ACCESS_TOKEN_TYPES,
145
                                    default='online')
146

    
147
    # not really useful
148
    state = models.TextField(null=True, default=None)
149

    
150
    def __repr__(self):
151
        return ("Token: %r (token_type: %r, grant_type: %r, "
152
                "user: %r, client: %r, scope: %r)" % (
153
                    self.code, self.token_type, self.grant_type,
154
                    self.user.log_display, self.client.get_id(), self.scope))