summaryrefslogtreecommitdiff
path: root/django/models/auth.py
blob: 96e6af9667e34e3e446e6f602769b72e16b27c93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
from django.core import meta, validators
from django.models import core

class Permission(meta.Model):
    fields = (
        meta.CharField('name', 'name', maxlength=50),
        meta.ForeignKey(core.Package, name='package'),
        meta.CharField('codename', 'code name', maxlength=100),
    )
    unique_together = (('package', 'codename'),)
    ordering = (('package', 'ASC'), ('codename', 'ASC'))

    def __repr__(self):
        return "%s | %s" % (self.package, self.name)

class Group(meta.Model):
    fields = (
        meta.CharField('name', 'name', maxlength=80, unique=True),
        meta.ManyToManyField(Permission, blank=True, filter_interface=meta.HORIZONTAL),
    )
    ordering = (('name', 'ASC'),)
    admin = meta.Admin(
        fields = (
            (None, {'fields': ('name', 'permissions')}),
        ),
        search_fields = ('name',),
    )

    def __repr__(self):
        return self.name

class User(meta.Model):
    fields = (
        meta.CharField('username', 'username', maxlength=30, unique=True,
            validator_list=[validators.isAlphaNumeric]),
        meta.CharField('first_name', 'first name', maxlength=30, blank=True),
        meta.CharField('last_name', 'last name', maxlength=30, blank=True),
        meta.EmailField('email', 'e-mail address', blank=True),
        meta.CharField('password_md5', 'password', maxlength=32),
        meta.BooleanField('is_staff', 'staff status',
            help_text="Designates whether the user can log into this admin site."),
        meta.BooleanField('is_active', 'active', default=True),
        meta.BooleanField('is_superuser', 'superuser status'),
        meta.DateTimeField('last_login', 'last login', default=meta.LazyDate()),
        meta.DateTimeField('date_joined', 'date joined', default=meta.LazyDate()),
        meta.ManyToManyField(Group, blank=True,
            help_text="In addition to the permissions manually assigned, this user will also get all permissions granted to each group he/she is in."),
        meta.ManyToManyField(Permission, name='user_permissions', blank=True, filter_interface=meta.HORIZONTAL),
    )
    ordering = (('username', 'ASC'),)
    exceptions = ('SiteProfileNotAvailable',)
    admin = meta.Admin(
        fields = (
            (None, {'fields': ('username', 'password_md5')}),
            ('Personal info', {'fields': ('first_name', 'last_name', 'email')}),
            ('Permissions', {'fields': ('is_staff', 'is_active', 'is_superuser', 'user_permissions')}),
            ('Important dates', {'fields': ('last_login', 'date_joined')}),
            ('Groups', {'fields': ('groups',)}),
        ),
        list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff'),
        list_filter = ('is_staff', 'is_superuser'),
        search_fields = ('username', 'first_name', 'last_name', 'email'),
    )

    def __repr__(self):
        return self.username

    def get_absolute_url(self):
        return "/users/%s/" % self.username

    def is_anonymous(self):
        return False

    def get_full_name(self):
        full_name = '%s %s' % (self.first_name, self.last_name)
        return full_name.strip()

    def set_password(self, raw_password):
        import md5
        self.password_md5 = md5.new(raw_password).hexdigest()

    def check_password(self, raw_password):
        "Returns a boolean of whether the raw_password was correct."
        import md5
        return self.password_md5 == md5.new(raw_password).hexdigest()

    def get_group_permissions(self):
        "Returns a list of permission strings that this user has through his/her groups."
        if not hasattr(self, '_group_perm_cache'):
            import sets
            cursor = db.cursor()
            cursor.execute("""
                SELECT p.package, p.codename
                FROM auth_permissions p, auth_groups_permissions gp, auth_users_groups ug
                WHERE p.id = gp.permission_id
                    AND gp.group_id = ug.group_id
                    AND ug.user_id = %s""", [self.id])
            self._group_perm_cache = sets.Set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()])
        return self._group_perm_cache

    def get_all_permissions(self):
        if not hasattr(self, '_perm_cache'):
            import sets
            self._perm_cache = sets.Set(["%s.%s" % (p.package, p.codename) for p in self.get_user_permissions()])
            self._perm_cache.update(self.get_group_permissions())
        return self._perm_cache

    def has_perm(self, perm):
        "Returns True if the user has the specified permission."
        if not self.is_active:
            return False
        if self.is_superuser:
            return True
        return perm in self.get_all_permissions()

    def has_perms(self, perm_list):
        "Returns True if the user has each of the specified permissions."
        for perm in perm_list:
            if not self.has_perm(perm):
                return False
        return True

    def has_module_perms(self, package_name):
        "Returns True if the user has any permissions in the given package."
        if self.is_superuser:
            return True
        return bool(len([p for p in self.get_all_permissions() if p[:p.index('.')] == package_name]))

    def get_and_delete_messages(self):
        messages = []
        for m in self.get_message_list():
            messages.append(m.message)
            m.delete()
        return messages

    def email_user(self, subject, message, from_email=None):
        "Sends an e-mail to this User."
        from django.core.mail import send_mail
        send_mail(subject, message, from_email, [self.email])

    def get_profile(self):
        """
        Returns site-specific profile for this user. Raises
        SiteProfileNotAvailable if this site does not allow profiles.
        """
        if not hasattr(self, '_profile_cache'):
            from django.conf.settings import AUTH_PROFILE_MODULE
            if not AUTH_PROFILE_MODULE:
                raise SiteProfileNotAvailable
            try:
                app, mod = AUTH_PROFILE_MODULE.split('.')
                module = __import__('ellington.%s.apps.%s' % (app, mod), [], [], [''])
                self._profile_cache = module.get_object(user_id=self.id)
            except ImportError:
                try:
                    module = __import__('django.models.%s' % AUTH_PROFILE_MODULE, [], [], [''])
                    self._profile_cache = module.get_object(user_id__exact=self.id)
                except ImportError:
                    raise SiteProfileNotAvailable
        return self._profile_cache

    def _module_create_user(username, email, password):
        "Creates and saves a User with the given username, e-mail and password."
        import md5
        password_md5 = md5.new(password).hexdigest()
        now = datetime.datetime.now()
        user = User(None, username, '', '', email.strip().lower(), password_md5, False, True, False, now, now)
        user.save()
        return user

    def _module_make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'):
        "Generates a random password with the given length and given allowed_chars"
        # Note that default value of allowed_chars does not have "I" or letters
        # that look like it -- just to avoid confusion.
        from whrandom import choice
        return ''.join([choice(allowed_chars) for i in range(length)])

class Session(meta.Model):
    fields = (
        meta.ForeignKey(User),
        meta.CharField('session_md5', 'session MD5 hash', maxlength=32),
        meta.DateTimeField('start_time', 'start time', auto_now=True),
    )
    module_constants = {
        # Used for providing pseudo-entropy in creating random session strings.
        'SESSION_SALT': 'ijw2f3_MUPPET_avo#*5)(*',
        # Secret used in cookie to guard against cookie tampering.
        'TAMPER_SECRET': 'lj908_PIGGY_j0vajeawej-092j3f',
        'TEST_COOKIE_NAME': 'testcookie',
        'TEST_COOKIE_VALUE': 'worked',
    }

    def __repr__(self):
        return "session started at %s" % self.start_time

    def get_cookie(self):
        "Returns a tuple of the cookie name and value for this session."
        import md5
        from django.conf.settings import AUTH_SESSION_COOKIE
        return AUTH_SESSION_COOKIE, self.session_md5 + md5.new(self.session_md5 + TAMPER_SECRET).hexdigest()

    def _module_create_session(user_id):
        "Registers a session and returns the session_md5."
        import md5, random, sys
        # The random module is seeded when this Apache child is created.
        # Use person_id and SESSION_SALT as added salt.
        session_md5 = md5.new(str(random.randint(user_id, sys.maxint - 1)) + SESSION_SALT).hexdigest()
        s = Session(None, user_id, session_md5, None)
        s.save()
        return s

    def _module_get_session_from_cookie(session_cookie_string):
        import md5
        if not session_cookie_string:
            raise SessionDoesNotExist
        session_md5, tamper_check = session_cookie_string[:32], session_cookie_string[32:]
        if md5.new(session_md5 + TAMPER_SECRET).hexdigest() != tamper_check:
            raise SuspiciousOperation, "User may have tampered with session cookie."
        return get_object(session_md5__exact=session_md5, select_related=True)

    def _module_destroy_all_sessions(user_id):
        "Destroys all sessions for a user, logging out all computers."
        for session in get_list(user_id__exact=user_id):
            session.delete()

    def _module_start_web_session(user_id, request, response):
        "Sets the necessary cookie in the given HttpResponse object, also updates last login time for user."
        from django.models.auth import users
        from django.conf.settings import REGISTRATION_COOKIE_DOMAIN
        user = users.get_object(id__exact=user_id)
        user.last_login = datetime.datetime.now()
        user.save()
        session = create_session(user_id)
        key, value = session.get_cookie()
        cookie_domain = REGISTRATION_COOKIE_DOMAIN or request.META['SERVER_NAME']
        response.set_cookie(key, value, domain=cookie_domain)

class Message(meta.Model):
    fields = (
        meta.AutoField('id', 'ID', primary_key=True),
        meta.ForeignKey(User),
        meta.TextField('message', 'message'),
    )

    def __repr__(self):
        return self.message

class LogEntry(meta.Model):
    module_name = 'log'
    verbose_name_plural = 'log entries'
    db_table = 'auth_admin_log'
    fields = (
        meta.DateTimeField('action_time', 'action time', auto_now=True),
        meta.ForeignKey(User),
        meta.ForeignKey(core.ContentType, name='content_type_id', rel_name='content_type', blank=True, null=True),
        meta.IntegerField('object_id', 'object ID', blank=True, null=True),
        meta.CharField('object_repr', 'object representation', maxlength=200),
        meta.PositiveSmallIntegerField('action_flag', 'action flag'),
        meta.TextField('change_message', 'change message', blank=True),
    )
    ordering = (('action_time', 'DESC'),)
    module_constants = {
        'ADDITION': 1,
        'CHANGE': 2,
        'DELETION': 3,
    }

    def __repr__(self):
        return str(self.action_time)

    def is_addition(self):
        return self.action_flag == ADDITION

    def is_change(self):
        return self.action_flag == CHANGE

    def is_deletion(self):
        return self.action_flag == DELETION

    def get_edited_object(self):
        "Returns the edited object represented by this log entry"
        return self.get_content_type().get_object_for_this_type(id__exact=self.object_id)

    def get_admin_url(self):
        "Returns the admin URL to edit the object represented by this log entry"
        return "/%s/%s/%s/" % (self.get_content_type().package, self.get_content_type().python_module_name, self.object_id)

    def _module_log_action(user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
        e = LogEntry(None, None, user_id, content_type_id, object_id, object_repr[:200], action_flag, change_message)
        e.save()