auth.py
3.36 KB
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
#!/usr/bin/env python
# -*- Mode: Python; tab-width: 4; indent-tabs-mode: nil; coding: utf-8; -*-
# vim:set ft=python ts=4 sw=4 sts=4 autoindent:
'''
Authentication and authorization mechanisms.
Author: Pontus Stenetorp <pontus is s u-tokyo ac jp>
Illes Solt <solt tmit bme hu>
Version: 2011-04-21
'''
from hashlib import sha512
from os.path import dirname, join as path_join, isdir
try:
from os.path import relpath
except ImportError:
# relpath new to python 2.6; use our implementation if not found
from common import relpath
from common import ProtocolError
from config import USER_PASSWORD, DATA_DIR
from message import Messager
from session import get_session, invalidate_session
from projectconfig import ProjectConfiguration
# To raise if the authority to carry out an operation is lacking
class NotAuthorisedError(ProtocolError):
def __init__(self, attempted_action):
self.attempted_action = attempted_action
def __str__(self):
return 'Login required to perform "%s"' % self.attempted_action
def json(self, json_dic):
json_dic['exception'] = 'notAuthorised'
return json_dic
# File/data access denial
class AccessDeniedError(ProtocolError):
def __init__(self):
pass
def __str__(self):
return 'Access Denied'
def json(self, json_dic):
json_dic['exception'] = 'accessDenied'
# TODO: Client should be responsible here
Messager.error('Access Denied')
return json_dic
class InvalidAuthError(ProtocolError):
def __init__(self):
pass
def __str__(self):
return 'Incorrect login and/or password'
def json(self, json_dic):
json_dic['exception'] = 'invalidAuth'
return json_dic
def _is_authenticated(user, password):
# TODO: Replace with a database back-end
return (user in USER_PASSWORD and
password == USER_PASSWORD[user])
#password == _password_hash(USER_PASSWORD[user]))
def _password_hash(password):
return sha512(password).hexdigest()
def login(user, password):
if not _is_authenticated(user, password):
raise InvalidAuthError
get_session()['user'] = user
Messager.info('Hello!')
return {}
def logout():
try:
del get_session()['user']
except KeyError:
# Already deleted, let it slide
pass
# TODO: Really send this message?
Messager.info('Bye!')
return {}
def whoami():
json_dic = {}
try:
json_dic['user'] = get_session().get('user')
except KeyError:
# TODO: Really send this message?
Messager.error('Not logged in!', duration=3)
return json_dic
def allowed_to_read(real_path):
data_path = path_join('/', relpath(real_path, DATA_DIR))
# add trailing slash to directories, required to comply to robots.txt
if isdir(real_path):
data_path = '%s/' % ( data_path )
real_dir = dirname(real_path)
robotparser = ProjectConfiguration(real_dir).get_access_control()
if robotparser is None:
return True # default allow
try:
user = get_session().get('user')
except KeyError:
user = None
if user is None:
user = 'guest'
#display_message('Path: %s, dir: %s, user: %s, ' % (data_path, real_dir, user), type='error', duration=-1)
return robotparser.can_fetch(user, data_path)
# TODO: Unittesting