Mercurial > libervia-web
comparison src/server/server.py @ 961:22fe06569b1a
server: moved logging worflow in separated method, so it can be used by Libervia Pages
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 27 Oct 2017 18:35:23 +0200 |
parents | 968eda9e982a |
children | c7fba7709d05 |
comparison
equal
deleted
inserted
replaced
960:e59edcae4c18 | 961:22fe06569b1a |
---|---|
887 | 887 |
888 def __init__(self, sat_host): | 888 def __init__(self, sat_host): |
889 JSONRPCMethodManager.__init__(self, sat_host) | 889 JSONRPCMethodManager.__init__(self, sat_host) |
890 self.profiles_waiting = {} | 890 self.profiles_waiting = {} |
891 self.request = None | 891 self.request = None |
892 self.waiting_profiles = WaitingRequests() | |
893 | 892 |
894 def render(self, request): | 893 def render(self, request): |
895 """ | 894 """ |
896 Render method with some hacks: | 895 Render method with some hacks: |
897 - if login is requested, try to login with form data | 896 - if login is requested, try to login with form data |
925 submit_type = request.args['submit_type'][0] | 924 submit_type = request.args['submit_type'][0] |
926 except KeyError: | 925 except KeyError: |
927 return C.BAD_REQUEST | 926 return C.BAD_REQUEST |
928 | 927 |
929 if submit_type == 'register': | 928 if submit_type == 'register': |
930 if not self.sat_host.options["allow_registration"]: | 929 self._registerNewAccount(request) |
931 log.warning(u"Registration received while it is not allowed, hack attempt?") | 930 return server.NOT_DONE_YET |
932 return exceptions.PermissionError(u"Registration is not allowed on this server") | |
933 return self._registerNewAccount(request) | |
934 elif submit_type == 'login': | 931 elif submit_type == 'login': |
935 d = self.asyncBridgeCall("getNewAccountDomain") | 932 self._loginAccount(request) |
936 d.addCallback(lambda domain: self._loginAccount(request, domain)) | |
937 return server.NOT_DONE_YET | 933 return server.NOT_DONE_YET |
938 return Exception('Unknown submit type') | 934 return Exception('Unknown submit type') |
939 | 935 |
940 def _loginAccount(self, request, new_account_domain): | 936 @defer.inlineCallbacks |
937 def _registerNewAccount(self, request): | |
938 try: | |
939 login = request.args['register_login'][0] | |
940 password = request.args['register_password'][0] | |
941 email = request.args['email'][0] | |
942 except KeyError: | |
943 request.write(C.BAD_REQUEST) | |
944 request.finish() | |
945 return | |
946 status = yield self.sat_host.registerNewAccount(request, login, password, email) | |
947 request.write(status) | |
948 request.finish() | |
949 | |
950 @defer.inlineCallbacks | |
951 def _loginAccount(self, request): | |
941 """Try to authenticate the user with the request information. | 952 """Try to authenticate the user with the request information. |
942 | 953 |
943 @param request: request of the register form | 954 will write to request a constant indicating the state: |
944 @param new_account_domain (unicode): host corresponding to the local domain | 955 - C.PROFILE_LOGGED: profile is connected |
945 @return: a constant indicating the state: | 956 - C.PROFILE_LOGGED_EXT_JID: profile is connected and an external jid has been used |
957 - C.SESSION_ACTIVE: session was already active | |
946 - C.BAD_REQUEST: something is wrong in the request (bad arguments) | 958 - C.BAD_REQUEST: something is wrong in the request (bad arguments) |
947 - C.PROFILE_AUTH_ERROR: either the profile (login) or the profile password is wrong | 959 - C.PROFILE_AUTH_ERROR: either the profile (login) or the profile password is wrong |
948 - C.XMPP_AUTH_ERROR: the profile is authenticated but the XMPP password is wrong | 960 - C.XMPP_AUTH_ERROR: the profile is authenticated but the XMPP password is wrong |
949 - C.ALREADY_WAITING: a request has already been submitted for this profile | 961 - C.ALREADY_WAITING: a request has already been submitted for this profil, C.PROFILE_LOGGED_EXT_JID)e |
950 - server.NOT_DONE_YET: the profile is being processed, the return | 962 - C.NOT_CONNECTED: connection has not been established |
951 value will be given by self._logged or auth_eb | 963 the request will then be finished |
964 @param request: request of the register form | |
952 """ | 965 """ |
953 try: | 966 try: |
954 login = request.args['login'][0] | 967 login = request.args['login'][0] |
955 password = request.args['login_password'][0] | 968 password = request.args['login_password'][0] |
956 except KeyError: | 969 except KeyError: |
958 request.finish() | 971 request.finish() |
959 return | 972 return |
960 | 973 |
961 assert login | 974 assert login |
962 | 975 |
963 if login.startswith('@'): # this is checked by javascript but also here for security reason | |
964 # FIXME: return an error instead of an Exception? | |
965 raise Exception('No profile_key allowed') | |
966 | |
967 if '@' in login: | |
968 try: | |
969 login_jid = jid.JID(login) | |
970 except (RuntimeError, jid.InvalidFormat, AttributeError): | |
971 request.write(C.PROFILE_AUTH_ERROR) | |
972 request.finish() | |
973 return | |
974 | |
975 if login_jid.host == new_account_domain: | |
976 # redirect "user@libervia.org" to the "user" profile | |
977 login = login_jid.user | |
978 login_jid = None | |
979 else: | |
980 login_jid = None | |
981 | |
982 try: | 976 try: |
983 profile = self.sat_host.bridge.profileNameGet(login) | 977 status = yield self.sat_host.connect(request, login, password) |
984 except Exception: # XXX: ProfileUnknownError wouldn't work, it's encapsulated | 978 except (exceptions.DataError, |
985 if login_jid is not None and login_jid.user: # try to create a new sat profile using the XMPP credentials | 979 exceptions.ProfileUnknownError, |
986 if not self.sat_host.options["allow_registration"]: | 980 exceptions.PermissionError): |
987 log.warning(u"Trying to register JID account while registration is not allowed") | 981 request.write(C.PROFILE_AUTH_ERROR) |
988 request.write(C.PROFILE_AUTH_ERROR) | 982 request.finish() |
989 request.finish() | 983 return |
990 return | 984 except exceptions.NotReady: |
991 profile = login # FIXME: what if there is a resource? | |
992 connect_method = "asyncConnectWithXMPPCredentials" | |
993 register_with_ext_jid = True | |
994 else: # non existing username | |
995 request.write(C.PROFILE_AUTH_ERROR) | |
996 request.finish() | |
997 return | |
998 else: | |
999 if profile != login or (not password and profile not in self.sat_host.options['empty_password_allowed_warning_dangerous_list']): | |
1000 # profiles with empty passwords are restricted to local frontends | |
1001 request.write(C.PROFILE_AUTH_ERROR) | |
1002 request.finish() | |
1003 return | |
1004 register_with_ext_jid = False | |
1005 | |
1006 connect_method = "connect" | |
1007 | |
1008 if self.waiting_profiles.getRequest(profile): | |
1009 request.write(C.ALREADY_WAITING) | 985 request.write(C.ALREADY_WAITING) |
1010 request.finish() | 986 request.finish() |
1011 return | 987 return |
1012 | 988 except exceptions.TimeOutError: |
1013 def auth_eb(failure): | 989 request.write(C.NO_REPLY) |
1014 fault = failure.value.faultString | |
1015 self.waiting_profiles.purgeRequest(profile) | |
1016 if fault in ('PasswordError', 'ProfileUnknownError'): | |
1017 log.info(u"Profile %s doesn't exist or the submitted password is wrong" % profile) | |
1018 request.write(C.PROFILE_AUTH_ERROR) | |
1019 elif fault == 'SASLAuthError': | |
1020 log.info(u"The XMPP password of profile %s is wrong" % profile) | |
1021 request.write(C.XMPP_AUTH_ERROR) | |
1022 elif fault == 'NoReply': | |
1023 log.info(_("Did not receive a reply (the timeout expired or the connection is broken)")) | |
1024 request.write(C.NO_REPLY) | |
1025 else: | |
1026 log.error(u'Unmanaged fault string "%s" in errback for the connection of profile %s' % (fault, profile)) | |
1027 request.write(fault) | |
1028 request.finish() | 990 request.finish() |
1029 | 991 return |
1030 self.waiting_profiles.setRequest(request, profile, register_with_ext_jid) | 992 except exceptions.InternalError as e: |
1031 d = self.asyncBridgeCall(connect_method, profile, password) | 993 request.write(e.message) |
1032 d.addCallbacks(lambda connected: self._logged(profile, request) if connected else None, auth_eb) | |
1033 | |
1034 def _registerNewAccount(self, request): | |
1035 """Create a new account, or return error | |
1036 @param request: request of the register form | |
1037 @return: a constant indicating the state: | |
1038 - C.BAD_REQUEST: something is wrong in the request (bad arguments) | |
1039 - C.REGISTRATION_SUCCEED: new account has been successfully registered | |
1040 - C.ALREADY_EXISTS: the given profile already exists | |
1041 - C.INTERNAL_ERROR or any unmanaged fault string | |
1042 - server.NOT_DONE_YET: the profile is being processed, the return | |
1043 value will be given later (one of those previously described) | |
1044 """ | |
1045 try: | |
1046 # XXX: for now libervia forces the creation to lower case | |
1047 profile = login = request.args['register_login'][0].lower() | |
1048 password = request.args['register_password'][0] | |
1049 email = request.args['email'][0] | |
1050 except KeyError: | |
1051 return C.BAD_REQUEST | |
1052 if not re.match(r'^[a-z0-9_-]+$', login, re.IGNORECASE) or \ | |
1053 not re.match(r'^.+@.+\..+', email, re.IGNORECASE) or \ | |
1054 len(password) < C.PASSWORD_MIN_LENGTH: | |
1055 return C.BAD_REQUEST | |
1056 | |
1057 def registered(result): | |
1058 request.write(C.REGISTRATION_SUCCEED) | |
1059 request.finish() | 994 request.finish() |
1060 | 995 return |
1061 def registeringError(failure): | 996 except exceptions.ConflictError: |
1062 reason = failure.value.faultString | |
1063 if reason == "ConflictError": | |
1064 request.write(C.ALREADY_EXISTS) | |
1065 elif reason == "InternalError": | |
1066 request.write(C.INTERNAL_ERROR) | |
1067 else: | |
1068 log.error(u'Unknown registering error: %s' % (reason,)) | |
1069 request.write(reason) | |
1070 request.finish() | |
1071 | |
1072 d = self.asyncBridgeCall("registerSatAccount", email, password, profile) | |
1073 d.addCallback(registered) | |
1074 d.addErrback(registeringError) | |
1075 return server.NOT_DONE_YET | |
1076 | |
1077 def _logged(self, profile, request): | |
1078 """Set everything when a user just logged in | |
1079 | |
1080 @param profile | |
1081 @param request | |
1082 @return: a constant indicating the state: | |
1083 - C.PROFILE_LOGGED | |
1084 - C.SESSION_ACTIVE | |
1085 """ | |
1086 register_with_ext_jid = self.waiting_profiles.getRegisterWithExtJid(profile) | |
1087 self.waiting_profiles.purgeRequest(profile) | |
1088 _session = request.getSession() | |
1089 sat_session = session_iface.ISATSession(_session) | |
1090 if sat_session.profile: | |
1091 log.error(_(u'/!\\ Session has already a profile, this should NEVER happen!')) | |
1092 request.write(C.SESSION_ACTIVE) | 997 request.write(C.SESSION_ACTIVE) |
1093 request.finish() | 998 request.finish() |
1094 return | 999 return |
1095 # we manage profile server side to avoid profile spoofing | 1000 except ValueError as e: |
1096 sat_session.profile = profile | 1001 if e.message in (C.PROFILE_AUTH_ERROR, C.XMPP_AUTH_ERROR): |
1097 self.sat_host.prof_connected.add(profile) | 1002 request.write(e.message) |
1098 cache_dir = os.path.join(self.sat_host.cache_root_dir, regex.pathEscape(profile)) | 1003 request.finish() |
1099 # FIXME: would be better to have a global /cache URL which redirect to profile's cache directory, without uuid | 1004 return |
1100 self.sat_host.cache_resource.putChild(sat_session.uuid, ProtectedFile(cache_dir)) | 1005 else: |
1101 log.debug(_(u"profile cache resource added from {uuid} to {path}").format(uuid=sat_session.uuid, path=cache_dir)) | 1006 raise e |
1102 | 1007 |
1103 def onExpire(): | 1008 assert status |
1104 log.info(u"Session expired (profile=%s)" % (profile,)) | 1009 request.write(status) |
1105 self.sat_host.cache_resource.delEntity(sat_session.uuid) | |
1106 log.debug(_(u"profile cache resource {uuid} deleted").format(uuid = sat_session.uuid)) | |
1107 try: | |
1108 #We purge the queue | |
1109 del self.sat_host.signal_handler.queue[profile] | |
1110 except KeyError: | |
1111 pass | |
1112 #and now we disconnect the profile | |
1113 self.sat_host.bridge.disconnect(profile) | |
1114 | |
1115 _session.notifyOnExpire(onExpire) | |
1116 | |
1117 request.write(C.PROFILE_LOGGED_REGISTERED_WITH_EXT_JID if register_with_ext_jid else C.PROFILE_LOGGED) | |
1118 request.finish() | 1010 request.finish() |
1119 | 1011 |
1120 def jsonrpc_isConnected(self): | 1012 def jsonrpc_isConnected(self): |
1121 _session = self.request.getSession() | 1013 _session = self.request.getSession() |
1122 profile = session_iface.ISATSession(_session).profile | 1014 profile = session_iface.ISATSession(_session).profile |
1213 _session.unlock() | 1105 _session.unlock() |
1214 try: | 1106 try: |
1215 source_defer = self.signalDeferred[profile] | 1107 source_defer = self.signalDeferred[profile] |
1216 if source_defer.called and source_defer.result[0] == "disconnected": | 1108 if source_defer.called and source_defer.result[0] == "disconnected": |
1217 log.info(u"[%s] disconnected" % (profile,)) | 1109 log.info(u"[%s] disconnected" % (profile,)) |
1218 _session.expire() | 1110 try: |
1111 _session.expire() | |
1112 except KeyError: | |
1113 # FIXME: happen if session is ended using login page | |
1114 # when pyjamas page is also launched | |
1115 log.warning(u'session is already expired') | |
1219 except IndexError: | 1116 except IndexError: |
1220 log.error("Deferred result should be a tuple with fonction name first") | 1117 log.error("Deferred result should be a tuple with fonction name first") |
1221 | 1118 |
1222 self.signalDeferred[profile] = defer.Deferred() | 1119 self.signalDeferred[profile] = defer.Deferred() |
1223 self.request.notifyFinish().addBoth(unlock, profile) | 1120 self.request.notifyFinish().addBoth(unlock, profile) |
1270 """Connection is done. | 1167 """Connection is done. |
1271 | 1168 |
1272 @param profile (unicode): %(doc_profile)s | 1169 @param profile (unicode): %(doc_profile)s |
1273 @param jid_s (unicode): the JID that we were assigned by the server, as the resource might differ from the JID we asked for. | 1170 @param jid_s (unicode): the JID that we were assigned by the server, as the resource might differ from the JID we asked for. |
1274 """ | 1171 """ |
1172 # FIXME: _logged should not be called from here, check this code | |
1173 # FIXME: check if needed to connect with external jid | |
1275 # jid_s is handled in QuickApp.connectionHandler already | 1174 # jid_s is handled in QuickApp.connectionHandler already |
1276 assert(self.register) # register must be plugged | 1175 # assert self.register # register must be plugged |
1277 request = self.register.waiting_profiles.getRequest(profile) | 1176 # request = self.sat_host.waiting_profiles.getRequest(profile) |
1278 if request: | 1177 # if request: |
1279 self.register._logged(profile, request) | 1178 # self.sat_host._logged(profile, request) |
1280 | 1179 |
1281 def disconnected(self, profile): | 1180 def disconnected(self, profile): |
1282 if not profile in self.sat_host.prof_connected: | 1181 if not profile in self.sat_host.prof_connected: |
1283 log.error("'disconnected' signal received for a not connected profile") | 1182 log.error("'disconnected' signal received for a not connected profile") |
1284 return | 1183 return |
1872 class Libervia(service.Service): | 1771 class Libervia(service.Service): |
1873 | 1772 |
1874 def __init__(self, options): | 1773 def __init__(self, options): |
1875 self.options = options | 1774 self.options = options |
1876 self.initialised = defer.Deferred() | 1775 self.initialised = defer.Deferred() |
1776 self.waiting_profiles = WaitingRequests() # FIXME: should be removed | |
1877 | 1777 |
1878 if self.options['base_url_ext']: | 1778 if self.options['base_url_ext']: |
1879 self.base_url_ext = self.options.pop('base_url_ext') | 1779 self.base_url_ext = self.options.pop('base_url_ext') |
1880 if self.base_url_ext[-1] != '/': | 1780 if self.base_url_ext[-1] != '/': |
1881 self.base_url_ext += '/' | 1781 self.base_url_ext += '/' |
2020 kwargs["callback"] = _callback | 1920 kwargs["callback"] = _callback |
2021 kwargs["errback"] = _errback | 1921 kwargs["errback"] = _errback |
2022 getattr(self.bridge, method_name)(*args, **kwargs) | 1922 getattr(self.bridge, method_name)(*args, **kwargs) |
2023 return d | 1923 return d |
2024 | 1924 |
1925 def _logged(self, profile, request): | |
1926 """Set everything when a user just logged in | |
1927 | |
1928 @param profile | |
1929 @param request | |
1930 @return: a constant indicating the state: | |
1931 - C.PROFILE_LOGGED | |
1932 - C.PROFILE_LOGGED_EXT_JID | |
1933 @raise exceptions.ConflictError: session is already active | |
1934 """ | |
1935 register_with_ext_jid = self.waiting_profiles.getRegisterWithExtJid(profile) | |
1936 self.waiting_profiles.purgeRequest(profile) | |
1937 _session = request.getSession() | |
1938 sat_session = session_iface.ISATSession(_session) | |
1939 if sat_session.profile: | |
1940 log.error(_(u'/!\\ Session has already a profile, this should NEVER happen!')) | |
1941 raise failure.Failure(exceptions.ConflictError("Already active")) | |
1942 | |
1943 sat_session.profile = profile | |
1944 self.prof_connected.add(profile) | |
1945 cache_dir = os.path.join(self.cache_root_dir, regex.pathEscape(profile)) | |
1946 # FIXME: would be better to have a global /cache URL which redirect to profile's cache directory, without uuid | |
1947 self.cache_resource.putChild(sat_session.uuid, ProtectedFile(cache_dir)) | |
1948 log.debug(_(u"profile cache resource added from {uuid} to {path}").format(uuid=sat_session.uuid, path=cache_dir)) | |
1949 | |
1950 def onExpire(): | |
1951 log.info(u"Session expired (profile={profile})".format(profile=profile,)) | |
1952 self.cache_resource.delEntity(sat_session.uuid) | |
1953 log.debug(_(u"profile cache resource {uuid} deleted").format(uuid = sat_session.uuid)) | |
1954 try: | |
1955 #We purge the queue | |
1956 del self.signal_handler.queue[profile] | |
1957 except KeyError: | |
1958 pass | |
1959 #and now we disconnect the profile | |
1960 self.bridge.disconnect(profile) | |
1961 | |
1962 _session.notifyOnExpire(onExpire) | |
1963 | |
1964 return C.PROFILE_LOGGED_EXT_JID if register_with_ext_jid else C.PROFILE_LOGGED | |
1965 | |
1966 @defer.inlineCallbacks | |
1967 def connect(self, request, login, password): | |
1968 """log user in | |
1969 | |
1970 If an other user was already logged, it will be unlogged first | |
1971 @param request(server.Request): request linked to the session | |
1972 @param login(unicode): user login | |
1973 can be profile name | |
1974 can be profile@[libervia_domain.ext] | |
1975 can be a jid (a new profile will be created with this jid if needed) | |
1976 @param password(unicode): user password | |
1977 @return (unicode, None): C.SESSION_ACTIVE: if session was aleady active else self._logged value | |
1978 @raise exceptions.DataError: invalid login | |
1979 @raise exceptions.ProfileUnknownError: this login doesn't exist | |
1980 @raise exceptions.PermissionError: a login is not accepted (e.g. empty password not allowed) | |
1981 @raise exceptions.NotReady: a profile connection is already waiting | |
1982 @raise exceptions.TimeoutError: didn't received and answer from Bridge | |
1983 @raise exceptions.InternalError: unknown error | |
1984 @raise ValueError(C.PROFILE_AUTH_ERROR): invalid login and/or password | |
1985 @raise ValueError(C.XMPP_AUTH_ERROR): invalid XMPP account password | |
1986 """ | |
1987 | |
1988 # XXX: all security checks must be done here, even if present in javascript | |
1989 if login.startswith('@'): | |
1990 raise failure.Failure(exceptions.DataError('No profile_key allowed')) | |
1991 | |
1992 if '@' in login: | |
1993 try: | |
1994 login_jid = jid.JID(login) | |
1995 except (RuntimeError, jid.InvalidFormat, AttributeError): | |
1996 raise failure.Failure(exceptions.DataError('No profile_key allowed')) | |
1997 | |
1998 # FIXME: should it be cached? | |
1999 new_account_domain = yield self.bridgeCall("getNewAccountDomain") | |
2000 | |
2001 if login_jid.host == new_account_domain: | |
2002 # redirect "user@libervia.org" to the "user" profile | |
2003 login = login_jid.user | |
2004 login_jid = None | |
2005 else: | |
2006 login_jid = None | |
2007 | |
2008 try: | |
2009 profile = yield self.bridgeCall("profileNameGet", login) | |
2010 except Exception: # XXX: ProfileUnknownError wouldn't work, it's encapsulated | |
2011 # FIXME: find a better way to handle bridge errors | |
2012 if login_jid is not None and login_jid.user: # try to create a new sat profile using the XMPP credentials | |
2013 if not self.options["allow_registration"]: | |
2014 log.warning(u"Trying to register JID account while registration is not allowed") | |
2015 raise failure.Failure(exceptions.DataError(u"JID login while registration is not allowed")) | |
2016 profile = login # FIXME: what if there is a resource? | |
2017 connect_method = "asyncConnectWithXMPPCredentials" | |
2018 register_with_ext_jid = True | |
2019 else: # non existing username | |
2020 raise failure.Failure(exceptions.ProfileUnknownError()) | |
2021 else: | |
2022 if profile != login or (not password and profile not in self.options['empty_password_allowed_warning_dangerous_list']): | |
2023 # profiles with empty passwords are restricted to local frontends | |
2024 raise exceptions.PermissionError | |
2025 register_with_ext_jid = False | |
2026 | |
2027 connect_method = "connect" | |
2028 | |
2029 # we check if there is not already an active session | |
2030 sat_session = session_iface.ISATSession(request.getSession()) | |
2031 if sat_session.profile: | |
2032 # yes, there is | |
2033 if sat_session.profile != profile: | |
2034 # it's a different profile, we need to disconnect it | |
2035 log.warning(_(u"{new_profile} requested login, but {old_profile} was already connected, disconnecting {old_profile}").format( | |
2036 old_profile = sat_session.profile, | |
2037 new_profile = profile)) | |
2038 self.purgeSession(request) | |
2039 | |
2040 if self.waiting_profiles.getRequest(profile): | |
2041 # FIXME: check if and when this can happen | |
2042 raise failure.Failure(exceptions.NotReady("Already waiting")) | |
2043 | |
2044 self.waiting_profiles.setRequest(request, profile, register_with_ext_jid) | |
2045 try: | |
2046 connected = yield self.bridgeCall(connect_method, profile, password) | |
2047 except Exception as failure_: | |
2048 fault = failure_.faultString | |
2049 self.waiting_profiles.purgeRequest(profile) | |
2050 if fault in ('PasswordError', 'ProfileUnknownError'): | |
2051 log.info(u"Profile {profile} doesn't exist or the submitted password is wrong".format(profile=profile)) | |
2052 raise failure.Failure(ValueError(C.PROFILE_AUTH_ERROR)) | |
2053 elif fault == 'SASLAuthError': | |
2054 log.info(u"The XMPP password of profile {profile} is wrong".format(profile=profile)) | |
2055 raise failure.Failure(ValueError(C.XMPP_AUTH_ERROR)) | |
2056 elif fault == 'NoReply': | |
2057 log.info(_("Did not receive a reply (the timeout expired or the connection is broken)")) | |
2058 raise exceptions.TimeOutError | |
2059 else: | |
2060 log.error(u'Unmanaged fault string "{fault}" in errback for the connection of profile {profile}'.format( | |
2061 fault=fault, profile=profile)) | |
2062 raise failure.Failure(exceptions.InternalError(fault)) | |
2063 | |
2064 if connected: | |
2065 # profile is already connected in backend | |
2066 # do we have a corresponding session in Libervia? | |
2067 sat_session = session_iface.ISATSession(request.getSession()) | |
2068 if sat_session.profile: | |
2069 # yes, session is active | |
2070 if sat_session.profile != profile: | |
2071 # existing session should have been ended above | |
2072 # so this line should never be reached | |
2073 log.error(_(u'session profile [{session_profile}] differs from login profile [{profile}], this should not happen!').format( | |
2074 session_profile = sat_session.profile, | |
2075 profile = profile | |
2076 )) | |
2077 raise exceptions.InternalError("profile mismatch") | |
2078 defer.returnValue(C.SESSION_ACTIVE) | |
2079 log.info(_(u"profile {profile} was already connected in backend".format(profile=profile))) | |
2080 # no, we have to create it | |
2081 defer.returnValue(self._logged(profile, request)) | |
2082 | |
2083 def registerNewAccount(self, request, login, password, email): | |
2084 """Create a new account, or return error | |
2085 @param request(server.Request): request linked to the session | |
2086 @param login(unicode): new account requested login | |
2087 @param email(unicode): new account email | |
2088 @param password(unicode): new account password | |
2089 @return(unicode): a constant indicating the state: | |
2090 - C.BAD_REQUEST: something is wrong in the request (bad arguments) | |
2091 - C.INVALID_INPUT: one of the data is not valid | |
2092 - C.REGISTRATION_SUCCEED: new account has been successfully registered | |
2093 - C.ALREADY_EXISTS: the given profile already exists | |
2094 - C.INTERNAL_ERROR or any unmanaged fault string | |
2095 @raise PermissionError: registration is now allowed in server configuration | |
2096 """ | |
2097 if not self.options["allow_registration"]: | |
2098 log.warning(_(u"Registration received while it is not allowed, hack attempt?")) | |
2099 raise failure.Failure(exceptions.PermissionError(u"Registration is not allowed on this server")) | |
2100 | |
2101 if not re.match(C.REG_LOGIN_RE, login) or \ | |
2102 not re.match(C.REG_EMAIL_RE, email, re.IGNORECASE) or \ | |
2103 len(password) < C.PASSWORD_MIN_LENGTH: | |
2104 return C.INVALID_INPUT | |
2105 | |
2106 def registered(result): | |
2107 return C.REGISTRATION_SUCCEED | |
2108 | |
2109 def registeringError(failure): | |
2110 status = failure.value.faultString | |
2111 if status == "ConflictError": | |
2112 return C.ALREADY_EXISTS | |
2113 elif status == "InternalError": | |
2114 return C.INTERNAL_ERROR | |
2115 else: | |
2116 log.error(_(u'Unknown registering error status: {status }').format( | |
2117 status = status)) | |
2118 return status | |
2119 | |
2120 d = self.bridgeCall("registerSatAccount", email, password, login) | |
2121 d.addCallback(registered) | |
2122 d.addErrback(registeringError) | |
2123 return d | |
2124 | |
2025 def addCleanup(self, callback, *args, **kwargs): | 2125 def addCleanup(self, callback, *args, **kwargs): |
2026 """Add cleaning method to call when service is stopped | 2126 """Add cleaning method to call when service is stopped |
2127 | |
2027 cleaning method will be called in reverse order of they insertion | 2128 cleaning method will be called in reverse order of they insertion |
2028 @param callback: callable to call on service stop | 2129 @param callback: callable to call on service stop |
2029 @param *args: list of arguments of the callback | 2130 @param *args: list of arguments of the callback |
2030 @param **kwargs: list of keyword arguments of the callback""" | 2131 @param **kwargs: list of keyword arguments of the callback""" |
2031 self._cleanup.insert(0, (callback, args, kwargs)) | 2132 self._cleanup.insert(0, (callback, args, kwargs)) |