def login(request, redirect_field_name=REDIRECT_FIELD_NAME, _form_class=LoginForm): # TODO: Logging in should reset request.user # TODO: Configure the login view as the default view for not having # permission to view something. if request.authenticated_userid is not None: return HTTPSeeOther(request.route_path("manage.projects")) user_service = request.find_service(IUserService, context=None) breach_service = request.find_service(IPasswordBreachedService, context=None) redirect_to = request.POST.get( redirect_field_name, request.GET.get(redirect_field_name) ) form = _form_class( request.POST, request=request, user_service=user_service, breach_service=breach_service, check_password_metrics_tags=["method:auth", "auth_method:login_form"], ) if request.method == "POST": if form.validate(): # Get the user id for the given username. username = form.username.data userid = user_service.find_userid(username) # If the user-originating redirection url is not safe, then # redirect to the index instead. if not redirect_to or not is_safe_url(url=redirect_to, host=request.host): redirect_to = request.route_path("manage.projects") # Actually perform the login routine for our user. headers = _login_user(request, userid) # Now that we're logged in we'll want to redirect the user to # either where they were trying to go originally, or to the default # view. resp = HTTPSeeOther(redirect_to, headers=dict(headers)) # We'll use this cookie so that client side javascript can # Determine the actual user ID (not username, user ID). This is # *not* a security sensitive context and it *MUST* not be used # where security matters. # # We'll also hash this value just to avoid leaking the actual User # IDs here, even though it really shouldn't matter. resp.set_cookie( USER_ID_INSECURE_COOKIE, hashlib.blake2b(str(userid).encode("ascii"), person=b"warehouse.userid") .hexdigest() .lower(), ) return resp return { "form": form, "redirect": {"field": REDIRECT_FIELD_NAME, "data": redirect_to}, }
def login(self): self.csrf_valid() try: schema = s.UserSchema.create_schema(self.request) deserialized = schema.deserialize(self.cstruct) headers = remember(self.request, deserialized['email']) token = self.request.session.new_csrf_token() response = HTTPSeeOther(location=self.request.route_url('main', traverse='user'), headers=headers) response.set_cookie('CSRF-Token', token, max_age=864000, overwrite=True) return response except colander.Invalid as e: self.request.response.status = 422 form_error = None field_errors = e.asdict() if 'email' in field_errors and 'password' in field_errors: if field_errors['email'] == field_errors['password']: form_error = "Username or password is incorrect." return { 'errors': field_errors, 'form_error': form_error, }
def change_language(request): lang = request.matchdict.get('lang') resp = HTTPSeeOther(request.application_url) if lang is None: resp.unset_cookie('_LOCALE_') else: resp.set_cookie('_LOCALE_', lang, max_age=timedelta(days=365)) # max_age = year return resp
def login(request, redirect_field_name=REDIRECT_FIELD_NAME, _form_class=forms.LoginForm): # TODO: Logging in should reset request.user # TODO: Configure the login view as the default view for not having # permission to view something. user_service = request.find_service(IUserService, context=None) redirect_to = request.POST.get(redirect_field_name, request.GET.get(redirect_field_name)) form = _form_class(request.POST, user_service=user_service) if request.method == "POST" and form.validate(): # Get the user id for the given username. username = form.username.data userid = user_service.find_userid(username) # If the user-originating redirection url is not safe, then redirect to # the index instead. if (not redirect_to or not is_safe_url(url=redirect_to, host=request.host)): redirect_to = "/" # Actually perform the login routine for our user. headers = _login_user(request, userid) # Now that we're logged in we'll want to redirect the user to either # where they were trying to go originally, or to the default view. resp = HTTPSeeOther(redirect_to, headers=dict(headers)) # We'll use this cookie so that client side javascript can Determine # the actual user ID (not username, user ID). This is *not* a security # sensitive context and it *MUST* not be used where security matters. # # We'll also hash this value just to avoid leaking the actual User IDs # here, even though it really shouldn't matter. resp.set_cookie( USER_ID_INSECURE_COOKIE, blake2b( str(userid).encode("ascii"), person=b"warehouse.userid", ).hexdigest().lower(), ) return resp return { "form": form, "redirect": { "field": REDIRECT_FIELD_NAME, "data": redirect_to, }, }
def set_color_theme(request): cookie_name = 'color_theme' current = request.cookies.get(cookie_name, 'default') new_theme = request.POST.get('color_theme') response = HTTPSeeOther(request.route_url('preferences')) if new_theme and new_theme != current: cookie_path = '/' # FIXME: not necessarily if new_theme == 'default': response.delete_cookie(cookie_name, path=cookie_path) else: response.set_cookie(cookie_name, new_theme, path=cookie_path) return response
def two_factor(request, _form_class=TwoFactorForm): if request.authenticated_userid is not None: return HTTPSeeOther(request.route_path("manage.projects")) token_service = request.find_service(ITokenService, name="two_factor") try: two_factor_data = token_service.loads(request.query_string) except TokenException: request.session.flash("Invalid or expired two factor login.", queue="error") return HTTPSeeOther(request.route_path("accounts.login")) userid = two_factor_data.get("userid") if not userid: return HTTPSeeOther(request.route_path("accounts.login")) redirect_to = two_factor_data.get("redirect_to") user_service = request.find_service(IUserService, context=None) form = _form_class( request.POST, user_id=userid, user_service=user_service, check_password_metrics_tags=["method:auth", "auth_method:login_form"], ) if request.method == "POST": if form.validate(): # If the user-originating redirection url is not safe, then # redirect to the index instead. if not redirect_to or not is_safe_url(url=redirect_to, host=request.host): redirect_to = request.route_path("manage.projects") _login_user(request, userid) resp = HTTPSeeOther(redirect_to) resp.set_cookie( USER_ID_INSECURE_COOKIE, hashlib.blake2b(str(userid).encode("ascii"), person=b"warehouse.userid") .hexdigest() .lower(), ) return resp return {"form": form}
def logout(request, redirect_field_name=REDIRECT_FIELD_NAME): # TODO: Logging out should reset request.user redirect_to = request.POST.get( redirect_field_name, request.GET.get(redirect_field_name) ) # If the user-originating redirection url is not safe, then redirect to # the index instead. if not redirect_to or not is_safe_url(url=redirect_to, host=request.host): redirect_to = "/" # If we're already logged out, then we'll go ahead and issue our redirect right # away instead of trying to log a non-existent user out. if request.user is None: return HTTPSeeOther(redirect_to) if request.method == "POST": # A POST to the logout view tells us to logout. There's no form to # validate here because there's no data. We should be protected against # CSRF attacks still because of the CSRF framework, so users will still # need a post body that contains the CSRF token. headers = forget(request) # When crossing an authentication boundary we want to create a new # session identifier. We don't want to keep any information in the # session when going from authenticated to unauthenticated because # user's generally expect that logging out is a destructive action # that erases all of their private data. However, if we don't clear the # session then another user can use the computer after them, log in to # their account, and then gain access to anything sensitive stored in # the session for the original user. request.session.invalidate() # Now that we're logged out we'll want to redirect the user to either # where they were originally, or to the default view. resp = HTTPSeeOther(redirect_to, headers=dict(headers)) # Ensure that we delete our user_id__insecure cookie, since the user is # no longer logged in. resp.delete_cookie(USER_ID_INSECURE_COOKIE) return resp return {"redirect": {"field": REDIRECT_FIELD_NAME, "data": redirect_to}}
def delete_project_release_file(self): def _error(message): self.request.session.flash(message, queue="error") return HTTPSeeOther( self.request.route_path( "manage.project.release", project_name=self.release.project.name, version=self.release.version, ) ) if self.request.flags.enabled(AdminFlagValue.DISALLOW_DELETION): message = ( "Project deletion temporarily disabled. " "See https://pypi.org/help#admin-intervention for details." ) return _error(message) project_name = self.request.POST.get("confirm_project_name") if not project_name: return _error("Confirm the request") try: release_file = ( self.request.db.query(File) .filter( File.release == self.release, File.id == self.request.POST.get("file_id"), ) .one() ) except NoResultFound: return _error("Could not find file") if project_name != self.release.project.name: return _error( "Could not delete file - " + f"{project_name!r} is not the same as " f"{self.release.project.name!r}" ) self.request.db.add( JournalEntry( name=self.release.project.name, action=f"remove file {release_file.filename}", version=self.release.version, submitted_by=self.request.user, submitted_from=self.request.remote_addr, ) ) self.release.project.record_event( tag="project:release:file:remove", ip_address=self.request.remote_addr, additional={ "submitted_by": self.request.user.username, "canonical_version": self.release.canonical_version, "filename": release_file.filename, }, ) self.request.db.delete(release_file) self.request.session.flash( f"Deleted file {release_file.filename!r}", queue="success" ) return HTTPSeeOther( self.request.route_path( "manage.project.release", project_name=self.release.project.name, version=self.release.version, ) )
def verify_project_role(request): token_service = request.find_service(ITokenService, name="email") user_service = request.find_service(IUserService, context=None) def _error(message): request.session.flash(message, queue="error") return HTTPSeeOther(request.route_path("manage.projects")) try: token = request.params.get("token") data = token_service.loads(token) except TokenExpired: return _error( request._("Expired token: request a new project role invite")) except TokenInvalid: return _error( request._("Invalid token: request a new project role invite")) except TokenMissing: return _error(request._("Invalid token: no token supplied")) # Check whether this token is being used correctly if data.get("action") != "email-project-role-verify": return _error( request._("Invalid token: not a collaboration invitation token")) user = user_service.get_user(data.get("user_id")) if user != request.user: return _error(request._("Role invitation is not valid.")) project = (request.db.query(Project).filter( Project.id == data.get("project_id")).one()) desired_role = data.get("desired_role") role_invite = (request.db.query(RoleInvitation).filter( RoleInvitation.project == project).filter( RoleInvitation.user == user).one_or_none()) if not role_invite: return _error(request._("Role invitation no longer exists.")) # Use the renderer to bring up a confirmation page # before adding as contributor if request.method == "GET": return { "project_name": project.name, "desired_role": desired_role, } elif request.method == "POST" and "decline" in request.POST: request.db.delete(role_invite) request.session.flash( request._( "Invitation for '${project_name}' is declined.", mapping={"project_name": project.name}, ), queue="success", ) return HTTPSeeOther(request.route_path("manage.projects")) request.db.add(Role(user=user, project=project, role_name=desired_role)) request.db.delete(role_invite) request.db.add( JournalEntry( name=project.name, action=f"accepted {desired_role} {user.username}", submitted_by=request.user, submitted_from=request.remote_addr, )) project.record_event( tag="project:role:accepted", ip_address=request.remote_addr, additional={ "submitted_by": request.user.username, "role_name": desired_role, "target_user": user.username, }, ) user.record_event( tag="account:role:accepted", ip_address=request.remote_addr, additional={ "submitted_by": request.user.username, "project_name": project.name, "role_name": desired_role, }, ) owner_roles = (request.db.query(Role).filter( Role.project == project).filter(Role.role_name == "Owner").all()) owner_users = {owner.user for owner in owner_roles} # Don't send email to new user if they are now an owner owner_users.discard(user) submitter_user = user_service.get_user(data.get("submitter_id")) send_collaborator_added_email( request, owner_users, user=user, submitter=submitter_user, project_name=project.name, role=desired_role, ) send_added_as_collaborator_email( request, user, submitter=submitter_user, project_name=project.name, role=desired_role, ) request.session.flash( request._( "You are now ${role} of the '${project_name}' project.", mapping={ "project_name": project.name, "role": desired_role }, ), queue="success", ) if desired_role == "Owner": return HTTPSeeOther( request.route_path("manage.project.roles", project_name=project.name)) else: return HTTPSeeOther( request.route_path("packaging.project", name=project.name))
def delete_project(project, request): confirm_project(project, request, fail_route="manage.project.settings") remove_project(project, request) return HTTPSeeOther(request.route_path('manage.projects'))
def change_project_role(project, request, _form_class=ChangeRoleForm): # TODO: This view was modified to handle deleting multiple roles for a # single user and should be updated when fixing GH-2745 form = _form_class(request.POST) if form.validate(): role_ids = request.POST.getall("role_id") if len(role_ids) > 1: # This user has more than one role, so just delete all the ones # that aren't what we want. # # TODO: This branch should be removed when fixing GH-2745. roles = (request.db.query(Role).join(User).filter( Role.id.in_(role_ids), Role.project == project, Role.role_name != form.role_name.data, ).all()) removing_self = any( role.role_name == "Owner" and role.user == request.user for role in roles) if removing_self: request.session.flash("Cannot remove yourself as Owner", queue="error") else: for role in roles: request.db.delete(role) request.db.add( JournalEntry( name=project.name, action= f"remove {role.role_name} {role.user.username}", submitted_by=request.user, submitted_from=request.remote_addr, )) project.record_event( tag="project:role:delete", ip_address=request.remote_addr, additional={ "submitted_by": request.user.username, "role_name": role.role_name, "target_user": role.user.username, }, ) request.session.flash("Changed role", queue="success") else: # This user only has one role, so get it and change the type. try: role = (request.db.query(Role).join(User).filter( Role.id == request.POST.get("role_id"), Role.project == project).one()) if role.role_name == "Owner" and role.user == request.user: request.session.flash("Cannot remove yourself as Owner", queue="error") else: request.db.add( JournalEntry( name=project.name, action="change {} {} to {}".format( role.role_name, role.user.username, form.role_name.data), submitted_by=request.user, submitted_from=request.remote_addr, )) role.role_name = form.role_name.data project.record_event( tag="project:role:change", ip_address=request.remote_addr, additional={ "submitted_by": request.user.username, "role_name": form.role_name.data, "target_user": role.user.username, }, ) request.session.flash("Changed role", queue="success") except NoResultFound: request.session.flash("Could not find role", queue="error") return HTTPSeeOther( request.route_path("manage.project.roles", project_name=project.name))
def _error(message): request.session.flash(message, queue="error") return HTTPSeeOther( request.route_path("accounts.request-password-reset"))
def join(group, request): groups_service = request.find_service(name='groups') groups_service.member_join(group, request.authenticated_userid) url = request.route_path('group_read', pubid=group.pubid, slug=group.slug) return HTTPSeeOther(url)
def verify_email(request): token_service = request.find_service(ITokenService, name="email") email_limiter = request.find_service(IRateLimiter, name="email.add") def _error(message): request.session.flash(message, queue="error") return HTTPSeeOther(request.route_path("manage.account")) try: token = request.params.get("token") data = token_service.loads(token) except TokenExpired: return _error( request._("Expired token: request a new email verification link")) except TokenInvalid: return _error( request._("Invalid token: request a new email verification link")) except TokenMissing: return _error(request._("Invalid token: no token supplied")) # Check whether this token is being used correctly if data.get("action") != "email-verify": return _error( request._("Invalid token: not an email verification token")) try: email = (request.db.query(Email).filter( Email.id == data["email.id"], Email.user == request.user).one()) except NoResultFound: return _error(request._("Email not found")) if email.verified: return _error(request._("Email already verified")) email.verified = True email.unverify_reason = None email.transient_bounces = 0 email.user.record_event( tag="account:email:verified", ip_address=request.remote_addr, additional={ "email": email.email, "primary": email.primary }, ) # Reset the email-adding rate limiter for this IP address email_limiter.clear(request.remote_addr) if not email.primary: confirm_message = request._( "You can now set this email as your primary address") else: confirm_message = request._("This is your primary address") request.user.is_active = True request.session.flash( request._( "Email address ${email_address} verified. ${confirm_message}.", mapping={ "email_address": email.email, "confirm_message": confirm_message }, ), queue="success", ) return HTTPSeeOther(request.route_path("manage.account"))
def login(request, redirect_field_name=REDIRECT_FIELD_NAME, _form_class=LoginForm): # TODO: Logging in should reset request.user # TODO: Configure the login view as the default view for not having # permission to view something. if request.authenticated_userid is not None: return HTTPSeeOther(request.route_path("manage.projects")) user_service = request.find_service(IUserService, context=None) breach_service = request.find_service(IPasswordBreachedService, context=None) redirect_to = request.POST.get(redirect_field_name, request.GET.get(redirect_field_name)) form = _form_class( request.POST, request=request, user_service=user_service, breach_service=breach_service, check_password_metrics_tags=["method:auth", "auth_method:login_form"], ) if request.method == "POST": if form.validate(): # Get the user id for the given username. username = form.username.data userid = user_service.find_userid(username) # If the user has enabled two factor authentication. if user_service.has_two_factor(userid): two_factor_data = {"userid": userid} if redirect_to: two_factor_data["redirect_to"] = redirect_to token_service = request.find_service(ITokenService, name="two_factor") token = token_service.dumps(two_factor_data) # Stuff our token in the query and redirect to two-factor page. resp = HTTPSeeOther( request.route_path("accounts.two-factor", _query=token)) return resp else: # If the user-originating redirection url is not safe, then # redirect to the index instead. if not redirect_to or not is_safe_url(url=redirect_to, host=request.host): redirect_to = request.route_path("manage.projects") # Actually perform the login routine for our user. headers = _login_user(request, userid) # Now that we're logged in we'll want to redirect the user to # either where they were trying to go originally, or to the default # view. resp = HTTPSeeOther(redirect_to, headers=dict(headers)) # We'll use this cookie so that client side javascript can # Determine the actual user ID (not username, user ID). This is # *not* a security sensitive context and it *MUST* not be used # where security matters. # # We'll also hash this value just to avoid leaking the actual User # IDs here, even though it really shouldn't matter. resp.set_cookie( USER_ID_INSECURE_COOKIE, hashlib.blake2b( str(userid).encode("ascii"), person=b"warehouse.userid").hexdigest().lower(), ) return resp return { "form": form, "redirect": { "field": REDIRECT_FIELD_NAME, "data": redirect_to }, }
def bail(): # Abort registration; typically if the request is nonsensical clear_pending() request.session.flash('Your session expired. Please try logging in again.') return HTTPSeeOther(location=request.route_url('account.login'))
def register(context, request): def clear_pending(): request.session.pop('pending_identity_email', None) request.session.pop('pending_identity_url', None) request.session.pop('pending_identity_webfinger', None) def bail(): # Abort registration; typically if the request is nonsensical clear_pending() request.session.flash('Your session expired. Please try logging in again.') return HTTPSeeOther(location=request.route_url('account.login')) # Check identity URL identity_url = request.session.get('pending_identity_url') identity_email = request.session.get('pending_identity_email') openid_q = model.session.query(IdentityURL).filter_by(url=identity_url) persona_q = model.session.query(IdentityEmail).filter_by(email=identity_email) # Must register against (or add) exactly one ID if not identity_url and not identity_email: return bail() if identity_url and identity_email: return bail() # Cannot re-register an ID if identity_url and openid_q.count(): return bail() if identity_email and persona_q.count(): return bail() form = RegistrationForm(request.POST) if request.method != 'POST' or not form.validate(): return render_to_response('account/register.mako', { 'form': form, 'identity_email': identity_email, 'identity_url': identity_url, 'identity_webfinger': request.session.get('pending_identity_webfinger'), }, request=request) # XXX waiting on auth_dev2 branch to merge to factor this out of controls from floof.lib.helpers import reduce_display_name if not form.display_name.data: display_name = None has_trivial_display_name = False else: display_name = form.display_name.data has_trivial_display_name = (form.username.data == reduce_display_name(display_name)) # Create db records resource = Resource(type=u'users') discussion = Discussion(resource=resource) user = User( name=form.username.data, email=form.email.data, resource=resource, timezone=form.timezone.data, display_name=display_name, has_trivial_display_name=has_trivial_display_name, ) model.session.add_all((user, resource, discussion)) base_user = model.session.query(Role).filter_by(name=u'user').one() user.roles.append(base_user) if identity_url: openid = IdentityURL(url=identity_url) user.identity_urls.append(openid) else: persona_id = IdentityEmail(email=identity_email) user.identity_emails.append(persona_id) model.session.flush() log.info('User #{0} registered: {1}'.format(user.id, user.name)) # Log 'em in clear_pending() auth_headers = security.forget(request) headers = security.remember( request, user, openid_url=identity_url, persona_addr=identity_email) if headers is None: log.error("Failed to log in new registrant.") # shouldn't happen else: auth_headers += headers # And off we go return HTTPSeeOther(request.route_url('root'), headers=auth_headers)
def retry(): """Redirect to the login page, preserving the return key (if any).""" location = request.route_url('account.login') if return_key: location = update_params(location, return_key=return_key) return HTTPSeeOther(location=location)
def login_finish(context, request): """Step two of logging in; the OpenID provider redirects back here.""" def retry(): """Redirect to the login page, preserving the return key (if any).""" location = request.route_url('account.login') if return_key: location = update_params(location, return_key=return_key) return HTTPSeeOther(location=location) return_url = request.route_url('account.login_finish') return_key = key_from_request(request) if return_key is not None: return_url = update_params(return_url, return_key=return_key) try: identity_url, identity_webfinger, auth_time, sreg_res = openid_end( return_url=return_url, request=request) except OpenIDError as exc: request.session.flash(exc.message, level='error', icon='key--exclamation') return retry() # Find who owns this URL, if anyone identity_owner = model.session.query(User) \ .filter(User.identity_urls.any(url=identity_url)) \ .limit(1).first() if not identity_owner: if return_key: request.session.flash('Unknown OpenID URL.', level='error', icon='key--exclamation') return retry() # Someone is either registering a new account, or adding a new OpenID # to an existing account request.session['pending_identity_url'] = identity_url request.session.changed() # Try to pull a name and email address out of the SReg response username = re.sub(u'[^_a-z0-9]', u'', sreg_res.get('nickname', u'').lower()) form = RegistrationForm( username=username, email=sreg_res.get('email', u''), timezone=sreg_res.get('timezone', u'UTC'), ) return render_to_response( 'account/register.mako', dict( form=form, identity_url=identity_url, identity_webfinger=identity_webfinger, identity_email=None), request=request) elif identity_owner == request.user: # Someone is just freshening up their cookie auth_headers = safe_openid_login(request, identity_owner, identity_url) if auth_headers is None: return retry() request.session.flash(u'Re-authentication successful', icon='user') if return_key: # Fetch a stashed request old_url = fetch_stash(request, key=return_key)['url'] if old_url: location = update_params(old_url, return_key=return_key) log.debug('Following Return Key \'{0}\' to URL: {1}' .format(return_key, location)) return HTTPSeeOther(location, headers=auth_headers) return HTTPSeeOther(request.route_url('root'), headers=auth_headers) else: # Existing user; new login # Log the successful OpenID authentication, mindful of users that may # have OpenID logins disabled, for instance. # XXX should we deny a logged-in user to authenticate as another user? auth_headers = security.forget(request) headers = safe_openid_login(request, identity_owner, identity_url) if headers is None: return retry() auth_headers += headers # An existing user has logged in successfully. Bravo! log.debug("User {0!r} logged in via OpenID: {1!r}" .format(identity_owner.name, identity_url)) request.session.flash( u"Welcome back, {0}!" .format(identity_owner.display_name or identity_owner.name), level=u'success', icon='user') # XXX this should ALSO probably do the return_key redirect, good grief return HTTPSeeOther( location=request.route_url('root'), headers=auth_headers)
def deauth(self): headers = forget(self.request) return HTTPSeeOther(location=self.request.route_url('management', traverse=''), headers = headers)
def delete_project(project, request): confirm_project(project, request, fail_route="admin.project.detail") remove_project(project, request) return HTTPSeeOther(request.route_path("admin.project.list"))
def registration_authorized_callback(self): if DEBUG_ROUTE: print( "application:flow-register:oauth1:authorized-callback", get_csrf_token(self.request), ) if LOG_ROUTE: log.debug( "application:flow-register:oauth1:authorized-callback %s", get_csrf_token(self.request), ) if DEBUG_USERID: print( "application:account:register:oauth1:authorized-callback", self.request.active_useraccount_id, ) # we don't have a UID here because we haven't had an account created yet! if self.request.active_useraccount_id: return HTTPSeeOther("/application/account/home") public_token = self.request.params.get("oauth_token") public_verifier = self.request.params.get("oauth_verifier") oauth_sessiondata = self.request.session["3rdparty-app_oauth"] if not oauth_sessiondata: raise ApiError( "we could not link your authorization session correctly.") _oauth_token = oauth_sessiondata.get("oauth_token") _oauth_token_secret = oauth_sessiondata.get("oauth_token_secret") if (_oauth_token is None) or (_oauth_token_secret is None): raise ApiError( "we could not link your authorization session data correctly.") app_data = get_ApiExampleAppData() apiClient = CustomApiClient( app_key=app_data["client_key"], app_secret=app_data["client_secret"], oauth_token=_oauth_token, oauth_token_secret=_oauth_token_secret, client_args={"verify": False}, ) authorized = apiClient.get_authorized_tokens(public_verifier) # wow ok, we have successfully authorized, so... # log them in as a new user! # do this first, because the `Developer_oAuth1Server_TokenClient` requires a self.request.session[ "active_useraccount_id"] = USERID_ACTIVE__APPLICATION newGrant = Developer_oAuth1Client_TokenAccess() newGrant.developer_application_id = app_data["id"] newGrant.useraccount_id = self.request.active_useraccount_id newGrant.timestamp_created = self.request.datetime newGrant.oauth_token = authorized["oauth_token"] newGrant.oauth_token_secret = authorized["oauth_token_secret"] newGrant._realms = (authorized["oauth_authorized_realms"] if "oauth_authorized_realms" in authorized else "") newGrant.oauth_version = "1" self.request.dbSession.add(newGrant) return HTTPSeeOther( location="/application/flow-register/authorized-callback-success")
def reset_password(request, _form_class=ResetPasswordForm): if request.authenticated_userid is not None: return HTTPSeeOther(request.route_path("index")) user_service = request.find_service(IUserService, context=None) breach_service = request.find_service(IPasswordBreachedService, context=None) token_service = request.find_service(ITokenService, name="password") def _error(message): request.session.flash(message, queue="error") return HTTPSeeOther( request.route_path("accounts.request-password-reset")) try: token = request.params.get("token") data = token_service.loads(token) except TokenExpired: return _error("Expired token: request a new password reset link") except TokenInvalid: return _error("Invalid token: request a new password reset link") except TokenMissing: return _error("Invalid token: no token supplied") # Check whether this token is being used correctly if data.get("action") != "password-reset": return _error("Invalid token: not a password reset token") # Check whether a user with the given user ID exists user = user_service.get_user(uuid.UUID(data.get("user.id"))) if user is None: return _error("Invalid token: user not found") # Check whether the user has logged in since the token was created last_login = data.get("user.last_login") if str(user.last_login) > last_login: # TODO: track and audit this, seems alertable return _error( "Invalid token: user has logged in since this token was requested") # Check whether the password has been changed since the token was created password_date = data.get("user.password_date") if str(user.password_date) > password_date: return _error( "Invalid token: password has already been changed since this " "token was requested") form = _form_class( **request.params, username=user.username, full_name=user.name, email=user.email, user_service=user_service, breach_service=breach_service, ) if request.method == "POST" and form.validate(): # Update password. user_service.update_user(user.id, password=form.new_password.data) user_service.record_event(user.id, tag="account:password:reset", ip_address=request.remote_addr) # Flash a success message request.session.flash("You have reset your password", queue="success") # Redirect to account login. return HTTPSeeOther(request.route_path("accounts.login")) return {"form": form}
def control_createfolder_(request): form = request.web_input(title="", parentid="") folder.create(request.userid, form) raise HTTPSeeOther(location="/manage/folders")
def _error(message): request.session.flash(message, queue="error") return HTTPSeeOther(request.route_path("manage.account"))
def control_renamefolder_(request): form = request.web_input(folderid="", title="") if define.get_int(form.folderid): folder.rename(request.userid, form) raise HTTPSeeOther(location="/manage/folders")
def home_view(request): """The main view on a discussion""" user_id = authenticated_userid(request) or Everyone context = get_default_context(request) discussion = context["discussion"] canRead = user_has_permission(discussion.id, user_id, P_READ) if not canRead and user_id == Everyone: # User isn't logged-in and discussion isn't public: # redirect to login page # need to pass the route to go to *after* login as well # With regards to a next_view, if explicitly stated, then # that is the next view. If not stated, the referer takes # precedence. In case of failure, login redirects to the # discussion which is its context. next_view = request.params.get('next', None) if not next_view and discussion: # If referred here from a post url, want to be able to # send the user back. Usually, Assembl will send the user # here to login on private discussions. referrer = request.url next_view = path_qs(referrer) login_url = get_social_autologin(request, discussion, next_view) if login_url: pass elif next_view: login_url = request.route_url("contextual_login", discussion_slug=discussion.slug, _query={"next": next_view}) else: login_url = request.route_url('contextual_login', discussion_slug=discussion.slug) return HTTPTemporaryRedirect(login_url) elif not canRead: # User is logged-in but doesn't have access to the discussion # Would use render_to_response, except for the 401 from pyramid_jinja2 import IJinja2Environment jinja_env = request.registry.queryUtility(IJinja2Environment, name='.jinja2') template = jinja_env.get_template('cannot_read_discussion.jinja2') body = template.render(get_default_context(request)) return Response(body, 401) # if the route asks for a post, get post content (because this is needed for meta tags) route_name = request.matched_route.name if route_name == "purl_posts": post_id = FrontendUrls.getRequestedPostId(request) if not post_id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) post = Post.get_instance(post_id) if not post or post.discussion_id != discussion.id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) context['post'] = post elif route_name == "purl_idea": idea_id = FrontendUrls.getRequestedIdeaId(request) if not idea_id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) idea = Idea.get_instance(idea_id) if not idea or idea.discussion_id != discussion.id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) context['idea'] = idea canAddExtract = user_has_permission(discussion.id, user_id, P_ADD_EXTRACT) context['canAddExtract'] = canAddExtract context['canDisplayTabs'] = True preferences = discussion.preferences session = discussion.db if user_id != Everyone: from assembl.models import UserPreferenceCollection user = User.get(user_id) preferences = UserPreferenceCollection(user_id, discussion) target_locale = get_locale_from_request(request, session, user) else: target_locale = get_locale_from_request(request, session) translation_service_data = {} try: service = discussion.translation_service() if service: translation_service_data = service.serviceData() except: pass context['translation_service_data_json'] = json.dumps( translation_service_data) locale_labels = json.dumps( DummyGoogleTranslationService.target_locale_labels_cls(target_locale)) context['translation_locale_names_json'] = locale_labels context['preferences_json'] = json.dumps(dict(preferences)) role_names = [x for (x) in session.query(Role.name).all()] context['role_names'] = json.dumps(role_names) response = render_to_response('../../templates/index.jinja2', context, request=request) # Prevent caching the home, especially for proper login/logout response.cache_control.max_age = 0 response.cache_control.prevent_auto = True return response
def control_unignoreuser_(request): form = request.web_input(username="") ignoreuser.remove(request.userid, define.get_userid_list(form.username)) raise HTTPSeeOther(location="/manage/ignore")
def new_machine(request): """ Handler for ``/{org}/machine/new/{id}``. The user must be authenticated for the organisation in the URL to reach here. ``{id}`` is the id of the catalogue item to use for the new machine. GET request Show a form to gather information required for provisioning. POST request Attempt to provision a machine with the given details. If the provisioning is successful, redirect the user to ``/{org}/machines`` with a success message. If the provisioning fails with an error that the user can correct, show the form with an error message. If the provisioning fails with a cloud error, show an error on ``/{org}/machines``. """ # Try to load the catalogue item item = request.active_cloud_session.get_image(request.matchdict['id']) # If we have a POST request, try and provision a machine with the info if request.method == 'POST': # For a POST request, the request must pass a CSRF test check_csrf_token(request) machine_info = { 'template': item, 'name': request.params.get('name', ''), 'description': request.params.get('description', ''), 'expose': request.params.get('expose', 'false'), 'ssh_key': request.params.get('ssh_key', ''), 'errors': {} } # Check that the SSH key is valid try: machine_info['ssh_key'] = validate_ssh_key(machine_info['ssh_key']) except ValueError as e: request.session.flash('There are errors with one or more fields', 'error') machine_info['errors']['ssh_key'] = [str(e)] return machine_info try: machine = request.active_cloud_session.provision_machine( item.id, machine_info['name'], machine_info['description'], machine_info['ssh_key'], machine_info['expose'] == 'true') request.session.flash('Machine provisioned successfully', 'success') if machine.external_ip: request.session.flash('Inbound access from internet enabled', 'success') except cloudservices.DuplicateNameError: # If there is an error with a duplicate name, the user can correct that request.session.flash('There are errors with one or more fields', 'error') machine_info['errors']['name'] = ['Machine name is already in use'] return machine_info except cloudservices.NetworkingError: # Networking doesn't happen until the machine has been provisioned # So we report that provisioning was successful before propagating request.session.flash('Machine provisioned successfully', 'success') raise # If we get this far, redirect to machines return HTTPSeeOther(location=request.route_url('machines')) # Only get requests should get this far return { 'template': item, 'name': '', 'description': '', # The default value for expose is based on the NAT policy 'expose': 'true' if item.nat_policy == NATPolicy.ALWAYS else 'false', # Use the current user's SSH key as the default 'ssh_key': request.authenticated_user.ssh_key or '', 'errors': {} }
def control_tagrestrictions_post_(request): tags = searchtag.parse_restricted_tags(request.params["tags"]) searchtag.edit_user_tag_restrictions(request.userid, tags) raise HTTPSeeOther(location=request.route_path('control_tagrestrictions'))
def delete_project_release(self): if self.request.flags.enabled(AdminFlagValue.DISALLOW_DELETION): self.request.session.flash( ("Project deletion temporarily disabled. " "See https://pypi.org/help#admin-intervention for details."), queue="error", ) return HTTPSeeOther( self.request.route_path( "manage.project.release", project_name=self.release.project.name, version=self.release.version, )) version = self.request.POST.get("confirm_version") if not version: self.request.session.flash("Confirm the request", queue="error") return HTTPSeeOther( self.request.route_path( "manage.project.release", project_name=self.release.project.name, version=self.release.version, )) if version != self.release.version: self.request.session.flash( "Could not delete release - " + f"{version!r} is not the same as {self.release.version!r}", queue="error", ) return HTTPSeeOther( self.request.route_path( "manage.project.release", project_name=self.release.project.name, version=self.release.version, )) self.request.db.add( JournalEntry( name=self.release.project.name, action="remove release", version=self.release.version, submitted_by=self.request.user, submitted_from=self.request.remote_addr, )) self.release.project.record_event( tag="project:release:remove", ip_address=self.request.remote_addr, additional={ "submitted_by": self.request.user.username, "canonical_version": self.release.canonical_version, }, ) self.request.db.delete(self.release) self.request.session.flash(f"Deleted release {self.release.version!r}", queue="success") return HTTPSeeOther( self.request.route_path("manage.project.releases", project_name=self.release.project.name))
def manage_avatar_post_(request): form = request.web_input(image="", x1=0, y1=0, x2=0, y2=0) avatar.create(request.userid, form.x1, form.y1, form.x2, form.y2) raise HTTPSeeOther(location="/control")
def manage_banner_post_(request): form = request.web_input(image="") banner.upload(request.userid, form.image) raise HTTPSeeOther(location="/control")
def persona_add_noxhr(context, request): return HTTPSeeOther(location=persona_add(context, request))
def set_lang(request): new_lang = request.POST['lang'] response = HTTPSeeOther(request.route_url('preferences')) cookie_path = '/' # FIXME: not necessarily response.set_cookie(LOCALE_COOKIE_NAME, new_lang, path=cookie_path) return response
def home_view(request): user_id = authenticated_userid(request) or Everyone context = get_default_context(request) discussion = context["discussion"] request.session["discussion"] = discussion.slug canRead = user_has_permission(discussion.id, user_id, P_READ) if not canRead and user_id == Everyone: # User isn't logged-in and discussion isn't public: # redirect to login page login_url = request.route_url('contextual_login', discussion_slug=discussion.slug) return HTTPSeeOther(login_url) elif not canRead: # User is logged-in but doesn't have access to the discussion return HTTPUnauthorized() # if the route asks for a post, get post content (because this is needed for meta tags) route_name = request.matched_route.name if route_name == "purl_posts": post_id = FrontendUrls.getRequestedPostId(request) if not post_id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) post = Post.get_instance(post_id) if not post or post.discussion_id != discussion.id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) context['post'] = post elif route_name == "purl_idea": idea_id = FrontendUrls.getRequestedIdeaId(request) if not idea_id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) idea = Idea.get_instance(idea_id) if not idea or idea.discussion_id != discussion.id: return HTTPSeeOther( request.route_url('home', discussion_slug=discussion.slug)) context['idea'] = idea canAddExtract = user_has_permission(discussion.id, user_id, P_ADD_EXTRACT) context['canAddExtract'] = canAddExtract context['canDisplayTabs'] = True if user_id != Everyone: from assembl.models import AgentProfile user = AgentProfile.get(user_id) # TODO: user may not exist. Case of session with BD change. user.is_visiting_discussion(discussion.id) session = Discussion.default_db current_prefs = session.query(UserLanguagePreference).\ filter_by(user_id = user_id).all() user = session.query(User).filter_by(id=user_id).first() def validate_locale(l): return ensure_locale_has_country(to_posix_format(locale)) if '_LOCALE_' in request.cookies: locale = request.cookies['_LOCALE_'] posix_locale = validate_locale(locale) process_locale(posix_locale, user_id, current_prefs, session, LanguagePreferenceOrder.Cookie) elif '_LOCALE_' in request.params: locale = request.params['_LOCALE_'] posix_locale = validate_locale(locale) process_locale(posix_locale, user_id, current_prefs, session, LanguagePreferenceOrder.Parameter) else: locale = default_locale_negotiator(request) posix_locale = validate_locale(locale) process_locale(posix_locale, user_id, current_prefs, session, LanguagePreferenceOrder.OS_Default) response = render_to_response('../../templates/index.jinja2', context, request=request) # Prevent caching the home, especially for proper login/logout response.cache_control.max_age = 0 response.cache_control.prevent_auto = True return response
def manage_alias_post_(request): form = request.web_input(username="") useralias.set(request.userid, define.get_sysname(form.username)) raise HTTPSeeOther(location="/control")
def reset_password(request, _form_class=ResetPasswordForm): if request.authenticated_userid is not None: return HTTPSeeOther(request.route_path("index")) user_service = request.find_service(IUserService, context=None) breach_service = request.find_service(IPasswordBreachedService, context=None) token_service = request.find_service(ITokenService, name="password") def _error(message): request.session.flash(message, queue="error") return HTTPSeeOther( request.route_path("accounts.request-password-reset")) try: token = request.params.get("token") data = token_service.loads(token) except TokenExpired: return _error( request._("Expired token: request a new password reset link")) except TokenInvalid: return _error( request._("Invalid token: request a new password reset link")) except TokenMissing: return _error(request._("Invalid token: no token supplied")) # Check whether this token is being used correctly if data.get("action") != "password-reset": return _error(request._("Invalid token: not a password reset token")) # Check whether a user with the given user ID exists user = user_service.get_user(uuid.UUID(data.get("user.id"))) if user is None: return _error(request._("Invalid token: user not found")) # Check whether the user has logged in since the token was created last_login = datetime.datetime.fromisoformat(data.get("user.last_login")) # Before updating itsdangerous to 2.x the last_login was naive, # now it's localized to UTC if not last_login.tzinfo: last_login = pytz.UTC.localize(last_login) if user.last_login > last_login: # TODO: track and audit this, seems alertable return _error( request. _("Invalid token: user has logged in since this token was requested" )) # Check whether the password has been changed since the token was created password_date = datetime.datetime.fromisoformat( data.get("user.password_date")) # Before updating itsdangerous to 2.x the password_date was naive, # now it's localized to UTC if not password_date.tzinfo: password_date = pytz.UTC.localize(password_date) if user.password_date > password_date: return _error( request._( "Invalid token: password has already been changed since this " "token was requested")) form = _form_class( **request.params, username=user.username, full_name=user.name, email=user.email, user_service=user_service, breach_service=breach_service, ) if request.method == "POST" and form.validate(): password_reset_limiter = request.find_service(IRateLimiter, name="password.reset") # Update password. user_service.update_user(user.id, password=form.new_password.data) user_service.record_event(user.id, tag="account:password:reset") password_reset_limiter.clear(user.id) # Send password change email send_password_change_email(request, user) # Flash a success message request.session.flash(request._("You have reset your password"), queue="success") # Redirect to account login. return HTTPSeeOther(request.route_path("accounts.login")) return {"form": form}