def ensure_db(redirect='/web/database/selector'): db = request.params.get('db') and request.params.get('db').strip() if db and db not in http.db_filter([db]): db = None if db and not request.session.db: r = request.httprequest url_redirect = werkzeug.urls.url_parse(r.base_url) if r.query_string: query_string = iri_to_uri(r.query_string) url_redirect = url_redirect.replace(query=query_string) request.session.db = db abort_and_redirect(url_redirect) if not db and request.session.db and http.db_filter([request.session.db]): db = request.session.db if not db: db = db_monodb(request.httprequest) if not db: werkzeug.exceptions.abort(werkzeug.utils.redirect(redirect, 303)) if db != request.session.db: request.session.logout() abort_and_redirect(request.httprequest.url) request.session.db = db
def ensure_db(): db = request.params.get('db') and request.params.get('db').strip() # Ensure db is legit if db and db not in http.db_filter([db]): db = None if db and not request.session.db: # User asked a specific database on a new session. request.session.db = db return # if db not provided, use the session one if not db and request.session.db and http.db_filter([request.session.db]): db = request.session.db # if no database provided and no database in session, use monodb if not db: db = http.db_monodb(request.httprequest) # always switch the session to the computed db if db != request.session.db: request.session.logout() request.session.db = db
def ensure_db(redirect='/web/database/selector'): print("zack ensurre_deb override") # This helper should be used in web client auth="none" routes # if those routes needs a db to work with. # If the heuristics does not find any database, then the users will be # redirected to db selector or any url specified by `redirect` argument. # If the db is taken out of a query parameter, it will be checked against # `http.db_filter()` in order to ensure it's legit and thus avoid db # forgering that could lead to xss attacks. db = request.params.get('db') and request.params.get('db').strip() # Ensure db is legit if db and db not in http.db_filter([db]): db = None if db and not request.session.db: # User asked a specific database on a new session. # That mean the nodb router has been used to find the route # Depending on installed module in the database, the rendering of the page # may depend on data injected by the database route dispatcher. # Thus, we redirect the user to the same page but with the session cookie set. # This will force using the database route dispatcher... r = request.httprequest url_redirect = r.base_url if r.query_string: # Can't use werkzeug.wrappers.BaseRequest.url with encoded hashes: # https://github.com/amigrave/werkzeug/commit/b4a62433f2f7678c234cdcac6247a869f90a7eb7 url_redirect += '?' + r.query_string response = werkzeug.utils.redirect(url_redirect, 302) request.session.db = db abort_and_redirect(url_redirect) # if db not provided, use the session one if not db and request.session.db and http.db_filter([request.session.db]): db = request.session.db # if no database provided and no database in session, use monodb if not db: db = db_monodb(request.httprequest) # if no db can be found til here, send to the database selector # the database selector will redirect to database manager if needed if not db: werkzeug.exceptions.abort(werkzeug.utils.redirect(redirect, 303)) # always switch the session to the computed db if db != request.session.db: request.session.logout() abort_and_redirect(request.httprequest.url) request.session.db = 'tctdemo'
def ensure_db(redirect='/web/database/selector'): # This helper should be used in web client auth="none" routes # if those routes needs a db to work with. # If the heuristics does not find any database, then the users will be # redirected to db selector or any url specified by `redirect` argument. # If the db is taken out of a query parameter, it will be checked against # `http.db_filter()` in order to ensure it's legit and thus avoid db # forgering that could lead to xss attacks. db = request.params.get('db') and request.params.get('db').strip() # Ensure db is legit if db and db not in http.db_filter([db]): db = None if db and not request.session.db: # User asked a specific database on a new session. # That mean the nodb router has been used to find the route # Depending on installed module in the database, the rendering of the page # may depend on data injected by the database route dispatcher. # Thus, we redirect the user to the same page but with the session cookie set. # This will force using the database route dispatcher... r = request.httprequest url_redirect = werkzeug.urls.url_parse(r.base_url) if r.query_string: # in P3, request.query_string is bytes, the rest is text, can't mix them query_string = iri_to_uri(r.query_string) url_redirect = url_redirect.replace(query=query_string) request.session.db = db werkzeug.exceptions.abort(request.redirect(url_redirect.to_url(), 302)) # if db not provided, use the session one if not db and request.session.db and http.db_filter([request.session.db]): db = request.session.db # if no database provided and no database in session, use monodb if not db: all_dbs = http.db_list(force=True) if len(all_dbs) == 1: db = all_dbs[0] # if no db can be found til here, send to the database selector # the database selector will redirect to database manager if needed if not db: werkzeug.exceptions.abort(request.redirect(redirect, 303)) # always switch the session to the computed db if db != request.session.db: request.session = http.root.session_store.new() request.session.update(http.DEFAULT_SESSION, db=db) request.session.context['lang'] = request.default_lang() werkzeug.exceptions.abort( request.redirect(request.httprequest.url, 302))
def _do_post_login(self, employee, redirect): """ 所有的验证都结束并正确后,需要界面跳转到主界面 :param employee: employee :param redirect: :return: """ ensure_db() dbname = request.session.db if not http.db_filter([dbname]): return BadRequest() context = {} registry = registry_get(dbname) oauth_uid = employee.sudo().ding_id with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, context) credentials = env['res.users'].sudo().auth_oauth_dingtalk( "dingtalk", oauth_uid) cr.commit() url = '/web' if not redirect else redirect uid = request.session.authenticate(*credentials) if uid: return http.redirect_with_hash(url) else: self._do_err_redirect("登录失败") except Exception as e: self._do_err_redirect("登录失败,原因为:{}".format(str(e)))
def oea(self, **kw): """login user via Odoo Account provider""" dbname = kw.pop('db', None) if not dbname: dbname = db_monodb() if not dbname: return BadRequest() if not http.db_filter([dbname]): return BadRequest() registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, {}) provider = env.ref('auth_oauth.provider_openerp') except ValueError: return set_cookie_and_redirect('/web?db=%s' % dbname) assert provider._name == 'auth.oauth.provider' state = { 'd': dbname, 'p': provider.id, 'c': {'no_user_creation': True}, } kw['state'] = json.dumps(state) return self.signin(**kw)
def oea(self, **kw): """login user via Odoo Account provider""" dbname = kw.pop('db', None) if not dbname: dbname = request.db if not dbname: raise BadRequest() if not http.db_filter([dbname]): raise BadRequest() registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, {}) provider = env.ref('auth_oauth.provider_openerp') except ValueError: redirect = request.redirect(f'/web?db={dbname}', 303) redirect.autocorrect_location_header = False return redirect assert provider._name == 'auth.oauth.provider' state = { 'd': dbname, 'p': provider.id, 'c': {'no_user_creation': True}, } kw['state'] = json.dumps(state) return self.signin(**kw)
def oea(self, **kw): """login user via Odoo Account provider""" dbname = kw.pop('db', None) if not dbname: dbname = db_monodb() if not dbname: return BadRequest() if not http.db_filter([dbname]): return BadRequest() registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, {}) provider = env.ref('auth_oauth.provider_openerp') except ValueError: return set_cookie_and_redirect('/web?db=%s' % dbname) assert provider._name == 'auth.oauth.provider' state = { 'd': dbname, 'p': provider.id, 'c': { 'no_user_creation': True }, } kw['state'] = json.dumps(state) return self.signin(**kw)
def _web_post_login(self, phone): """ 验证手机并登陆系统 :param phone: :return: """ dbname = request.session.db if not http.db_filter([dbname]): return BadRequest() context = {} registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, context) credentials = env['res.users'].sudo().auth_oauth_sms('sms', phone) cr.commit() url = '/web' uid = request.session.authenticate(*credentials) if uid is not False: request.params['login_success'] = True return json.dumps({'state': True, 'msg': "登录成功"}) except Exception as e: # signup error _logger.exception("OAuth2: %s" % str(e)) url = "/web/login?oauth_error=2" return set_cookie_and_redirect(url)
def _wxent_do_post_login(self, user_id, redirect): """ 所有的验证都结束并正确后,需要界面跳转到主界面 :param user_id: user_id :param redirect: :return: """ ensure_db() dbname = request.session.db if not http.db_filter([dbname]): return BadRequest() context = {} registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, context) credentials = env['res.users'].sudo().auth_oauth_weixin_ent( "weixin_ent", user_id) cr.commit() url = '/web' if not redirect else redirect uid = request.session.authenticate(*credentials) if uid: return http.redirect_with_hash(url) else: return self._do_err_redirect("Oauth认证失败!请使用账号登录") except Exception as e: return self._do_err_redirect("登录失败,原因为:{}".format(str(e)))
def wrapper(*args, **kwargs): params = http.request.params session = http.request.session database = params.get('db') and params.get('db').strip() if database and database not in http.db_filter([database]): database = None if not database and session.db and http.db_filter([session.db]): database = session.db if not database: database = http.db_monodb(http.request.httprequest) if not database: return exceptions.common.NoDatabaseFound() if database != session.db: session.logout() session.db = database return func(*args, **kwargs)
def web_dingtalk_auto_signin_action(self, **kw): """ 通过获得的【免登授权码或者临时授权码】获取用户信息 :param kw: :return: """ auth_code = kw.get('authCode') logging.info(">>>免登授权码: %s", auth_code) config = request.env['dingtalk.mc.config'].sudo().search( [('m_login', '=', True)], limit=1) client = dt.get_client( request, dt.get_dingtalk_config(request, config.company_id)) result = client.user.getuserinfo(auth_code) domain = [('ding_id', '=', result.userid), ('company_id', '=', config.company_id.id)] employee = request.env['hr.employee'].sudo().search(domain, limit=1) if not employee: _logger.info(_("系统对应员工不存在!")) return self._do_err_redirect(_("系统对应员工不存在!")) _logger.info(">>>员工:{}正在尝试登录系统".format(employee.name)) if not employee.ding_id: _logger.info(_("员工不存在钉钉ID,请维护后再试!")) return self._do_err_redirect(_("员工不存在钉钉ID,请维护后再试!")) if not employee.user_id: return self._do_err_redirect(_("你还没有关联系统用户,请联系管理员处理!")) ensure_db() dbname = request.session.db if not http.db_filter([dbname]): return BadRequest() registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, {}) credentials = env['res.users'].sudo().auth_oauth( 'dingtalk', employee.ding_id) cr.commit() url = '/web' resp = login_and_redirect(*credentials, redirect_url=url) if werkzeug.urls.url_parse( resp.location ).path == '/web' and not request.env.user.has_group( 'base.group_user'): resp.location = '/' return resp except AttributeError: _logger.error(">>>未在数据库'%s'上安装auth_signup:oauth注册已取消。" % (dbname, )) url = "/web/login?oauth_error=1" except AccessDenied: _logger.info( '>>>DingTalk-OAuth2: 访问被拒绝,在存在有效会话的情况下重定向到主页,而未设置Cookie') url = "/web/login?oauth_error=3" redirect = werkzeug.utils.redirect(url, 303) redirect.autocorrect_location_header = False return redirect except Exception as e: _logger.exception("OAuth2: %s" % str(e)) url = "/web/login?oauth_error=2" return http.redirect_with_hash(url)
def db_env(dbname): if not http.db_filter([dbname]): raise werkzeug.exceptions.BadRequest() cr = None if dbname == http.request.db: cr = http.request.cr if not cr: cr = odoo.sql_db.db_connect(dbname).cursor() with api.Environment.manage(): yield api.Environment(cr, SUPERUSER_ID, {})
def signin(self, **kw): state = json.loads(kw['state']) dbname = state['d'] if not http.db_filter([dbname]): return BadRequest() provider = state['p'] context = state.get('c', {}) registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, context) credentials = env['res.users'].sudo().auth_oauth(provider, kw) cr.commit() action = state.get('a') menu = state.get('m') redirect = werkzeug.urls.url_unquote_plus( state['r']) if state.get('r') else False url = '/web' if redirect: url = redirect elif action: url = '/web#action=%s' % action elif menu: url = '/web#menu_id=%s' % menu resp = login_and_redirect(*credentials, redirect_url=url) # Since /web is hardcoded, verify user has right to land on it if werkzeug.urls.url_parse( resp.location ).path == '/web' and not request.env.user.has_group( 'base.group_user'): resp.location = '/' return resp except AttributeError: # auth_signup is not installed _logger.error( "auth_signup not installed on database %s: oauth sign up cancelled." % (dbname, )) url = "/web/login?oauth_error=1" except AccessDenied: # oauth credentials not valid, user could be on a temporary session _logger.info( 'OAuth2: access denied, redirect to main page in case a valid session exists, without setting cookies' ) url = "/web/login?oauth_error=3" redirect = werkzeug.utils.redirect(url, 303) redirect.autocorrect_location_header = False return redirect except Exception as e: # signup error _logger.exception("OAuth2: %s" % str(e)) url = "/web/login?oauth_error=2" return set_cookie_and_redirect(url)
def ensure_db(): db = request.params.get('db') and request.params.get('db').strip() if db and db not in http.db_filter([db]): db = None if not db and request.session.db and http.db_filter([request.session.db]): db = request.session.db if not db: db = db_monodb(request.httprequest) if not db: abort(DB_INVALID, status=404) if db != request.session.db: request.session.logout() request.session.db = db try: env = api.Environment(request.cr, odoo.SUPERUSER_ID, {}) module = env['ir.module.module'].search([['name', '=', "muk_rest"]], limit=1) if module.state != 'installed': abort(NO_API, status=500) except Exception as error: _logger.error(error) abort(DB_INVALID, status=404)
def ensure_db(redirect='/web/database/selector'): db = request.params.get('db') if db and db not in http.db_filter([db]): db = None if db and not request.session.db: r = request.httprequest url_redirect = r.base_url if r.query_string: url_redirect += '?' + r.query_string response = werkzeug.utils.redirect(url_redirect, 302) request.session.db = db abort_and_redirect(url_redirect) if not db and request.session.db and http.db_filter([request.session.db]): db = request.session.db if not db: db = http.db_monodb(request.httprequest) if not db: werkzeug.exceptions.abort(werkzeug.utils.redirect(redirect, 303)) if db != request.session.db: request.session.logout() abort_and_redirect(request.httprequest.url) request.session.db = db
def authenticate(self, db, login, password, base_location=None): if not http.db_filter([db]): raise AccessError("Database not found.") pre_uid = request.session.authenticate(db, login, password) if pre_uid != request.session.uid: # Crapy workaround for unupdatable Odoo Mobile App iOS (Thanks Apple :@) and Android # Correct behavior should be to raise AccessError("Renewing an expired session for user that has multi-factor-authentication is not supported. Please use /web/login instead.") return {'uid': None} request.session.db = db registry = odoo.modules.registry.Registry(db) with registry.cursor() as cr: env = odoo.api.Environment(cr, request.session.uid, request.session.context) return env['ir.http'].session_info()
def signin(self, **kw): state = json.loads(kw['state']) dbname = state['d'] if not http.db_filter([dbname]): return BadRequest() provider = state['p'] context = state.get('c', {}) registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, context) credentials = env['res.users'].sudo().auth_oauth(provider, kw) cr.commit() action = state.get('a') menu = state.get('m') redirect = werkzeug.url_unquote_plus(state['r']) if state.get('r') else False url = '/web' if redirect: url = redirect elif action: url = '/web#action=%s' % action elif menu: url = '/web#menu_id=%s' % menu resp = login_and_redirect(*credentials, redirect_url=url) # Since /web is hardcoded, verify user has right to land on it if werkzeug.urls.url_parse(resp.location).path == '/web' and not request.env.user.has_group('base.group_user'): resp.location = '/' return resp except AttributeError: # auth_signup is not installed _logger.error("auth_signup not installed on database %s: oauth sign up cancelled." % (dbname,)) url = "/web/login?oauth_error=1" except AccessDenied: # oauth credentials not valid, user could be on a temporary session _logger.info('OAuth2: access denied, redirect to main page in case a valid session exists, without setting cookies') url = "/web/login?oauth_error=3" redirect = werkzeug.utils.redirect(url, 303) redirect.autocorrect_location_header = False return redirect except Exception as e: # signup error _logger.exception("OAuth2: %s" % str(e)) url = "/web/login?oauth_error=2" return set_cookie_and_redirect(url)
def user_login_by_emp(self, employee): """ :param employee: employee :return: """ ensure_db() dbname = request.session.db if not http.db_filter([dbname]): return BadRequest() registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, {}) credentials = env['res.users'].sudo().auth_oauth( 'dingtalk', employee.ding_id) cr.commit() url = '/web' resp = login_and_redirect(*credentials, redirect_url=url) if werkzeug.urls.url_parse( resp.location ).path == '/web' and not request.env.user.has_group( 'base.group_user'): resp.location = '/' return resp except AttributeError: _logger.error(">>>未在数据库'%s'上安装auth_signup:oauth注册已取消。" % (dbname, )) url = "/web/login?oauth_error=1" except AccessDenied: _logger.info( '>>>DingTalk-OAuth2: 访问被拒绝,在存在有效会话的情况下重定向到主页,而未设置Cookie') url = "/web/login?oauth_error=3" redirect = werkzeug.utils.redirect(url, 303) redirect.autocorrect_location_header = False return redirect except Exception as e: err_str = "OAuth2: %s" % str(e) _logger.exception(err_str) return self.do_error_redirect(err_str) return http.redirect_with_hash(url)
def auto_signin(self, **kw): """ 通过获得的【免登授权码或者临时授权码】获取用户信息 :param kw: :return: """ auth_code = kw.get('authCode') logging.info(">>>免登授权码: %s", auth_code) user_id = self.get_userid_by_auth_code(auth_code) if not user_id: return self._do_err_redirect( "钉钉免登失败!具体原因是无法获取用户code,请检查后台IP是否发生变化!") employee = request.env['hr.employee'].sudo().search( [('ding_id', '=', user_id)], limit=1) if not employee: return self._do_err_redirect("系统对应员工不存在!") logging.info(">>>员工{}正在尝试登录系统".format(employee.name)) dbname = request.session.db if not http.db_filter([dbname]): return BadRequest() context = {} registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, context) credentials = env['res.users'].sudo().auth_oauth_dingtalk( "dingtalk", employee.sudo().ding_id) cr.commit() url = '/web' uid = request.session.authenticate(*credentials) if uid is not False: logging.info(">>>员工{}登录成功".format(employee.sudo().name)) # request.params['login_success'] = False return set_cookie_and_redirect(url) except Exception as e: _logger.exception("OAuth2: %s" % str(e)) url = "/web/login?oauth_error=2" return set_cookie_and_redirect(url)
def wxwork_qr_signin(self, **kw): code = kw.pop("code", None) corpid = request.env["ir.config_parameter"].sudo().get_param( "wxwork.corpid") secret = (request.env["ir.config_parameter"].sudo().get_param( "wxwork.auth_secret")) wxwork_api = CorpApi(corpid, secret) response = wxwork_api.httpCall( CORP_API_TYPE["GET_USER_INFO_BY_CODE"], { "code": code, }, ) state = json.loads(kw["state"].replace("M", '"')) dbname = state["d"] if not http.db_filter([dbname]): return BadRequest() provider = state["p"] context = {"no_user_creation": True} registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, context) credentials = (env["res.users"].sudo().auth_oauth_wxwork( provider, response)) cr.commit() action = state.get("a") menu = state.get("m") redirect = (werkzeug.url_unquote_plus(state["r"]) if state.get("r") else False) url = "/web" if redirect: url = redirect elif action: url = "/web#action=%s" % action elif menu: url = "/web#menu_id=%s" % menu resp = login_and_redirect(*credentials, redirect_url=url) if werkzeug.urls.url_parse( resp.location ).path == "/web" and not request.env.user.has_group( "base.group_user"): resp.location = "/" return resp except AttributeError: # auth_signup is not installed _logger.error( "auth_signup not installed on database %s: oauth sign up cancelled." % (dbname, )) url = "/web/login?oauth_error=1" except AccessDenied: # oauth credentials not valid, user could be on a temporary session _logger.info( "OAuth2: access denied, redirect to main page in case a valid session exists, without setting cookies" ) url = "/web/login?oauth_error=3" redirect = werkzeug.utils.redirect(url, 303) redirect.autocorrect_location_header = False return redirect except Exception as e: # signup error _logger.exception("OAuth2: %s" % str(e)) url = "/web/login?oauth_error=2" return set_cookie_and_redirect(url)
def wecom_web_authorize(self, **kw): code = kw.pop("code", None) state = json.loads(kw["state"]) company = ( request.env["res.company"] .sudo() .search( [("corpid", "=", state["a"]), ("is_wecom_organization", "=", True),], ) ) try: wxapi = ( request.env["wecom.service_api"] .sudo() .InitServiceApi(company, "auth_secret", "auth") ) response = wxapi.httpCall( request.env["wecom.service_api_list"] .sudo() .get_server_api_call("GET_USER_INFO_BY_CODE"), {"code": code,}, ) dbname = state["d"] if not http.db_filter([dbname]): return BadRequest() provider = state["p"] context = {"no_user_creation": True} registry = registry_get(dbname) with registry.cursor() as cr: try: env = api.Environment(cr, SUPERUSER_ID, context) credentials = ( env["res.users"].sudo().wxwrok_auth_oauth(provider, response) ) cr.commit() action = state.get("a") menu = state.get("m") redirect = ( werkzeug.urls.url_unquote_plus(state["r"]) if state.get("r") else False ) url = "/web" if redirect: url = redirect elif action: url = "/web#action=%s" % action elif menu: url = "/web#menu_id=%s" % menu resp = login_and_redirect(*credentials, redirect_url=url) # Since /web is hardcoded, verify user has right to land on it if werkzeug.urls.url_parse( resp.location ).path == "/web" and not request.env.user.has_group( "base.group_user" ): resp.location = "/" return resp except AttributeError: # auth_signup is not installed _logger.error( _( "auth_signup not installed on database %s: oauth sign up cancelled." ) % (dbname,) ) url = "/web/login?oauth_error=1" except AccessDenied: # oauth credentials not valid, user could be on a temporary session _logger.info( _( "OAuth2: access denied, redirect to main page in case a valid session exists, without setting cookies" ) ) url = "/web/login?oauth_error=3" redirect = werkzeug.utils.redirect(url, 303) redirect.autocorrect_location_header = False return redirect except Exception as e: # signup error _logger.exception("OAuth2: %s" % str(e)) url = "/web/login?oauth_error=2" return set_cookie_and_redirect(url) except ApiException as e: return request.env["wecom.tools"].ApiExceptionDialog(e)