def settings_oauth_token_exchange(actor, code): settings = system_settings.get_system_settings() log.debug(settings) url = "https://accounts.google.com/o/oauth2/token" payload = urllib.urlencode({ "code": code, "client_id": settings["oauth2_google_client_id"], "client_secret": settings["oauth2_google_client_secret"], "redirect_uri": "http://%s/settings/oauth/token" % settings["host"], "grant_type": "authorization_code", "scope": "" }) response = urlfetch.fetch(url, payload=payload, method=urlfetch.POST) if response.status_code >= 400: log.debug(response.status_code) log.debug(response.content) raise Exception() result = json.loads(response.content) system_settings.save_system_settings(actor, \ { 'oauth2_google_request_token': str(result["refresh_token"]) })
def get_access_token_header(settings=None): settings = settings or system_settings.get_system_settings() if not "oauth2_google_client_id" in settings: raise Exception("OAuth2 Client ID not set") if not "oauth2_google_client_secret" in settings: raise Exception("OAuth2 Client Secret not set") if not "oauth2_google_request_token" in settings: raise Exception("OAuth2 Request Token not set") url = "https://accounts.google.com/o/oauth2/token" payload = urllib.urlencode({ "client_id": settings["oauth2_google_client_id"], "client_secret": settings["oauth2_google_client_secret"], "grant_type": "refresh_token", "refresh_token": settings["oauth2_google_request_token"] }) result = fetch(url, payload=payload, method=urlfetch.POST) token_type = str(result["token_type"]) access_token = str(result["access_token"]) log.debug("Access Token: %s %s" % (token_type, access_token)) return {'Authorization': "%s %s" % (token_type, access_token)}
def error_report(viewer, url=None, request_code=None, description=None, stack=None, **ignored): settings = system_settings.get_system_settings() sender = viewer.user.email() if "email_admin" in settings: sender = settings["email_admin"] body = "%s\n\nURL: %s\nRequest: %s\n\n%s" % (description, url, request_code, stack) log.debug("Sending Email to Admins from %s:" % sender) log.debug(body) mail.send_mail_to_admins(sender, "Aegis Error - %s" % url, body)
def settings_oauth2_google_url(viewer): settings = system_settings.get_system_settings() scopes = [ "https://www.googleapis.com/auth/admin.directory.user.readonly", "https://www.googleapis.com/auth/admin.directory.group.readonly" ] return "https://accounts.google.com/o/oauth2/auth?%s" % urllib.urlencode( \ { "client_id": settings.get("oauth2_google_client_id"), "redirect_uri": "http://%s/settings/oauth/token" % settings.get("host"), "scope": " ".join(scopes), "response_type": "code", "approval_prompt": "force", "access_type": "offline" })
def refresh_users(actor, force=False, **ignored): settings = system_settings.get_system_settings() if not force and settings.get("directory_sync", "disabled") != "enabled": log.debug("Directory action disabled") return if not "directory_domain" in settings: raise Exception("Directory domain not set") actor = actor or cron_user log.debug("Refreshing user list from directory: %s" % actor) auth_header = get_access_token_header(settings) user_count = 0 alias_count = 0 page_token = "" while (True): result = fetch("https://www.googleapis.com/admin/directory/v1/users?%s" % \ urllib.urlencode({ "domain": settings["directory_domain"], "pageToken": page_token, "maxResults": 500, "fields": "nextPageToken,users/primaryEmail,users/name,users/emails" }), \ headers=auth_header) user_count += len(result["users"]) for user in result["users"]: user_create_or_update(actor, user_id=user["primaryEmail"], first_name=user["name"]["givenName"], last_name=user["name"]["familyName"]) alias_count += len(user["emails"]) for alias in user["emails"]: alias_create(actor, alias_id=alias["address"], user_id=user["primaryEmail"]) if not "nextPageToken" in result: break page_token = result["nextPageToken"] log.debug("Created or updated %s users, %s aliases" % (user_count, alias_count))
def get_access_token_header(settings=None): settings = settings or system_settings.get_system_settings() if not "oauth2_google_client_id" in settings: raise Exception("OAuth2 Client ID not set") if not "oauth2_google_client_secret" in settings: raise Exception("OAuth2 Client Secret not set") if not "oauth2_google_request_token" in settings: raise Exception("OAuth2 Request Token not set") url = "https://accounts.google.com/o/oauth2/token" payload = urllib.urlencode({ "client_id": settings["oauth2_google_client_id"], "client_secret": settings["oauth2_google_client_secret"], "grant_type": "refresh_token", "refresh_token": settings["oauth2_google_request_token"] }) result = fetch(url, payload=payload, method=urlfetch.POST) token_type = str(result["token_type"]) access_token = str(result["access_token"]) log.debug("Access Token: %s %s" % (token_type, access_token)) return { 'Authorization': "%s %s" % (token_type, access_token) }
def settings_load(viewer): return system_settings.get_system_settings()
def refresh_groups(actor, force=False, **ignored): settings = system_settings.get_system_settings() if not force and settings.get("directory_sync", "disabled") != "enabled": log.debug("Directory action disabled") return if not "directory_domain" in settings: raise Exception("Directory domain not set") actor = actor or cron_user log.debug("Refreshing group list from directory: %s" % actor) auth_header = get_access_token_header(settings) group_count = 0 alias_count = 0 member_count = 0 page_token = "" all_groups = {} while (True): result = fetch("https://www.googleapis.com/admin/directory/v1/groups?%s" % \ urllib.urlencode({ "domain": settings["directory_domain"], "pageToken": page_token, "maxResults": 500, "fields": ",".join([ "nextPageToken", "groups/email", "groups/name", "groups/aliases", "groups/id", "groups/directMembersCount" ]) }), \ headers=auth_header) for group in result["groups"]: group_data = { 'email': group["email"], 'name': group["name"], 'aliases': [], 'members': [] } all_groups[group["email"]] = group_data if "aliases" in group: group_data["aliases"] = group["aliases"] log.debug("Getting members of group %s" % group["email"]) if int(group["directMembersCount"]) > 0: member_page_token = "" while (True): member_result = fetch("https://www.googleapis.com/admin/directory/v1/groups/%s/members?%s" % (group["id"], \ urllib.urlencode({ "pageToken": member_page_token, "fields": ",".join([ "nextPageToken", "members/email", "members/type" ]) })), \ headers=auth_header) if "members" in member_result: group_data["members"].extend(member_result["members"]) if not "nextPageToken" in member_result: break member_page_token = member_result["nextPageToken"] if not "nextPageToken" in result: break page_token = result["nextPageToken"] all_users = { user.user.email(): user for user in user_list_raw(actor) } def get_group_members(group_id, members): result = [] for member in members: if member["type"] == "GROUP": if member["email"] in all_groups: result.extend(get_group_members(group_id, all_groups[member["email"]]["members"])) else: log.warn("Could not find group: %s" % member["email"]) elif member["type"] == "USER": if member["email"] in all_users: result.append(all_users[member["email"]]) elif member["type"] == "CUSTOMER": result.extend(all_users.values()) else: log.debug("%s" % member) return result group_count += len(all_groups) for group_name in sorted(all_groups): log.debug("Creating or updating group %s" % group_name) group = all_groups[group_name] group_create_or_update(actor, group_id=group["email"], name=group["name"], active=True) group_obj = build_group_key(group_name).get() alias_create(actor, alias_id=group["email"], group=group_obj) group_members_clear(actor, group=group_obj) alias_count += len(group["aliases"]) + 1 for alias in group["aliases"]: alias_create(actor, alias_id=alias, group=group_obj) for member in get_group_members(group["email"], group["members"]): group_members_add(actor, group=group_obj, user=member) log.debug("Created or updated %s groups, %s aliases, %s members" % (group_count, alias_count, member_count))
def issue_update(actor, issue_id=None, key=None, issue=None, summary=undefined, project=undefined, status=undefined, priority=undefined, severity=undefined, reporters=undefined, assignees=undefined, verifiers=undefined, cc=undefined, depends_on=undefined, blocking=undefined, privacy=undefined, due_date=undefined, body="", send_mail=True, blobs=undefined, **args): issue = issue or (key or issue_key(issue_id)).get() header = "" is_root = permission_is_root(actor) if not is_root and issue.privacy != "public" and \ build_user_key(actor) not in issue.cc + issue.assignees + issue.reporters + issue.verifiers: raise NotAllowedError() blob_list = None to_recipients = set([]) if issue.assignees: to_recipients.update(issue.assignees) if issue.reporters: to_recipients.update(issue.reporters) if issue.verifiers: to_recipients.update(issue.verifiers) cc_recipients = set(issue.cc) if is_root or issue.privacy != "secure" or build_user_key( actor) in issue.assignees + issue.verifiers: # Rewrite input types if necessary def fix_users(field): log.debug(field) if is_undefined(field): return undefined if not field: return undefined if isinstance(field, basestring): return set([ build_user_key(id) for id in re.split("[\\s,;]+", field) if len(id) > 0 ]) return [build_user_key(user) for user in field] reporters = fix_users(reporters) assignees = fix_users(assignees) verifiers = fix_users(verifiers) cc = fix_users(cc) if is_defined(depends_on): depends_on = set([ issue_key(id) for id in re.split("[\\s,;]+", depends_on) if len(id) > 0 ]) if is_defined(blocking): blocking = set([ issue_key(id) for id in re.split("[\\s,;]+", blocking) if len(id) > 0 ]) if is_defined(due_date): if due_date == "": due_date = None else: if "timezoneoffset" in args: offset = datetime.timedelta( minutes=int(args["timezoneoffset"])) client_time = datetime.datetime.utcnow() - offset parsed_time = lib.parsedatetime.Calendar().parse( due_date, client_time) log.debug("client_time = %s" % client_time) else: offset = datetime.timedelta(0) parsed_time = lib.parsedatetime.Calendar().parse(due_date) if parsed_time[1] == 1: due_date = datetime.datetime(*parsed_time[0][:3]) + offset else: due_date = datetime.datetime(*parsed_time[0][:6]) + offset # Update all fields if is_defined(summary) and summary != issue.summary: header = header + "**Summary:** " + summary + " \n" issue.summary = summary issue.summary_index = set(re.split("[^\\w\\d]+", summary.lower())) if is_defined(project) and project != issue.project: header = header + "**Project:** " + project + " \n" issue.project = project if is_defined(status) and status != issue.status: if not status in issue_transitions: raise IllegalError("Status not recognized") if not status in issue_transitions[issue.status]: raise IllegalError("Status transition not allowed") header = header + "**Status:** " + status + " \n" issue.status = status if is_defined(priority) and int(priority) != issue.priority: header = header + "**Priority:** " + str(priority) + " \n" issue.priority = int(priority) if is_defined(severity) and int(severity) != issue.severity: header = header + "**Severity:** " + str(severity) + " \n" issue.severity = int(severity) if is_defined(reporters) and reporters != set(issue.reporters): log.debug("Reporters: %s" % reporters) header = header + "**Reporters:** " + ", ".join( [user.id() for user in reporters]) + " \n" issue.reporters = reporters if is_defined(assignees) and assignees != set(issue.assignees): header = header + "**Assignees:** " + ", ".join( [user.id() for user in assignees]) + " \n" issue.assignees = assignees if is_defined(verifiers) and verifiers != set(issue.verifiers): header = header + "**Verifiers:** " + ", ".join( [user.id() for user in verifiers]) + " \n" issue.verifiers = verifiers if is_defined(cc) and cc != set(issue.cc): header = header + "**CC:** " + ", ".join( [user.id() for user in cc]) + " \n" issue.cc = list(cc) if is_defined(depends_on) and depends_on != set(issue.depends_on): header = header + "**Depends On:** " + ", ".join( [str(iss.id()) for iss in depends_on]) + " \n" issue.depends_on = list(depends_on) if is_defined(blocking) and blocking != set(issue.blocking): header = header + "**Blocking:** " + ", ".join( [str(iss.id()) for iss in blocking]) + " \n" issue.blocking = list(blocking) if is_defined(privacy) and privacy != issue.privacy: header = header + "**Privacy:** " + privacy + " \n" issue.privacy = privacy if is_defined(due_date) and due_date != issue.due_date: header = header + "**Due Date:** " + str(due_date) + " UTC \n" issue.due_date = due_date if is_defined(blobs) and blobs: blob_list = build_blob_keys(blobs) header = header + "**Attachments:** %s File(s) \n" % len( blob_list) # Fix up missing stuff if not issue.reporters: issue.reporters = [build_user_key(actor)] if not issue.verifiers: issue.verifiers = [build_user_key(actor)] if not issue.assignees: issue.assignees = [build_user_key(actor)] to_recipients.update(issue.assignees) to_recipients.update(issue.reporters) to_recipients.update(issue.verifiers) cc_recipients.update(issue.cc) issue.score, issue.score_description = calculate_issue_score(issue) issue.text_index = set(issue.text_index) | \ set(issue.summary_index) | \ set(re.split("[^\\w\\d]+", body.lower())) issue.updated_by = build_user_key(actor) issue.put() issue.history = [ remark_create(actor, issue.key, body.strip(), header.strip(), blobs=blob_list) ] if send_mail: settings = get_system_settings() if "host" in settings and settings["host"] and settings["host"] != "": host = settings["host"] else: host = "%s.appspot.com" % app_identity.get_application_id() message_id = "<issue-%s@%s>" % (issue.key.id(), app_identity.get_application_id()) url = "http://%s/issues/%s" % (host, issue.key.id()) text = "%s\n\n%s\n\n%s" % (header, body, url) html = "<div style='font-size: 0.8em'>%s</div><div>%s</div><div>%s</div>" % \ (lib.markdown.markdown(header), lib.markdown.markdown(body), url) try: if len(cc_recipients) > 0: mail.send_mail(sender=actor.user.email(), to=[user.id() for user in to_recipients], cc=[user.id() for user in cc_recipients], reply_to=actor.user.email(), subject="[" + str(issue.key.id()) + "] " + issue.summary, body=text, html=html, headers={ "In-Reply-To": message_id, "References": message_id }) else: mail.send_mail(sender=actor.user.email(), to=[user.id() for user in to_recipients], reply_to=actor.user.email(), subject="[" + str(issue.key.id()) + "] " + issue.summary, body=text, html=html, headers={ "In-Reply-To": message_id, "References": message_id }) log.debug("Email sent to %s" % (to_recipients | cc_recipients)) except: log.warn("Email quota exceeded, email not sent") log.debug(text) return to_model(actor, issue)
def refresh_groups(actor, force=False, **ignored): settings = system_settings.get_system_settings() if not force and settings.get("directory_sync", "disabled") != "enabled": log.debug("Directory action disabled") return if not "directory_domain" in settings: raise Exception("Directory domain not set") actor = actor or cron_user log.debug("Refreshing group list from directory: %s" % actor) auth_header = get_access_token_header(settings) group_count = 0 alias_count = 0 member_count = 0 page_token = "" all_groups = {} while (True): result = fetch("https://www.googleapis.com/admin/directory/v1/groups?%s" % \ urllib.urlencode({ "domain": settings["directory_domain"], "pageToken": page_token, "maxResults": 500, "fields": ",".join([ "nextPageToken", "groups/email", "groups/name", "groups/aliases", "groups/id", "groups/directMembersCount" ]) }), \ headers=auth_header) for group in result["groups"]: group_data = { 'email': group["email"], 'name': group["name"], 'aliases': [], 'members': [] } all_groups[group["email"]] = group_data if "aliases" in group: group_data["aliases"] = group["aliases"] log.debug("Getting members of group %s" % group["email"]) if int(group["directMembersCount"]) > 0: member_page_token = "" while (True): member_result = fetch("https://www.googleapis.com/admin/directory/v1/groups/%s/members?%s" % (group["id"], \ urllib.urlencode({ "pageToken": member_page_token, "fields": ",".join([ "nextPageToken", "members/email", "members/type" ]) })), \ headers=auth_header) if "members" in member_result: group_data["members"].extend(member_result["members"]) if not "nextPageToken" in member_result: break member_page_token = member_result["nextPageToken"] if not "nextPageToken" in result: break page_token = result["nextPageToken"] all_users = {user.user.email(): user for user in user_list_raw(actor)} def get_group_members(group_id, members): result = [] for member in members: if member["type"] == "GROUP": if member["email"] in all_groups: result.extend( get_group_members( group_id, all_groups[member["email"]]["members"])) else: log.warn("Could not find group: %s" % member["email"]) elif member["type"] == "USER": if member["email"] in all_users: result.append(all_users[member["email"]]) elif member["type"] == "CUSTOMER": result.extend(all_users.values()) else: log.debug("%s" % member) return result group_count += len(all_groups) for group_name in sorted(all_groups): log.debug("Creating or updating group %s" % group_name) group = all_groups[group_name] group_create_or_update(actor, group_id=group["email"], name=group["name"], active=True) group_obj = build_group_key(group_name).get() alias_create(actor, alias_id=group["email"], group=group_obj) group_members_clear(actor, group=group_obj) alias_count += len(group["aliases"]) + 1 for alias in group["aliases"]: alias_create(actor, alias_id=alias, group=group_obj) for member in get_group_members(group["email"], group["members"]): group_members_add(actor, group=group_obj, user=member) log.debug("Created or updated %s groups, %s aliases, %s members" % (group_count, alias_count, member_count))
def issue_update(actor, issue_id=None, key=None, issue=None, summary=undefined, project=undefined, status=undefined, priority=undefined, severity=undefined, reporters=undefined, assignees=undefined, verifiers=undefined, cc=undefined, depends_on=undefined, blocking=undefined, privacy=undefined, due_date=undefined, body="", send_mail=True, blobs=undefined, **args): issue = issue or (key or issue_key(issue_id)).get() header = "" is_root = permission_is_root(actor) if not is_root and issue.privacy != "public" and \ build_user_key(actor) not in issue.cc + issue.assignees + issue.reporters + issue.verifiers: raise NotAllowedError() blob_list = None to_recipients = set([]) if issue.assignees: to_recipients.update(issue.assignees) if issue.reporters: to_recipients.update(issue.reporters) if issue.verifiers: to_recipients.update(issue.verifiers) cc_recipients = set(issue.cc) if is_root or issue.privacy != "secure" or build_user_key(actor) in issue.assignees + issue.verifiers: # Rewrite input types if necessary def fix_users(field): log.debug(field) if is_undefined(field): return undefined if not field: return undefined if isinstance(field, basestring): return set([build_user_key(id) for id in re.split("[\\s,;]+", field) if len(id) > 0]) return [build_user_key(user) for user in field] reporters = fix_users(reporters) assignees = fix_users(assignees) verifiers = fix_users(verifiers) cc = fix_users(cc) if is_defined(depends_on): depends_on = set([issue_key(id) for id in re.split("[\\s,;]+", depends_on) if len(id) > 0]) if is_defined(blocking): blocking = set([issue_key(id) for id in re.split("[\\s,;]+", blocking) if len(id) > 0]) if is_defined(due_date): if due_date == "": due_date = None else: if "timezoneoffset" in args: offset = datetime.timedelta(minutes=int(args["timezoneoffset"])) client_time = datetime.datetime.utcnow() - offset parsed_time = lib.parsedatetime.Calendar().parse(due_date, client_time) log.debug("client_time = %s" % client_time) else: offset = datetime.timedelta(0) parsed_time = lib.parsedatetime.Calendar().parse(due_date) if parsed_time[1] == 1: due_date = datetime.datetime(*parsed_time[0][:3]) + offset else: due_date = datetime.datetime(*parsed_time[0][:6]) + offset # Update all fields if is_defined(summary) and summary != issue.summary: header = header + "**Summary:** " + summary + " \n" issue.summary = summary issue.summary_index = set(re.split("[^\\w\\d]+", summary.lower())) if is_defined(project) and project != issue.project: header = header + "**Project:** " + project + " \n" issue.project = project if is_defined(status) and status != issue.status: if not status in issue_transitions: raise IllegalError("Status not recognized") if not status in issue_transitions[issue.status]: raise IllegalError("Status transition not allowed") header = header + "**Status:** " + status + " \n" issue.status = status if is_defined(priority) and int(priority) != issue.priority: header = header + "**Priority:** " + str(priority) + " \n" issue.priority = int(priority) if is_defined(severity) and int(severity) != issue.severity: header = header + "**Severity:** " + str(severity) + " \n" issue.severity = int(severity) if is_defined(reporters) and reporters != set(issue.reporters): log.debug("Reporters: %s" % reporters) header = header + "**Reporters:** " + ", ".join([user.id() for user in reporters]) + " \n" issue.reporters = reporters if is_defined(assignees) and assignees != set(issue.assignees): header = header + "**Assignees:** " + ", ".join([user.id() for user in assignees]) + " \n" issue.assignees = assignees if is_defined(verifiers) and verifiers != set(issue.verifiers): header = header + "**Verifiers:** " + ", ".join([user.id() for user in verifiers]) + " \n" issue.verifiers = verifiers if is_defined(cc) and cc != set(issue.cc): header = header + "**CC:** " + ", ".join([user.id() for user in cc]) + " \n" issue.cc = list(cc) if is_defined(depends_on) and depends_on != set(issue.depends_on): header = header + "**Depends On:** " + ", ".join([str(iss.id()) for iss in depends_on]) + " \n" issue.depends_on = list(depends_on) if is_defined(blocking) and blocking != set(issue.blocking): header = header + "**Blocking:** " + ", ".join([str(iss.id()) for iss in blocking]) + " \n" issue.blocking = list(blocking) if is_defined(privacy) and privacy != issue.privacy: header = header + "**Privacy:** " + privacy + " \n" issue.privacy = privacy if is_defined(due_date) and due_date != issue.due_date: header = header + "**Due Date:** " + str(due_date) + " UTC \n" issue.due_date = due_date if is_defined(blobs) and blobs: blob_list = build_blob_keys(blobs) header = header + "**Attachments:** %s File(s) \n" % len(blob_list) # Fix up missing stuff if not issue.reporters: issue.reporters = [ build_user_key(actor) ] if not issue.verifiers: issue.verifiers = [ build_user_key(actor) ] if not issue.assignees: issue.assignees = [ build_user_key(actor) ] to_recipients.update(issue.assignees) to_recipients.update(issue.reporters) to_recipients.update(issue.verifiers) cc_recipients.update(issue.cc) issue.score, issue.score_description = calculate_issue_score(issue) issue.text_index = set(issue.text_index) | \ set(issue.summary_index) | \ set(re.split("[^\\w\\d]+", body.lower())) issue.updated_by = build_user_key(actor) issue.put() issue.history = [ remark_create(actor, issue.key, body.strip(), header.strip(), blobs=blob_list) ] if send_mail: settings = get_system_settings() if "host" in settings and settings["host"] and settings["host"] != "": host = settings["host"] else: host = "%s.appspot.com" % app_identity.get_application_id() message_id = "<issue-%s@%s>" % (issue.key.id(), app_identity.get_application_id()) url = "http://%s/issues/%s" % (host, issue.key.id()) text = "%s\n\n%s\n\n%s" % (header, body, url) html = "<div style='font-size: 0.8em'>%s</div><div>%s</div><div>%s</div>" % \ (lib.markdown.markdown(header), lib.markdown.markdown(body), url) try: if len(cc_recipients) > 0: mail.send_mail(sender=actor.user.email(), to=[user.id() for user in to_recipients], cc=[user.id() for user in cc_recipients], reply_to=actor.user.email(), subject="[" + str(issue.key.id()) + "] " + issue.summary, body=text, html=html, headers={"In-Reply-To": message_id, "References": message_id }) else: mail.send_mail(sender=actor.user.email(), to=[user.id() for user in to_recipients], reply_to=actor.user.email(), subject="[" + str(issue.key.id()) + "] " + issue.summary, body=text, html=html, headers={"In-Reply-To": message_id, "References": message_id }) log.debug("Email sent to %s" % (to_recipients | cc_recipients)) except: log.warn("Email quota exceeded, email not sent") log.debug(text) return to_model(actor, issue)