/yaki/snakeserver/user.py

https://github.com/20after4/Yaki · Python · 133 lines · 85 code · 18 blank · 30 comment · 28 complexity · 083a5cff7b76530327fbd2e4a512b13a MD5 · raw file

  1. #############################################################################
  2. #
  3. # $Id: user.py,v 1.19 2008/10/12 15:42:16 irmen Exp $
  4. # User management (authenticated users, roles).
  5. #
  6. # This is part of "Snakelets" - Python Web Application Server
  7. # which is (c) Irmen de Jong - irmen@users.sourceforge.net
  8. # Modified by Rui Carmo to include p3 password escrow
  9. #
  10. #############################################################################
  11. #
  12. # Notice that the user id is set once (when creating the user object) and cannot
  13. # be changed, and that the password itself is not stored but its secure hash instead.
  14. #
  15. # Privileges are stored and returned as a Set.
  16. #
  17. import hashlib, time, p3
  18. class LoginUser(object):
  19. def getuserid(self): return self.__userid
  20. def getname(self): return self.__name
  21. def setname(self, name): self.__name=name
  22. def setpassword(self,passwd):
  23. if passwd:
  24. string = self.userid+passwd
  25. if type(string) is unicode:
  26. string=string.encode("UTF-8")
  27. self.__passwordhash=p3.p3_encrypt(string,self.escrow)
  28. else:
  29. self.__passwordhash=None
  30. def getpassword(self): return self.__passwordhash
  31. def getplaintextpassword(self): return p3.p3_decrypt(self.__passwordhash,self.escrow)
  32. def getprivileges(self): return self.__privileges
  33. def setprivileges(self, privs): self.__privileges=set(privs)
  34. def delprivileges(self): self.__privileges=set()
  35. userid=property(getuserid, None, None, "unique id")
  36. name=property(getname, setname, None, "descriptive name")
  37. password=property(getpassword, setpassword, None, "secret password. Only the secure hash is stored, not the pw itself")
  38. privileges=property(getprivileges, setprivileges, delprivileges, "set of the privileges this user has")
  39. def __init__(self, userid, password=None, name=None, privileges=None, passwordhash=None, escrow=None):
  40. self.__userid=userid
  41. self.name=name
  42. if escrow:
  43. self.escrow=escrow
  44. else:
  45. self.escrow=""
  46. if passwordhash:
  47. # To initialize the password hash from an external source
  48. # for instance when you're loading user data from a database
  49. self.__passwordhash = passwordhash
  50. else:
  51. self.password=password
  52. self.privileges=privileges or []
  53. def checkPassword(self, password):
  54. string = self.userid+password
  55. if type(string) is unicode:
  56. string=string.encode("UTF-8")
  57. return p3.p3_encrypt(string,self.escrow) == self.__passwordhash
  58. def hasPrivileges(self, privileges):
  59. # does this user have ALL of the asked privileges?
  60. return set(privileges).issubset(self.privileges)
  61. def hasAnyPrivilege(self, privileges):
  62. # does this user have any of the asked privileges?
  63. return len(set(privileges) & self.privileges)>0 # intersection
  64. def hasPrivilege(self, privilege):
  65. # does this user have the given privilege?
  66. return privilege in self.privileges
  67. def __repr__(self):
  68. return "<%s.%s object '%s' at 0x%08lx>" % (self.__module__, self.__class__.__name__, self.userid, id(self))
  69. # the following class can be used as a base class for Ypages.
  70. # note that the form fields must be called "login" and "password"
  71. # They can occur both on the request form (examined first) and on the request context.
  72. from YpageEngine import Ypage
  73. import httpauth
  74. class LoginPage(object):
  75. def attemptLogin(self, fallbackReturnpage=None, successfulLoginFunc=None):
  76. ctx=self.Request.getContext()
  77. if self.requiresSession() == self.SESSION_NOT_NEEDED:
  78. raise Ypage.PageAbortError("session type may not be 'no' for login pages")
  79. login = self.Request.getParameter("login") or getattr(ctx, "login", None)
  80. if login:
  81. # a login attempt is made. Check for returnpage on the session
  82. returnpage_session = getattr(self.Request.getSessionContext(),"_SNKLOGIN_RETURNPAGE",None)
  83. MAINPAGE = getattr(ctx,"_SNKLOGIN_RETURNPAGE",None) or returnpage_session or fallbackReturnpage
  84. else:
  85. # no login attempt (probably just entering the login page for the first time)
  86. # don't get a returnpage from the session!
  87. MAINPAGE = getattr(ctx,"_SNKLOGIN_RETURNPAGE",None) or fallbackReturnpage
  88. if not MAINPAGE:
  89. raise Ypage.PageAbortError("no RETURNPAGE")
  90. self.Request.getSessionContext()._SNKLOGIN_RETURNPAGE=MAINPAGE
  91. # check if we are already logged in.
  92. # in that case, go directly to the main page.
  93. if self.User:
  94. del self.Request.getSessionContext()._SNKLOGIN_RETURNPAGE
  95. self.Yhttpredirect(MAINPAGE)
  96. else:
  97. login = self.Request.getParameter("login") or getattr(ctx, "login", None)
  98. password = self.Request.getParameter("password") or getattr(ctx, "password", None)
  99. if not self.WebApp.authorizeUser:
  100. raise httpauth.AuthError("no http user authenticator defined in webapp")
  101. if login:
  102. auth = self.WebApp.authorizeUser("loginpage", self.getURL(), login, password, self.Request)
  103. if auth is None:
  104. time.sleep(2) # to thwart brute-force password attacks
  105. else:
  106. if isinstance(auth,LoginUser):
  107. userobject = auth
  108. else:
  109. userobject = LoginUser(login,privileges=auth)
  110. # user is okay! log in and go to the returnpage.
  111. self.Request.getSession().loginUser(userobject)
  112. del self.Request.getSessionContext()._SNKLOGIN_RETURNPAGE
  113. if successfulLoginFunc:
  114. successfulLoginFunc(userobject)
  115. self.Yhttpredirect(MAINPAGE)