def authorize_user(request_user_id): auth = _config["auth"]; if not auth["on"]: return; # method donot require check. conditions = cherrypy.request.config.get('auth.require', None) if conditions is None: return; # QQ-OAuth not enabled. if auth["strategy"] == "qq_oauth": # check QQ-OAuth session. user_id = cherrypy.session.get(SESSION_KEY); if user_id is None: error("authorize_user invalid, no session."); enable_crossdomain(); raise cherrypy.HTTPError(401, "You are not authorized, login please."); return; if request_user_id in authorize_get_exception_user_id(user_id): error("authorize_user(id=%s) requires user id=%s invalid, check authorization failed."%(user_id, request_user_id)); enable_crossdomain(); raise cherrypy.HTTPError(403, "You(id=%s) are not authorized as %s, login please."%(user_id, request_user_id)); return; trace("authorize success, user_id=%s requires id=%s"%(user_id, request_user_id)); return;
def qq_oauth_access(self, access_token): auth = _config["auth"] # https://graph.qq.com/oauth2.0/me?access_token=QE9894RYY787767676G8G87G90980D0D api = "%s?access_token=%s" % (auth["qq_oauth_api_me"], access_token) trace("validate access_token from %s" % (api)) # query qq_oauth_openid url = urllib.urlopen(api) data = url.read() url.close() json_data = data.strip().strip("callback").strip("(").strip(";").strip( ")").strip() trace("trim me data to %s" % (json_data)) try: res_json = json.loads(json_data) except Exception, e: error(sys.exc_info) return json.dumps({ "code": ErrorCode.Failed, "error": ErrorCode.Failed, "error_description": "qq_oauth_openid to json error" })
def GET(self, group="", start_time="", end_time="", summary="", user_id="", product_id="", type_id="", query_all="false", r=None): enable_crossdomain(); if query_all == True or query_all == "true" or str(query_all) == "1": query_all = True else: query_all = False # if not null, must be a digit. if group != "" and str(group) != "-1" and not str(group).isdigit(): error("group must be digit, actual is %s"%(group)); raise cherrypy.HTTPError(400, "group must be digit"); trace('group=%s, start_time=%s, end_time=%s, summary=%s, user_id=%s, product_id=%s, type_id=%s, query_all=%s'%(group, start_time, end_time, summary, user_id, product_id, type_id, query_all)); if user_id != "": authorize_user(user_id); if group == "" or str(group) == "-1": if summary == "1": return self.query_summary(start_time, end_time, user_id, product_id, type_id, query_all); else: return self.query_detail(start_time, end_time, user_id, product_id, type_id, query_all); else: if summary == "1": return self.query_summary_group(group, start_time, end_time, user_id, product_id, type_id, query_all); else: return self.query_detail_group(group, start_time, end_time, user_id, product_id, type_id, query_all);
def qq_oauth_cache_qq_oauth_openid(self, access_token, qq_oauth_openid): auth = _config["auth"] # query user by qq_oauth_openid from local db. records = self.qq_oauth_get_associated(qq_oauth_openid) if len(records) == 0: # if not auto register user, let user to select the available user. if not auth["qq_oauth_auto_register_user"]: return self.qq_oauth_query_available_associate_user( access_token, qq_oauth_openid) # auto register user then reinitialize the associated records. self.qq_oauth_auto_register(access_token, qq_oauth_openid) records = self.qq_oauth_get_associated(qq_oauth_openid) # matched, update session to login success (user_id, user_name) = (records[0]["user_id"], records[0]["user_name"]) trace("qq_oauth_openid=%s match user %s(id=%s)" % (qq_oauth_openid, user_name, user_id)) cherrypy.session[SESSION_KEY] = user_id res = json.dumps({ "code": ErrorCode.Success, "error": ErrorCode.Success, "user_id": user_id, "error_description": "validate success", "api_key": str(cherrypy.session.id) # the api_key used to hack the cookie. }) trace("response: %s" % (res)) return res
def check_auth(*args, **kwargs): # auth not enabled in config. auth = _config["auth"]; if not auth["on"]: return; # method donot require check. conditions = cherrypy.request.config.get('auth.require', None) if conditions is None: return; # QQ-OAuth not enabled. if auth["strategy"] == "qq_oauth": trace("check session, session_id=%s"%(cherrypy.session.id)); # check QQ-OAuth session. user_id = cherrypy.session.get(SESSION_KEY); if user_id is None: error("session invalid, check auth failed."); enable_crossdomain(); raise cherrypy.HTTPError(401, "You are not authorized, login please."); return; # check condition. for condition in conditions: if not condition(): error("codition check invalid, check auth failed."); enable_crossdomain(); raise cherrypy.HTTPError(401, "You are not authorized for specified condition"); return; trace("check auth success. user_id=%s"%(user_id));
def qq_oauth_auto_register(self, access_token, qq_oauth_openid): auth = _config["auth"] # https://graph.qq.com/user/get_user_info?access_token=71871H1H3187I31EQJK3197J3JWQ8Q0D&appid=8373636744&openid=87JDD73KH32W3983JIUDS92198DS5B32 # get user nickname as user_name, email empty api = "%s?access_token=%s&appid=%s&openid=%s" % ( auth["qq_oauth_api_get_user_info"], access_token, auth["qq_oauth_api_app_id"], qq_oauth_openid) trace("auto register get user_info from %s" % (api)) # query qq_oauth_openid url = urllib.urlopen(api) data = url.read() url.close() json_data = data.strip().strip("callback").strip("(").strip(";").strip( ")").strip() trace("trim get_user_info data to %s" % (json_data)) try: res_json = json.loads(json_data) except Exception, e: error("ex=%s, info=%s" % (e, traceback.format_exc())) return json.dumps({ "code": ErrorCode.Failed, "error": ErrorCode.Failed, "error_description": "userinfo to json error" })
def qq_oauth_cache_qq_oauth_openid(self, access_token, qq_oauth_openid): auth = _config["auth"]; # query user by qq_oauth_openid from local db. records = self.qq_oauth_get_associated(qq_oauth_openid); if len(records) == 0: # if not auto register user, let user to select the available user. if not auth["qq_oauth_auto_register_user"]: return self.qq_oauth_query_available_associate_user(access_token, qq_oauth_openid); # auto register user then reinitialize the associated records. self.qq_oauth_auto_register(access_token, qq_oauth_openid); records = self.qq_oauth_get_associated(qq_oauth_openid); # matched, update session to login success (user_id, user_name) = (records[0]["user_id"], records[0]["user_name"]); trace("qq_oauth_openid=%s match user %s(id=%s)"%(qq_oauth_openid, user_name, user_id)); cherrypy.session[SESSION_KEY] = user_id; res = json.dumps({ "code":ErrorCode.Success, "error":ErrorCode.Success, "user_id":user_id, "error_description":"validate success", "api_key":str(cherrypy.session.id) # the api_key used to hack the cookie. }); trace("response: %s"%(res)); return res;
def qq_oauth_register_associate(self, access_token, qq_oauth_openid, user_id): sql_exec( "delete from dr_authenticate where user_id=%s and qq_oauth_openid=%s", (user_id, qq_oauth_openid)) sql_exec( "insert into dr_authenticate (user_id, qq_oauth_openid, qq_oauth_access_token) values(%s, %s, %s)", (user_id, qq_oauth_openid, access_token)) trace( "associate user id=%s to auth qq_oauth_openid=%s access_token=%s" % (user_id, qq_oauth_openid, access_token))
def email_strategy_check(self, date): mail = _config["mail"]; # check only when someone has submitted report. if mail["strategy_check_only_someone_submited"]: records = sql_exec("select user_id,email from dr_user where enabled=true and user_id in " "(select distinct u.user_id from dr_user u, dr_report r where u.user_id = r.user_id and r.work_date=%s)"%(date)); if len(records) < mail["strategy_check_only_someone_submited_count"]: trace("strategy_check_only_someone_submited is checked, " "bug only %s submited(<%s), ignore and donot email."%(len(records), mail["strategy_check_only_someone_submited_count"])); return False; return True;
def GET(self, group="", query_all="false", r=None): enable_crossdomain(); if query_all == True or query_all == "true" or str(query_all) == "1": query_all = True else: query_all = False # if not null, must be a digit. if group != "" and str(group) != "-1" and not str(group).isdigit(): error("group must be digit, actual is %s"%(group)); raise cherrypy.HTTPError(400, "group must be digit"); records = []; if query_all: if group == "" or str(group) == "-1": records = sql_exec("select user_id,user_name from dr_user"); else: records = sql_exec("select u.user_id,u.user_name " "from dr_user u,dr_group g,dr_rs_group_user rs " "where rs.user_id = u.user_id and g.group_id = rs.group_id and g.group_id = %s", (group)); else: if group == "" or str(group) == "-1": records = sql_exec("select user_id,user_name from dr_user where enabled=true"); else: records = sql_exec("select u.user_id,u.user_name " "from dr_user u,dr_group g,dr_rs_group_user rs " "where u.enabled=true " "and rs.user_id = u.user_id and g.group_id = rs.group_id and g.group_id = %s", (group)); user_id = None; auth = _config["auth"]; if auth["on"]: # QQ-OAuth not enabled. if auth["strategy"] == "qq_oauth": # check QQ-OAuth session. user_id = cherrypy.session.get(SESSION_KEY); # the user cannot authorize by specified user. exception_users = authorize_get_exception_user_id(user_id); trace("get users while group=%s for user_id=%s exception_users=%s"%(group, user_id, exception_users)); ret = []; for record in records: returned_user_id = record["user_id"]; if returned_user_id in exception_users: continue; ret.append({ "id":returned_user_id, "value":record["user_name"] }); return json.dumps({"code":ErrorCode.Success, "auth":user_id, "users":ret});
def email_for_time(self, mail_time, mail_times): (hour, minute, second) = mail_time.split(":"); now = datetime.datetime.now(); if now.hour != int(hour): return True; if now.minute != int(minute): return True; if now.second != int(second): return True; mail = _config["mail"]; # log date = now.strftime("%Y-%m-%d"); trace("email from %s when time is %s, date is %s"%(mail["username"], mail_times, date)); time.sleep(1); # check email strategy if not self.email_strategy_check(date): return False; # query email to user list. records = sql_exec("select user_id,user_name,email from dr_user where enabled=true and user_id not in " "(select distinct u.user_id from dr_user u, dr_report r where u.user_id = r.user_id and r.work_date=%s)"%(date)); if len(records) == 0: trace("all user reported, donot email"); return False; # generate to user list. to_user = []; for record in records: to_user.append(record["user_name"]); trace("email to %s."%(to_user)); for record in records: if not self.do_email_to(record["user_id"], record["user_name"], record["email"], date): return False; trace("email to %s cc=%s success."%(to_user, mail["cc_user"])); return True;
def GET(self, issue_id, r=None): enable_crossdomain(); # read config from file. redmine = _config["redmine"]; redmine_api_issues = "%s://%s:%s@%s:%s/%s"%( redmine["protocol"], redmine["username"], redmine["password"], redmine["host"], redmine["port"], redmine["path"]); # proxy for redmine issues # 1. must Enable the RESTful api: http://www.redmine.org/projects/redmine/wiki/Rest_api#Authentication # 2. add a user, username="******", password="******", add to report user, which can access the issues. api = "%s/%s.json"%(redmine_api_issues, issue_id); trace(api); url = urllib.urlopen(api); data = url.read(); url.close(); return data;
def GET(self, issue_id, r=None): enable_crossdomain() # read config from file. redmine = _config["redmine"] redmine_api_issues = "%s://%s:%s@%s:%s/%s" % ( redmine["protocol"], redmine["username"], redmine["password"], redmine["host"], redmine["port"], redmine["path"]) # proxy for redmine issues # 1. must Enable the RESTful api: http://www.redmine.org/projects/redmine/wiki/Rest_api#Authentication # 2. add a user, username="******", password="******", add to report user, which can access the issues. api = "%s/%s.json" % (redmine_api_issues, issue_id) trace(api) url = urllib.urlopen(api) data = url.read() url.close() return data
def do_email_to(self, user_id, user_name, email, date): if email is None: error("ignore the empty email for user %s(%s)"%(user_name, user_id)); return True; mail = _config["mail"]; # generate subject subject = mail["subject"]; content = mail["content"]; # generate content subject = subject.replace("{user_name}", user_name).replace("{date}", date); content = content.replace("{user_id}", str(user_id)); # do email. if not send_mail(mail["smtp_server"], mail["username"], mail["password"], [email], mail["cc_user"], subject, content): trace("email to %s(%s) id=%s failed"%(user_name, email, user_id)); return False; trace("email to %s(%s) id=%s success"%(user_name, email, user_id)); return True;
def crossdomain_session(*args, **kwargs): # to generate the query string. # the on_start_resource handler have not parse the query string. cherrypy.request.process_query_string(); # reload session id if request contains api_key session_id. if "api_key" in cherrypy.request.params: # get the origin session id origin_session_id = ""; if "session_id" in cherrypy.request.cookie: origin_session_id = cherrypy.request.cookie["session_id"]; # update session id session_id = cherrypy.request.params["api_key"]; # remove the session_id in query_string cherrypy.request.params.clear(); cherrypy.request.query_string = cherrypy.request.query_string.replace("api_key="+session_id, ""); # hack cookie. cherrypy.request.cookie["session_id"] = session_id; trace("hack cookie session %s to %s"%(origin_session_id, session_id));
def qq_oauth_access(self, access_token): auth = _config["auth"]; # https://graph.qq.com/oauth2.0/me?access_token=QE9894RYY787767676G8G87G90980D0D api = "%s?access_token=%s"%(auth["qq_oauth_api_me"], access_token); trace("validate access_token from %s"%(api)); # query qq_oauth_openid url = urllib.urlopen(api); data = url.read(); url.close(); json_data = data.strip().strip("callback").strip("(").strip(";").strip(")").strip(); trace("trim me data to %s"%(json_data)); try: res_json = json.loads(json_data); except Exception,e: error(sys.exc_info); return json.dumps({"code":ErrorCode.Failed, "error":ErrorCode.Failed, "error_description":"qq_oauth_openid to json error"});
def qq_oauth_auto_register(self, access_token, qq_oauth_openid): auth = _config["auth"]; # https://graph.qq.com/user/get_user_info?access_token=71871H1H3187I31EQJK3197J3JWQ8Q0D&appid=8373636744&openid=87JDD73KH32W3983JIUDS92198DS5B32 # get user nickname as user_name, email empty api = "%s?access_token=%s&appid=%s&openid=%s"%(auth["qq_oauth_api_get_user_info"], access_token, auth["qq_oauth_api_app_id"], qq_oauth_openid); trace("auto register get user_info from %s"%(api)); # query qq_oauth_openid url = urllib.urlopen(api); data = url.read(); url.close(); json_data = data.strip().strip("callback").strip("(").strip(";").strip(")").strip(); trace("trim get_user_info data to %s"%(json_data)); try: res_json = json.loads(json_data); except Exception,e: error("ex=%s, info=%s"%(e, traceback.format_exc())); return json.dumps({"code":ErrorCode.Failed, "error":ErrorCode.Failed, "error_description":"userinfo to json error"});
def check_auth(*args, **kwargs): # auth not enabled in config. auth = _config["auth"]; if not auth["on"]: return; # method donot require check. conditions = cherrypy.request.config.get('auth.require', None) if conditions is None: return; # QQ-OAuth not enabled. if auth["strategy"] == "qq_oauth": trace("check session, session_id=%s"%(cherrypy.session.id)); # check QQ-OAuth session. user_id = cherrypy.session.get(SESSION_KEY); if user_id is None: error("session invalid, check auth failed."); enable_crossdomain(); raise cherrypy.HTTPError(401, "You are not authorized, login please."); return; # check user enabled. if True: user_id = cherrypy.session.get(SESSION_KEY); trace("check whether user enabled. id=%s"%(user_id)); records = sql_exec("select user_id from dr_user where user_id='%s' and enabled=true",(user_id)); if len(records) <= 0: error("user disabled, id=%s."%(user_id)); enable_crossdomain(); raise cherrypy.HTTPError(401, "You are disabled"); return; # check condition. for condition in conditions: if not condition(): error("codition check invalid, check auth failed."); enable_crossdomain(); raise cherrypy.HTTPError(401, "You are not authorized for specified condition"); return; trace("check auth success. user_id=%s"%(user_id));
def handle_SIGUSR2(): trace("get SIGUSR2, reload config."); _config = do_reload(); cherrypy.engine.restart();
class RESTAuth(object): exposed = True def qq_oauth_query_available_associate_user(self, access_token, qq_oauth_openid): # query all un-associated users. users = [] records = sql_exec( "select user_id,user_name from dr_user where " "user_id not in (select user_id from dr_authenticate) " "and enabled=true") for record in records: users.append({ "id": record["user_id"], "value": record["user_name"] }) return json.dumps({ "code": ErrorCode.NotAssociated, "error": ErrorCode.NotAssociated, "access_token": access_token, "qq_oauth_openid": qq_oauth_openid, "users": users, "error_description": "user not found, please associate one" }) def qq_oauth_get_associated(self, qq_oauth_openid): return sql_exec( "select u.user_id,u.user_name from dr_user u, dr_authenticate a " "where u.enabled=true and u.user_id=a.user_id and a.qq_oauth_openid=%s", (qq_oauth_openid)) def qq_oauth_auto_register(self, access_token, qq_oauth_openid): auth = _config["auth"] # https://graph.qq.com/user/get_user_info?access_token=71871H1H3187I31EQJK3197J3JWQ8Q0D&appid=8373636744&openid=87JDD73KH32W3983JIUDS92198DS5B32 # get user nickname as user_name, email empty api = "%s?access_token=%s&appid=%s&openid=%s" % ( auth["qq_oauth_api_get_user_info"], access_token, auth["qq_oauth_api_app_id"], qq_oauth_openid) trace("auto register get user_info from %s" % (api)) # query qq_oauth_openid url = urllib.urlopen(api) data = url.read() url.close() json_data = data.strip().strip("callback").strip("(").strip(";").strip( ")").strip() trace("trim get_user_info data to %s" % (json_data)) try: res_json = json.loads(json_data) except Exception, e: error("ex=%s, info=%s" % (e, traceback.format_exc())) return json.dumps({ "code": ErrorCode.Failed, "error": ErrorCode.Failed, "error_description": "userinfo to json error" }) # check userinfo if "error" in res_json: return json.dumps({ "code": ErrorCode.Failed, "error": ErrorCode.Failed, "error_description": "request userinfo error, response=%s" % (data) }) if "nickname" not in res_json: return json.dumps({ "code": ErrorCode.Failed, "error": ErrorCode.Failed, "error_description": "request nickname invalid, response=%s" % (data) }) nickname = res_json["nickname"] trace("nickname=%s access_token=%s qq_oauth_openid=%s" % (nickname, access_token, qq_oauth_openid)) # check exists. user_name = nickname records = sql_exec( "select user_id from dr_user where user_name=%s and enabled=true", (user_name)) # exists, change nickname with random postfix. if len(records) != 0: user_name = "%s%s" % (nickname, int(random.random() * 1000000)) # register user sql_exec("insert into dr_user(user_name) values(%s)", (user_name)) records = sql_exec("select user_id from dr_user where user_name=%s", (user_name)) user_id = records[0]["user_id"] trace( "auto insert user, access_token=%s, qq_oauth_openid=%s, user_id=%s" % (access_token, qq_oauth_openid, user_id)) self.qq_oauth_register_associate(access_token, qq_oauth_openid, user_id)
def handle_SIGUSR2(): trace("get SIGUSR2, reload config.") _config = do_reload() cherrypy.engine.restart()
"error": ErrorCode.Failed, "error_description": "request qq_oauth_openid error, response=%s" % (data) }) if "openid" not in res_json: return json.dumps({ "code": ErrorCode.Failed, "error": ErrorCode.Failed, "error_description": "request qq_oauth_openid invalid, response=%s" % (data) }) qq_oauth_openid = res_json["openid"] trace("qq_oauth_openid=%s access_token=%s" % (qq_oauth_openid, access_token)) return self.qq_oauth_cache_qq_oauth_openid(access_token, qq_oauth_openid) def qq_oauth_associate(self, req_json): access_token = req_json["access_token"] qq_oauth_openid = req_json["qq_oauth_openid"] user_id = req_json["user"] self.qq_oauth_register_associate(access_token, qq_oauth_openid, user_id) qq_oauth_openid = qq_oauth_openid return self.qq_oauth_cache_qq_oauth_openid(access_token, qq_oauth_openid)
json_data = data.strip().strip("callback").strip("(").strip(";").strip(")").strip(); trace("trim me data to %s"%(json_data)); try: res_json = json.loads(json_data); except Exception,e: error(sys.exc_info); return json.dumps({"code":ErrorCode.Failed, "error":ErrorCode.Failed, "error_description":"qq_oauth_openid to json error"}); # check qq_oauth_openid if "error" in res_json: return json.dumps({"code":ErrorCode.Failed, "error":ErrorCode.Failed, "error_description":"request qq_oauth_openid error, response=%s"%(data)}); if "openid" not in res_json: return json.dumps({"code":ErrorCode.Failed, "error":ErrorCode.Failed, "error_description":"request qq_oauth_openid invalid, response=%s"%(data)}); qq_oauth_openid = res_json["openid"]; trace("qq_oauth_openid=%s access_token=%s"%(qq_oauth_openid, access_token)); return self.qq_oauth_cache_qq_oauth_openid(access_token, qq_oauth_openid); def qq_oauth_associate(self, req_json): access_token = req_json["access_token"]; qq_oauth_openid = req_json["qq_oauth_openid"]; user_id = req_json["user"]; self.qq_oauth_register_associate(access_token, qq_oauth_openid, user_id); qq_oauth_openid = qq_oauth_openid; return self.qq_oauth_cache_qq_oauth_openid(access_token, qq_oauth_openid); def GET(self, access_token, r=None): enable_crossdomain();
def qq_oauth_register_associate(self, access_token, qq_oauth_openid, user_id): sql_exec("delete from dr_authenticate where user_id=%s and qq_oauth_openid=%s", (user_id, qq_oauth_openid)); sql_exec("insert into dr_authenticate (user_id, qq_oauth_openid, qq_oauth_access_token) values(%s, %s, %s)", (user_id, qq_oauth_openid, access_token)); trace("associate user id=%s to auth qq_oauth_openid=%s access_token=%s"%(user_id, qq_oauth_openid, access_token));