You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

382 regels
11 KiB

  1. # Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
  2. #
  3. # MIT License (MIT)
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a
  6. # copy of this software and associated documentation files (the "Software"),
  7. # to deal in the Software without restriction, including without limitation
  8. # the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. # and/or sell copies of the Software, and to permit persons to whom the
  10. # Software is furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17. # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  20. # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #
  22. from __future__ import unicode_literals
  23. import webnotes
  24. import webnotes.db
  25. import webnotes.utils
  26. import webnotes.profile
  27. import conf
  28. # =================================================================================
  29. # HTTPRequest
  30. # =================================================================================
  31. class HTTPRequest:
  32. def __init__(self):
  33. # Get Environment variables
  34. self.domain = webnotes.get_env_vars('HTTP_HOST')
  35. if self.domain and self.domain.startswith('www.'):
  36. self.domain = self.domain[4:]
  37. webnotes.remote_ip = webnotes.get_env_vars('REMOTE_ADDR')
  38. # load cookies
  39. webnotes.cookie_manager = CookieManager()
  40. # set db
  41. self.set_db()
  42. # -----------------------------
  43. # start transaction
  44. webnotes.conn.begin()
  45. # login
  46. webnotes.login_manager = LoginManager()
  47. # start session
  48. webnotes.session_obj = Session()
  49. webnotes.session = webnotes.session_obj.data
  50. # check status
  51. if webnotes.conn.get_global("__session_status")=='stop':
  52. webnotes.msgprint(webnotes.conn.get_global("__session_status_message"))
  53. raise webnotes.SessionStopped('Session Stopped')
  54. # load profile
  55. self.setup_profile()
  56. # run login triggers
  57. if webnotes.form_dict.get('cmd')=='login':
  58. webnotes.login_manager.run_trigger('on_login_post_session')
  59. # write out cookies
  60. webnotes.cookie_manager.set_cookies()
  61. webnotes.conn.commit()
  62. # end transaction
  63. # -----------------------------
  64. # setup profile
  65. # -------------
  66. def setup_profile(self):
  67. webnotes.user = webnotes.profile.Profile()
  68. # load the profile data
  69. if not webnotes.session['data'].get('profile'):
  70. webnotes.session['data']['profile'] = webnotes.user.load_profile()
  71. webnotes.user.load_from_session(webnotes.session['data']['profile'])
  72. # set database login
  73. # ------------------
  74. def get_db_name(self):
  75. """get database name from conf"""
  76. return conf.db_name
  77. def set_db(self, ac_name = None):
  78. """connect to db, from ac_name or db_name"""
  79. webnotes.conn = webnotes.db.Database(user = self.get_db_name(), \
  80. password = getattr(conf,'db_password', ''))
  81. # =================================================================================
  82. # Login Manager
  83. # =================================================================================
  84. class LoginManager:
  85. def __init__(self):
  86. if webnotes.form_dict.get('cmd')=='login':
  87. # clear cache
  88. from webnotes.sessions import clear_cache
  89. clear_cache(webnotes.form_dict.get('usr'))
  90. self.authenticate()
  91. self.post_login()
  92. webnotes.response['message'] = 'Logged In'
  93. # run triggers, write cookies
  94. # ---------------------------
  95. def post_login(self):
  96. self.run_trigger()
  97. self.validate_ip_address()
  98. self.validate_hour()
  99. # check password
  100. # --------------
  101. def authenticate(self, user=None, pwd=None):
  102. if not (user and pwd):
  103. user, pwd = webnotes.form_dict.get('usr'), webnotes.form_dict.get('pwd')
  104. if not (user and pwd):
  105. self.fail('Incomplete login details')
  106. self.check_if_enabled(user)
  107. self.user = self.check_password(user, pwd)
  108. def check_if_enabled(self, user):
  109. """raise exception if user not enabled"""
  110. from webnotes.utils import cint
  111. if user=='Administrator': return
  112. if not cint(webnotes.conn.get_value('Profile', user, 'enabled')):
  113. self.fail('User disabled or missing')
  114. def check_password(self, user, pwd):
  115. """check password"""
  116. user = webnotes.conn.sql("""select `user` from __Auth where `user`=%s
  117. and `password`=password(%s)""", (user, pwd))
  118. if not user:
  119. self.fail('Incorrect password')
  120. else:
  121. return user[0][0] # in correct case
  122. def fail(self, message):
  123. webnotes.response['message'] = message
  124. raise webnotes.AuthenticationError
  125. def run_trigger(self, method='on_login'):
  126. try:
  127. from startup import event_handlers
  128. if hasattr(event_handlers, method):
  129. getattr(event_handlers, method)(self)
  130. return
  131. except ImportError, e:
  132. pass
  133. def validate_ip_address(self):
  134. """check if IP Address is valid"""
  135. ip_list = webnotes.conn.get_value('Profile', self.user, 'restrict_ip', ignore=True)
  136. if not ip_list:
  137. return
  138. ip_list = ip_list.replace(",", "\n").split('\n')
  139. ip_list = [i.strip() for i in ip_list]
  140. for ip in ip_list:
  141. if webnotes.remote_ip.startswith(ip):
  142. return
  143. webnotes.msgprint('Not allowed from this IP Address')
  144. raise webnotes.AuthenticationError
  145. def validate_hour(self):
  146. """check if user is logging in during restricted hours"""
  147. login_before = int(webnotes.conn.get_value('Profile', self.user, 'login_before', ignore=True) or 0)
  148. login_after = int(webnotes.conn.get_value('Profile', self.user, 'login_after', ignore=True) or 0)
  149. if not (login_before or login_after):
  150. return
  151. from webnotes.utils import now_datetime
  152. current_hour = int(now_datetime().strftime('%H'))
  153. if login_before and current_hour > login_before:
  154. webnotes.msgprint('Not allowed to login after restricted hour', raise_exception=1)
  155. if login_after and current_hour < login_after:
  156. webnotes.msgprint('Not allowed to login before restricted hour', raise_exception=1)
  157. def login_as_guest(self):
  158. """login as guest"""
  159. self.user = 'Guest'
  160. self.post_login()
  161. def logout(self, arg='', user=None):
  162. if not user: user = webnotes.session.get('user')
  163. self.user = user
  164. self.run_trigger('on_logout')
  165. if user in ['demo@erpnext.com', 'Administrator']:
  166. webnotes.conn.sql('delete from tabSessions where sid=%s', webnotes.session.get('sid'))
  167. else:
  168. webnotes.conn.sql('delete from tabSessions where user=%s', user)
  169. # =================================================================================
  170. # Cookie Manager
  171. # =================================================================================
  172. class CookieManager:
  173. def __init__(self):
  174. import Cookie
  175. webnotes.cookies = Cookie.SimpleCookie()
  176. self.get_incoming_cookies()
  177. def get_incoming_cookies(self):
  178. import os
  179. cookies = {}
  180. if 'HTTP_COOKIE' in os.environ:
  181. c = os.environ['HTTP_COOKIE']
  182. webnotes.cookies.load(c)
  183. for c in webnotes.cookies.values():
  184. cookies[c.key] = c.value
  185. webnotes.incoming_cookies = cookies
  186. def set_cookies(self):
  187. if not webnotes.session.get('sid'): return
  188. import datetime
  189. # sid expires in 3 days
  190. expires = datetime.datetime.now() + datetime.timedelta(days=3)
  191. expires = expires.strftime('%a, %d %b %Y %H:%M:%S')
  192. webnotes.cookies[b'sid'] = webnotes.session['sid'].encode('utf-8')
  193. webnotes.cookies[b'sid'][b'expires'] = expires.encode('utf-8')
  194. webnotes.cookies[b'sid'][b'path'] = b'/'
  195. def set_remember_me(self):
  196. from webnotes.utils import cint
  197. if not cint(webnotes.form_dict.get('remember_me')): return
  198. remember_days = webnotes.conn.get_value('Control Panel', None,
  199. 'remember_for_days') or 7
  200. import datetime
  201. expires = datetime.datetime.now() + \
  202. datetime.timedelta(days=remember_days)
  203. expires = expires.strftime('%a, %d %b %Y %H:%M:%S')
  204. webnotes.cookies[b'remember_me'] = 1
  205. for k in webnotes.cookies.keys():
  206. webnotes.cookies[k][b'expires'] = expires.encode('utf-8')
  207. # =================================================================================
  208. # Session
  209. # =================================================================================
  210. class Session:
  211. def __init__(self, user=None):
  212. self.user = user
  213. self.sid = webnotes.form_dict.get('sid') or webnotes.incoming_cookies.get('sid', 'Guest')
  214. self.data = webnotes.DictObj({'user':user,'data':{}})
  215. if webnotes.form_dict.get('cmd')=='login':
  216. self.start()
  217. return
  218. self.load()
  219. # start a session
  220. # ---------------
  221. def get_session_record(self):
  222. """get session record, or return the standard Guest Record"""
  223. r = webnotes.conn.sql("""select user, sessiondata, status from
  224. tabSessions where sid='%s'""" % self.sid)
  225. if not r:
  226. self.sid = 'Guest'
  227. r = webnotes.conn.sql("""select user, sessiondata, status from
  228. tabSessions where sid='%s'""" % self.sid)
  229. return r and r[0] or None
  230. def load(self):
  231. """non-login request: load a session"""
  232. import webnotes
  233. r = self.get_session_record()
  234. if r:
  235. self.data = webnotes.DictObj({'data': (r[1] and eval(r[1]) or {}),
  236. 'user':r[0], 'sid': self.sid})
  237. else:
  238. self.start_as_guest()
  239. def start_as_guest(self):
  240. """all guests share the same 'Guest' session"""
  241. webnotes.login_manager.login_as_guest()
  242. self.start()
  243. def start(self):
  244. """start a new session"""
  245. import os
  246. import webnotes
  247. import webnotes.utils
  248. # generate sid
  249. if webnotes.login_manager.user=='Guest':
  250. sid = 'Guest'
  251. else:
  252. sid = webnotes.generate_hash()
  253. self.data['user'] = webnotes.login_manager.user
  254. self.data['sid'] = sid
  255. self.data['data']['session_ip'] = os.environ.get('REMOTE_ADDR');
  256. # get ipinfo
  257. if webnotes.conn.get_global('get_ip_info'):
  258. self.get_ipinfo()
  259. # insert session
  260. self.insert_session_record()
  261. # update profile
  262. webnotes.conn.sql("""UPDATE tabProfile SET last_login = '%s', last_ip = '%s'
  263. where name='%s'""" % (webnotes.utils.now(), webnotes.remote_ip, self.data['user']))
  264. # set cookies to write
  265. webnotes.session = self.data
  266. webnotes.cookie_manager.set_cookies()
  267. def update(self):
  268. """extend session expiry"""
  269. if webnotes.session['user'] != 'Guest':
  270. self.check_expired()
  271. webnotes.conn.sql("""update tabSessions set sessiondata=%s, user=%s, lastupdate=NOW()
  272. where sid=%s""" , (str(self.data['data']), self.data['user'], self.data['sid']))
  273. # check expired
  274. # -------------
  275. def check_expired(self):
  276. """expire non-guest sessions"""
  277. exp_sec = webnotes.conn.get_value('Control Panel', None, 'session_expiry') or '06:00:00'
  278. # incase seconds is missing
  279. if len(exp_sec.split(':')) == 2:
  280. exp_sec = exp_sec + ':00'
  281. # set sessions as expired
  282. webnotes.conn.sql("""delete from tabSessions
  283. where TIMEDIFF(NOW(), lastupdate) > TIME(%s) and sid!='Guest'""", exp_sec)
  284. def get_ipinfo(self):
  285. import os
  286. try:
  287. import pygeoip
  288. except:
  289. return
  290. gi = pygeoip.GeoIP('data/GeoIP.dat')
  291. self.data['data']['ipinfo'] = {'countryName': gi.country_name_by_addr(os.environ.get('REMOTE_ADDR'))}
  292. def insert_session_record(self):
  293. webnotes.conn.sql("""insert into tabSessions
  294. (sessiondata, user, lastupdate, sid, status)
  295. values (%s , %s, NOW(), %s, 'Active')""",
  296. (str(self.data['data']), self.data['user'], self.data['sid']))