def add_or_edit_group(): params = request.form if request.form else request.args if "group_name" in params: member_user_ids = set() admin_user_ids = set() admin_user_ids.add( g.user_session.user_id ) #ZS: Always add the user creating the group as an admin if "admin_emails_to_add" in params: admin_emails = params['admin_emails_to_add'].split(",") for email in admin_emails: user_details = get_user_by_unique_column( "email_address", email) if user_details: admin_user_ids.add(user_details['user_id']) #send_group_invites(params['group_id'], user_email_list = admin_emails, user_type="admins") if "member_emails_to_add" in params: member_emails = params['member_emails_to_add'].split(",") for email in member_emails: user_details = get_user_by_unique_column( "email_address", email) if user_details: member_user_ids.add(user_details['user_id']) #send_group_invites(params['group_id'], user_email_list = user_emails, user_type="members") create_group(list(admin_user_ids), list(member_user_ids), params['group_name']) return redirect(url_for('manage_groups')) else: return render_template("admin/create_group.html")
def password_reset(): """Entry point after user clicks link in E-mail""" logger.debug("in password_reset request.url is:", request.url) # We do this mainly just to assert that it's in proper form for displaying next page # Really not necessary but doesn't hurt # user_encode = DecodeUser(ForgotPasswordEmail.key_prefix).reencode_standalone() verification_code = request.args.get('code') hmac = request.args.get('hm') if verification_code: user_email = check_verification_code(verification_code) if user_email: user_details = get_user_by_unique_column('email_address', user_email) if user_details: return render_template("new_security/password_reset.html", user_encode=user_details["user_id"]) else: flash("Invalid code: User no longer exists!", "error") else: flash( "Invalid code: Password reset code does not exist or might have expired!", "error") else: return redirect(url_for("login"))
def send_group_invites(group_id, user_email_list=[], user_type="members"): for user_email in user_email_list: user_details = get_user_by_unique_column("email_address", user_email) if user_details: group_info = get_group_info(group_id) #ZS: Probably not necessary since the group should normally always exist if group_id is being passed here, # but it's technically possible to hit it if Redis is cleared out before submitting the new users or something if group_info: #ZS: Don't add user if they're already an admin or if they're being added a regular user and are already a regular user, # but do add them if they're a regular user and are added as an admin if (user_details['user_id'] in group_info['admins']) or \ ((user_type == "members") and (user_details['user_id'] in group_info['members'])): continue else: send_verification_email( user_details, template_name="email/group_verification.txt", key_prefix="verification_code", subject= "You've been invited to join a GeneNetwork user group") else: temp_password = ''.join( random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) user_details = { 'user_id': str(uuid.uuid4()), 'email_address': user_email, 'registration_info': basic_info(), 'password': set_password(temp_password), 'confirmed': 0 } save_user(user_details, user_details['user_id']) send_invitation_email(user_email, temp_password)
def manage_resource(): params = request.form if request.form else request.args if 'resource_id' in request.args: resource_id = request.args['resource_id'] admin_status = check_owner_or_admin(resource_id=resource_id) resource_info = get_resource_info(resource_id) group_masks = resource_info['group_masks'] group_masks_with_names = get_group_names(group_masks) default_mask = resource_info['default_mask']['data'] owner_id = resource_info['owner_id'] owner_display_name = None if owner_id != "none": owner_info = get_user_by_unique_column("user_id", owner_id) if 'name' in owner_info: owner_display_name = owner_info['full_name'] elif 'user_name' in owner_info: owner_display_name = owner_info['user_name'] elif 'email_address' in owner_info: owner_display_name = owner_info['email_address'] return render_template("admin/manage_resource.html", owner_name=owner_display_name, resource_id=resource_id, resource_info=resource_info, default_mask=default_mask, group_masks=group_masks_with_names, admin_status=admin_status)
def manage_user(): params = request.form if request.form else request.args if 'new_full_name' in params: set_user_attribute(g.user_session.user_id, 'full_name', params['new_full_name']) if 'new_organization' in params: set_user_attribute(g.user_session.user_id, 'organization', params['new_organization']) user_details = get_user_by_unique_column("user_id", g.user_session.user_id) return render_template("admin/manage_user.html", user_details=user_details)
def view_group(): params = request.form if request.form else request.args group_id = params['id'] group_info = get_group_info(group_id) admins_info = [] user_is_admin = False if g.user_session.user_id in group_info['admins']: user_is_admin = True for user_id in group_info['admins']: if user_id: user_info = get_user_by_unique_column("user_id", user_id) admins_info.append(user_info) members_info = [] for user_id in group_info['members']: if user_id: user_info = get_user_by_unique_column("user_id", user_id) members_info.append(user_info) #ZS: This whole part might not scale well with many resources resources_info = [] all_resources = get_resources() for resource_id in all_resources: resource_info = get_resource_info(resource_id) group_masks = resource_info['group_masks'] if group_id in group_masks: this_resource = {} privileges = group_masks[group_id] this_resource['id'] = resource_id this_resource['name'] = resource_info['name'] this_resource['data'] = privileges['data'] this_resource['metadata'] = privileges['metadata'] this_resource['admin'] = privileges['admin'] resources_info.append(this_resource) return render_template("admin/view_group.html", group_info=group_info, admins=admins_info, members=members_info, user_is_admin=user_is_admin, resources=resources_info)
def oauth2_login(self, login_type, user_id): """Login via an OAuth2 provider""" user_details = get_user_by_unique_column("user_id", user_id) if user_details: user = model.User() user.id = user_details["user_id"] if user_details[ "user_id"] == None else "N/A" user.full_name = user_details["name"] user.login_type = user_details["login_type"] return self.actual_login(user) else: flash("Error logging in via OAuth2") return make_response(redirect(url_for('login')))
def __init__(self, kw): self.thank_you_mode = False self.errors = [] self.user = Bunch() self.user.email_address = kw.get('email_address', '').encode("utf-8").strip() if not (5 <= len(self.user.email_address) <= 50): self.errors.append( 'Email Address needs to be between 5 and 50 characters.') else: email_exists = get_user_by_unique_column("email_address", self.user.email_address) #email_exists = get_user_by_unique_column(es, "email_address", self.user.email_address) if email_exists: self.errors.append('User already exists with that email') self.user.full_name = kw.get('full_name', '').encode("utf-8").strip() if not (5 <= len(self.user.full_name) <= 50): self.errors.append( 'Full Name needs to be between 5 and 50 characters.') self.user.organization = kw.get('organization', '').encode("utf-8").strip() if self.user.organization and not (5 <= len(self.user.organization) <= 50): self.errors.append( 'Organization needs to be empty or between 5 and 50 characters.' ) password = str(kw.get('password', '')) if not (6 <= len(password)): self.errors.append('Password needs to be at least 6 characters.') if kw.get('password_confirm') != password: self.errors.append("Passwords don't match.") if self.errors: return logger.debug("No errors!") set_password(password, self.user) self.user.user_id = str(uuid.uuid4()) self.user.confirmed = 1 self.user.registration_info = json.dumps(basic_info(), sort_keys=True) save_user(self.user.__dict__, self.user.user_id)
def github_oauth2(): from utility.tools import GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_AUTH_URL code = request.args.get("code") data = { "client_id": GITHUB_CLIENT_ID, "client_secret": GITHUB_CLIENT_SECRET, "code": code } result = requests.post("https://github.com/login/oauth/access_token", json=data) result_dict = { arr[0]: arr[1] for arr in [ tok.split("=") for tok in [token.encode("utf-8") for token in result.text.split("&")] ] } github_user = get_github_user_details(result_dict["access_token"]) user_details = get_user_by_unique_column("github_id", github_user["id"]) if user_details == None: user_details = { "user_id": str(uuid.uuid4()), "name": github_user["name"].encode("utf-8") if github_user["name"] else "None", "github_id": github_user["id"], "user_url": github_user["html_url"].encode("utf-8"), "login_type": "github", "organization": "", "active": 1, "confirmed": 1 } save_user(user_details, user_details["user_id"]) url = "/n/login?type=github&uid=" + user_details["user_id"] return redirect(url)
def orcid_oauth2(): from uuid import uuid4 from utility.tools import ORCID_CLIENT_ID, ORCID_CLIENT_SECRET, ORCID_TOKEN_URL, ORCID_AUTH_URL code = request.args.get("code") error = request.args.get("error") url = "/n/login" if code: data = { "client_id": ORCID_CLIENT_ID, "client_secret": ORCID_CLIENT_SECRET, "grant_type": "authorization_code", "redirect_uri": GN2_BRANCH_URL + "n/login/orcid_oauth2", "code": code } result = requests.post(ORCID_TOKEN_URL, data=data) result_dict = json.loads(result.text.encode("utf-8")) user_details = get_user_by_unique_column("orcid", result_dict["orcid"]) if user_details == None: user_details = { "user_id": str(uuid4()), "name": result_dict["name"], "orcid": result_dict["orcid"], "user_url": "%s/%s" % ("/".join( ORCID_AUTH_URL.split("/")[:-2]), result_dict["orcid"]), "login_type": "orcid", "organization": "", "active": 1, "confirmed": 1 } save_user(user_details, user_details["user_id"]) url = "/n/login?type=orcid&uid=" + user_details["user_id"] else: flash("There was an error getting code from ORCID") return redirect(url)
def register_user(params): thank_you_mode = False errors = [] user_details = {} user_details['email_address'] = params.get('email_address', '').encode("utf-8").strip() if not (5 <= len(user_details['email_address']) <= 50): errors.append('Email Address needs to be between 5 and 50 characters.') else: email_exists = get_user_by_unique_column("email_address", user_details['email_address']) if email_exists: errors.append('User already exists with that email') user_details['full_name'] = params.get('full_name', '').encode("utf-8").strip() if not (5 <= len(user_details['full_name']) <= 50): errors.append('Full Name needs to be between 5 and 50 characters.') user_details['organization'] = params.get('organization', '').encode("utf-8").strip() if user_details['organization'] and not (5 <= len( user_details['organization']) <= 50): errors.append( 'Organization needs to be empty or between 5 and 50 characters.') password = str(params.get('password', '')) if not (6 <= len(password)): errors.append('Password needs to be at least 6 characters.') if params.get('password_confirm') != password: errors.append("Passwords don't match.") user_details['password'] = set_password(password) user_details['user_id'] = str(uuid.uuid4()) user_details['confirmed'] = 1 user_details['registration_info'] = basic_info() if len(errors) == 0: save_user(user_details, user_details['user_id']) return errors
def forgot_password_submit(): """When a forgotten password form is submitted we get here""" params = request.form email_address = params['email_address'] next_page = None if email_address != "": logger.debug("Wants to send password E-mail to ", email_address) user_details = get_user_by_unique_column("email_address", email_address) if user_details: ForgotPasswordEmail(user_details["email_address"]) return render_template("new_security/forgot_password_step2.html", subject=ForgotPasswordEmail.subject) else: flash("The e-mail entered is not associated with an account.", "alert-danger") return redirect(url_for("forgot_password")) else: flash("You MUST provide an email", "alert-danger") return redirect(url_for("forgot_password"))
def password_reset(): """Entry point after user clicks link in E-mail""" logger.debug("in password_reset request.url is:", request.url) verification_code = request.args.get('code') hmac = request.args.get('hm') if verification_code: user_email = check_verification_code(verification_code) if user_email: user_details = get_user_by_unique_column('email_address', user_email) if user_details: return render_template( "new_security/password_reset.html", user_encode=user_details["email_address"]) else: flash("Invalid code: User no longer exists!", "error") else: flash( "Invalid code: Password reset code does not exist or might have expired!", "error") else: return redirect(url_for("login"))
def standard_login(self): """Login through the normal form""" params = request.form if request.form else request.args logger.debug("in login params are:", params) if not params: from utility.tools import GITHUB_AUTH_URL, GITHUB_CLIENT_ID, ORCID_AUTH_URL, ORCID_CLIENT_ID external_login = {} if GITHUB_AUTH_URL and GITHUB_CLIENT_ID != 'UNKNOWN': external_login["github"] = GITHUB_AUTH_URL if ORCID_AUTH_URL and ORCID_CLIENT_ID != 'UNKNOWN': external_login["orcid"] = ORCID_AUTH_URL return render_template("new_security/login_user.html", external_login=external_login, redis_is_available=is_redis_available()) else: user_details = get_user_by_unique_column("email_address", params["email_address"]) #user_details = get_user_by_unique_column(es, "email_address", params["email_address"]) user = None valid = None if user_details: user = model.User() for key in user_details: user.__dict__[key] = user_details[key] valid = False submitted_password = params['password'] pwfields = Struct(json.loads(user.password)) encrypted = Password(submitted_password, pwfields.salt, pwfields.iterations, pwfields.keylength, pwfields.hashfunc) logger.debug("\n\nComparing:\n{}\n{}\n".format( encrypted.password, pwfields.password)) valid = pbkdf2.safe_str_cmp(encrypted.password, pwfields.password) logger.debug("valid is:", valid) if valid and not user.confirmed: VerificationEmail(user) return render_template( "new_security/verification_still_needed.html", subject=VerificationEmail.subject) if valid: if params.get('remember'): logger.debug("I will remember you") self.remember_me = True if 'import_collections' in params: import_col = "true" else: import_col = "false" #g.cookie_session.import_traits_to_user() self.logged_in = True return self.actual_login(user, import_collections=import_col) else: if user: self.unsuccessful_login(user) flash("Invalid email-address or password. Please try again.", "alert-danger") response = make_response(redirect(url_for('login'))) return response
def login(): params = request.form if request.form else request.args logger.debug("in login params are:", params) if not params: #ZS: If coming to page for first time from utility.tools import GITHUB_AUTH_URL, GITHUB_CLIENT_ID, ORCID_AUTH_URL, ORCID_CLIENT_ID external_login = {} if GITHUB_AUTH_URL and GITHUB_CLIENT_ID != 'UNKNOWN': external_login["github"] = GITHUB_AUTH_URL if ORCID_AUTH_URL and ORCID_CLIENT_ID != 'UNKNOWN': external_login["orcid"] = ORCID_AUTH_URL return render_template("new_security/login_user.html", external_login=external_login, redis_is_available=is_redis_available()) else: #ZS: After clicking sign-in if 'type' in params and 'uid' in params: user_details = get_user_by_unique_column("user_id", params['uid']) if user_details: session_id_signed = get_signed_session_id(user_details) if 'name' in user_details and user_details['name'] != "None": display_id = user_details['name'] elif 'github_id' in user_details: display_id = user_details['github_id'] elif 'orcid' in user_details: display_id = user_details['orcid'] else: display_id = "" flash("Thank you for logging in {}.".format(display_id), "alert-success") response = make_response(redirect(url_for('index_page'))) response.set_cookie(UserSession.user_cookie_name, session_id_signed, max_age=None) else: flash("Something went unexpectedly wrong.", "alert-danger") response = make_response(redirect(url_for('index_page'))) return response else: user_details = get_user_by_unique_column("email_address", params['email_address']) password_match = False if user_details: submitted_password = params['password'] pwfields = user_details['password'] if isinstance(pwfields, str): pwfields = json.loads(pwfields) encrypted_pass_fields = encode_password( pwfields, submitted_password) password_match = pbkdf2.safe_str_cmp( encrypted_pass_fields['password'], pwfields['password']) else: # Invalid e-mail flash("Invalid e-mail address. Please try again.", "alert-danger") response = make_response(redirect(url_for('login'))) return response if password_match: # If password correct if user_details['confirmed']: # If account confirmed import_col = "false" anon_id = "" if 'import_collections' in params: import_col = "true" anon_id = params['anon_id'] session_id_signed = get_signed_session_id(user_details) flash( "Thank you for logging in {}.".format( user_details['full_name']), "alert-success") response = make_response( redirect( url_for('index_page', import_collections=import_col, anon_id=anon_id))) response.set_cookie(UserSession.user_cookie_name, session_id_signed, max_age=None) return response else: email_ob = send_verification_email( user_details, template_name="email/user_verification.txt") return render_template( "newsecurity/verification_still_needed.html", subject=email_ob['subject']) else: # Incorrect password #ZS: It previously seemed to store that there was an incorrect log-in attempt here, but it did so in the MySQL DB so this might need to be reproduced with Redis flash("Invalid password. Please try again.", "alert-danger") response = make_response(redirect(url_for('login'))) return response