blob: 1efe8f3eb73a98598fac297c08d2217ad64231ca [file] [log] [blame]
Akronca9bd982016-12-06 16:59:57 +01001from flask import flash
2from requests.auth import HTTPBasicAuth
3
4import APIFactory
5import config
6
7
8__author__ = 'hanl'
9
10
11
12# instance reference for authentication provider
13# must be set before usage!
14provider = None
15message_handler = None
16
17
18def load_provider(provider_name, handler):
19 '''
20 :param provider_name:
21 :return:
22 '''
23 global message_handler
24 message_handler = handler
25
26 split = provider_name.split('.')
27 # get last element, so you have the class name
28 _class = split[len(split) - 1]
29 provider_name = provider_name.replace("." + _class, "")
30 module = __import__(provider_name)
31 obj = getattr(module, _class, None)
32 instance = obj()
33 if instance is None:
34 raise KeyError("the provider class %s is undefined!" % str(_class))
35 print "successfully loaded provider '%s'" % str(_class)
36 global provider
37 provider = instance
38 return instance
39
40
41class User(object):
42 '''
43 the user object
44 '''
45
46 def __init__(self, username, password=None, email=None, firstName=None, lastName=None, address=None,
47 institution=None,
48 phone=None, country=None, id_token=None):
49 print "the username %s" % str(username)
50 if not username:
51 raise ValueError("the username must be set")
52 self.username = username
53 self.password = password
54 self.email = email
55 self.firstName = firstName
56 self.lastName = lastName
57 self.address = address
58 self.institution = institution
59 self.phone = phone
60 self.country = country
61 self.id_token = id_token
62
63 def is_authenticated(self):
64 return True
65
66 def has_details(self):
67 if self.firstName and self.lastName and self.email:
68 return True
69 return False
70
71 def is_anonymous(self):
72 return False
73
74 def get_id(self):
75 '''
76 :return: id reference to retrieve user object from middleware
77 '''
78 return unicode(self.username)
79
80 def is_active(self):
81 return True
82
83 def get_full_name(self):
84 if self.firstName and self.lastName:
85 return u' '.join([self.firstName, self.lastName])
86 return None
87
88
89class Provider(object):
90 global message_handler
91
92 def __init__(self):
93 self.handler = message_handler
94
95 def authenticate(self, username=None, password=None):
96 pass
97
98 def get_user(self, username=None, session=None, full=False):
99 if not username or not session:
100 return ValueError("username and session must be provided!")
101
102 def login(self, session=None, user=None):
103 pass
104
105
106 def logout(self, session=None):
107 pass
108
109 def is_authenticated(self):
110 pass
111
112
113class CustomProvider(Provider):
114 def authenticate(self, username=None, password=None):
115 pass
116
117 def get_user(self, username=None, session=None, full=False):
118 """
119 Returns the user model instance associated with the given request session.
120 If no user is retrieved an instance of `AnonymousUser` is returned.
121 """
122 # call super method
123 super(CustomProvider, self).get_user(username, session, full)
124 if full:
125 id_token = session['api_token']
126 code = APIFactory.decrypt_openid(token=id_token)
127 user = User(username=username, email=code['email'], firstName=code['firstName'],
128 lastName=code['lastName'], address=code['address'], institution=code['institution'],
129 phone=code['phone'])
130 return user
131 else:
132 return User(username=username)
133
134 def login(self, session=None, user=None):
135 '''
136 :param login_func: client specific login function
137 :param user: user object to register user for
138 :return: boolean if login successful
139 '''
140 super(CustomProvider, self).login(session, user)
141
142 response = APIFactory.get("auth/requestToken", auth=HTTPBasicAuth(username=user.username,
143 password=user.password))
144 user.password = None
145
146 if response is None:
147 return False
148 elif self.handler.isError(response):
149 self.handler.notifyNext(response.json(), flash)
150 return False
151 print "the response %i:%s" % (response.status_code, str(response.content))
152 session['api_token'] = response.content.replace('api_token ', '')
153 return True
154
155 def logout(self, session=None):
156 if 'api_token' not in session:
157 return False
158 session.pop('api_token', None)
159 return True
160
161 def is_authenticated(self):
162 '''
163 check that oauth id_token and access_token are not expired!
164 :return:
165 '''
166 pass
167
168
169class OAuth2Provider(Provider):
170 def authenticate(self, username=None, password=None):
171 pass
172
173 def get_user(self, username=None, session=None, full=False):
174 """
175 Returns the user model instance associated with the given request session.
176 If no user is retrieved an instance of `AnonymousUser` is returned.
177 """
178 # call super method
179 super(OAuth2Provider, self).get_user(username, session, full)
180
181 if full and "openid" in config.OPENID_CONNECT_SCOPES and "profile" in config.OPENID_CONNECT_SCOPES:
182 id_token = session['id_token']
183 code = APIFactory.decrypt_openid(secret=config.OAUTH2_CLIENT_SECRET, token=id_token)
184 user = User(username=username, email=code['email'], firstName=code['firstName'],
185 lastName=code['lastName'], address=code['address'], institution=code['institution'],
186 phone=code['phone'])
187 return user
188 elif full:
189 response = APIFactory.get("user/info", auth=APIFactory.Oauth2Auth(session['access_token']))
190 if response is None:
191 return None
192 elif self.handler.isError(response):
193 self.handler.notifyNext(response.json(), flash)
194 return None
195 else:
196 code = response.json()
197 user = User(username=username, email=code['email'], firstName=code['firstName'],
198 lastName=code['lastName'], address=code['address'], institution=code['institution'],
199 phone=code['phone'])
200 return user
201 else:
202 # for the most tasks its only about to have a user object, not the actual data!
203 return User(username=username)
204
205 def login(self, session=None, user=None):
206 '''
207 :param login_func: client specific login function
208 :param user: user object to register user for
209 :return: boolean if login successful
210 '''
211 super(OAuth2Provider, self).login(session, user)
212
213 params = {"username": user.username, "password": user.password,
214 "grant_type": "password", "client_id": config.OAUTH2_CLIENT_ID,
215 "client_secret": config.OAUTH2_CLIENT_SECRET, "scope": config.OPENID_CONNECT_SCOPES}
216 response = APIFactory.post(path='oauth2/token', params=params)
217 user.password = None
218
219 if response is None:
220 return False
221 elif self.handler.isError(response):
222 self.handler.notifyNext(response.json(), flash)
223 return False
224 print "the response %i:%s" % (response.status_code, str(response.content))
225
226 session['access_token'] = response.json()['access_token']
227 if "openid" in config.OPENID_CONNECT_SCOPES:
228 session['id_token'] = response.json()['id_token']
229 else:
230 session['id_token'] = "some random string" # todo ???
231 return True
232
233
234 def logout(self, session=None):
235 if 'access_token' not in session:
236 return False
237
238 session.pop('access_token', None)
239 if 'id_token' in session:
240 session.pop('id_token', None)
241 return True
242
243
244 def is_authenticated(self):
245 '''
246 check that oauth id_token and access_token are not expired!
247 add function to auth decorator
248 :return:
249 '''
250 pass