("path", "expected"), [("/foo/bar/", True), ("/static/wat/", False), ("/_debug_toolbar/thing/", False)], ) def test_activate_hook(path, expected): request = pretend.stub(path=path) assert config.activate_hook(request) == expected @pytest.mark.parametrize( ("exc_info", "expected"), [ (None, False), ((ValueError, ValueError(), None), True), ((HTTPForbidden, HTTPForbidden(), None), True), ((HTTPUnauthorized, HTTPUnauthorized(), None), True), ((BasicAuthBreachedPassword, BasicAuthBreachedPassword(), None), False), ((BasicAuthFailedPassword, BasicAuthFailedPassword(), None), False), ], ) def test_commit_veto(exc_info, expected): request = pretend.stub(exc_info=exc_info) response = pretend.stub() assert bool(config.commit_veto(request, response)) == expected @pytest.mark.parametrize("route_kw", [None, {}, {"foo": "bar"}]) def test_template_view(route_kw): configobj = pretend.stub(
def developer_application_edit(request): app_id = request.matchdict['app'] try: uuid.UUID(app_id) except ValueError: return HTTPBadRequest() try: app = Session.query(Application).filter(Application.id == app_id).one() except NoResultFound: return HTTPNotFound() assert_authenticated_user_is_registered(request) if app.user != request.user: return HTTPUnauthorized() schema = FullApplicationSchema() button1 = Button('submit', _('Save application')) button1.css_class = 'btn-primary' button2 = Button('delete', _('Delete application')) button2.css_class = 'btn-danger' button3 = Button('cancel', _('Cancel')) button3.css_class = 'btn-default' form = Form(schema, buttons=(button1, button2, button3)) if 'submit' in request.POST: controls = request.POST.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return {'form': e.render(), 'app': app} # the data is fine, save into the db app.name = appstruct['name'] app.main_url = appstruct['main_url'] app.callback_url = appstruct['callback_url'] app.authorized_origins = appstruct['authorized_origins'] app.production_ready = appstruct['production_ready'] app.image_url = appstruct['image_url'] app.description = appstruct['description'] Session.add(app) request.session.flash(_('The changes were saved successfully'), 'success') return HTTPFound( location=request.route_path('oauth2_developer_applications')) elif 'delete' in request.POST: return HTTPFound(location=request.route_path( 'oauth2_developer_application_delete', app=app.id)) elif 'cancel' in request.POST: return HTTPFound( location=request.route_path('oauth2_developer_applications')) # this is a GET return { 'form': form.render({ 'name': app.name, 'main_url': app.main_url, 'callback_url': app.callback_url, 'authorized_origins': app.authorized_origins, 'production_ready': app.production_ready, 'image_url': app.image_url, 'description': app.description, 'client_id': app.id, 'client_secret': app.secret, }), 'app': app, }
def wrapper(request): if check_group_of_user(request, 'Users', plugin_name): return view_function(request) else: return HTTPUnauthorized()
def make_401_error(message, realm="AIRS Export"): error = HTTPUnauthorized( headers=make_headers({"WWW-Authenticate": 'Basic realm="%s"' % realm})) error.content_type = "text/plain" error.text = message return error
def mutate(root, args, context, info): cls = models.Thematic discussion_id = context.matchdict['discussion_id'] user_id = context.authenticated_userid or Everyone thematic_id = args.get('id') id_ = int(Node.from_global_id(thematic_id)[1]) thematic = cls.get(id_) permissions = get_permissions(user_id, discussion_id) allowed = thematic.user_can(user_id, CrudPermissions.UPDATE, permissions) if not allowed or (allowed == IF_OWNED and user_id == Everyone): raise HTTPUnauthorized() with cls.default_db.no_autoflush: title_entries = args.get('title_entries') if len(title_entries) == 0: raise Exception( 'Thematic titleEntries needs at least one entry') # Better to have this message than # 'NoneType' object has no attribute 'owner_object' # when creating the saobj below if title=None update_langstring_from_input_entries(thematic, 'title', title_entries) update_langstring_from_input_entries( thematic, 'description', args.get('description_entries')) kwargs = {} video = args.get('video') if video is not None: update_langstring_from_input_entries(thematic, 'video_title', video['title_entries']) update_langstring_from_input_entries( thematic, 'video_description', video['description_entries']) kwargs['video_html_code'] = video['html_code'] # take the first entry and set it for short_title kwargs['short_title'] = title_entries[0]['value'] kwargs['identifier'] = args.get('identifier') for attr, value in kwargs.items(): setattr(thematic, attr, value) db = thematic.db db.flush() questions_input = args.get('questions') existing_questions = { question.id: question for question in thematic.get_children() } updated_questions = set() if questions_input is not None: for question_input in questions_input: if question_input.get('id', None) is not None: id_ = int(Node.from_global_id(question_input['id'])[1]) updated_questions.add(id_) question = models.Question.get(id_) update_langstring_from_input_entries( question, 'title', question_input['title_entries']) else: title_ls = langstring_from_input_entries( question_input['title_entries']) models.Question(title=title_ls, discussion_id=discussion_id) thematic.children.append( models.Question(title=title_ls, discussion_id=discussion_id)) # remove question (tombstone it) that are not in questions_input for question_id in set( existing_questions.keys()).difference(updated_questions): existing_questions[ question_id].tombstone_date = datetime.utcnow() db.flush() return UpdateThematic(thematic=thematic)
def mutate(root, args, context, info): EMBED_ATTACHMENT = models.AttachmentPurpose.EMBED_ATTACHMENT.value discussion_id = context.matchdict['discussion_id'] user_id = context.authenticated_userid or Everyone discussion = models.Discussion.get(discussion_id) idea_id = args.get('idea_id') idea_id = int(Node.from_global_id(idea_id)[1]) in_reply_to_idea = models.Idea.get(idea_id) if isinstance(in_reply_to_idea, models.Question): cls = models.PropositionPost else: cls = models.AssemblPost extract_id = args.get('extract_id') if extract_id: extract_id_global = int(Node.from_global_id(extract_id)[1]) extract = models.Extract.get(extract_id_global) cls = models.ExtractComment in_reply_to_post = None if (cls == models.AssemblPost) or (cls == models.ExtractComment): in_reply_to_post_id = args.get('parent_id') if in_reply_to_post_id: in_reply_to_post_id = int( Node.from_global_id(in_reply_to_post_id)[1]) if in_reply_to_post_id: in_reply_to_post = models.Post.get(in_reply_to_post_id) permissions = get_permissions(user_id, discussion_id) allowed = cls.user_can_cls(user_id, CrudPermissions.CREATE, permissions) if not allowed: raise HTTPUnauthorized() with cls.default_db.no_autoflush: subject = args.get('subject') body = args.get('body') classifier = args.get('message_classifier', None) body = sanitize_html(body) body_langstring = models.LangString.create(body) publication_state = models.PublicationStates.from_string( args.get('publication_state')) if args.get( 'publication_state') in models.PublicationStates.values( ) else models.PublicationStates.PUBLISHED if subject: subject = sanitize_text(subject) subject_langstring = models.LangString.create(subject) elif issubclass(cls, models.PropositionPost): # Specific case first. Respect inheritance. Since we are using # a specific value, construct it with localization machinery. subject_langstring = models.LangString.create_localized_langstring( # noqa: E501 _('Proposal'), discussion.discussion_locales, {'fr': 'Proposition'}) else: # We apply the same logic than in views/api/post.py::create_post # noqa: E501 locale = models.Locale.UNDEFINED if in_reply_to_post and in_reply_to_post.get_title(): original_subject = in_reply_to_post.get_title( ).first_original() locale = original_subject.locale_code subject = original_subject.value elif in_reply_to_idea: # TODO: some ideas have extra langstring titles # we try to guess the locale of the body to use the same locale for post's subject body_lang, data = discussion.translation_service( ).identify(body_langstring.entries[0].value, discussion.discussion_locales) closest_subject = in_reply_to_idea.title.closest_entry( body_lang) if closest_subject: subject = closest_subject.value locale = closest_subject.locale.code else: # rather no subject than one in a random locale subject = u'' locale = discussion.main_locale else: subject = discussion.topic if discussion.topic else '' locale = discussion.main_locale if subject is not None: if in_reply_to_idea and in_reply_to_idea.message_view_override == u'messageColumns': new_subject = subject else: new_subject = u'Re: ' + restrip_pat.sub( '', subject).strip() # noqa: E501 if (in_reply_to_post and new_subject == subject and in_reply_to_post.get_title()): # reuse subject and translations subject_langstring = in_reply_to_post.get_title( ).clone(discussion.db) else: subject_langstring = models.LangString.create( new_subject, locale) if cls == models.ExtractComment: new_post = cls(discussion=discussion, subject=subject_langstring, body=body_langstring, creator_id=user_id, body_mime_type=u'text/html', message_classifier=classifier, creation_date=datetime.utcnow(), publication_state=publication_state, parent_extract_id=extract.id) else: new_post = cls(discussion=discussion, subject=subject_langstring, body=body_langstring, creator_id=user_id, body_mime_type=u'text/html', message_classifier=classifier, creation_date=datetime.utcnow(), publication_state=publication_state) new_post.guess_languages() db = new_post.db db.add(new_post) db.flush() if in_reply_to_post: new_post.set_parent(in_reply_to_post) elif in_reply_to_idea and cls != models.ExtractComment: # don't create IdeaRelatedPostLink when we have both # in_reply_to_post and in_reply_to_idea or if it's a comment # for an extract idea_post_link = models.IdeaRelatedPostLink( creator_id=user_id, content=new_post, idea=in_reply_to_idea) db.add(idea_post_link) db.flush() attachments = args.get('attachments', []) for document_id in attachments: document = models.Document.get(document_id) models.PostAttachment(document=document, discussion=discussion, creator_id=context.authenticated_userid, post=new_post, title=document.title, attachmentPurpose=EMBED_ATTACHMENT) db.flush() return CreatePost(post=new_post)
def lux_report_create(self): token = self.config["authtkt_secret"] print_servers = DBSession.query(LuxPrintServers).all() if os.environ.get('FAKE_PRINT_URLS'): print_urls = os.environ.get('FAKE_PRINT_URLS').split(',') else: print_urls = [print_server.url for print_server in print_servers] urllib.request.getproxies = lambda: {} valid_print_urls = [] if print_urls is not None and len(print_urls) > 0: for url in print_urls: try: test_url = url.replace("/print/geoportailv3", "") urllib.request.urlopen(test_url) valid_print_urls.append(url) except Exception as e: log.exception(e) log.error("Print server not available : " + url) print_url = valid_print_urls[random.randint( 0, len(valid_print_urls) - 1)] else: print_url = self.config["print_url"] spec = json.loads( self.request.body.decode("utf-8").replace( ".app.geoportail", ".geoportail").replace("vectortiles.geoportail.lu", "vectortiles-print.geoportail.lu")) for map_layer in spec["attributes"]["map"]["layers"]: if "baseURL" in map_layer and\ "ogcproxywms" in map_layer["baseURL"]: if "customParams" in map_layer: map_layer["customParams"]["GP_TOKEN"] = token else: map_layer["customParams"] = {"GP_TOKEN": token} if self.request.user and\ self.request.user.ogc_role is not None and\ self.request.user.ogc_role != -1: if "customParams" in map_layer: map_layer["customParams"]["roleOGC"] =\ str(self.request.user.ogc_role) else: map_layer["customParams"] =\ {"roleOGC": str(self.request.user.ogc_role)} for layer in map_layer["layers"]: internal_wms = DBSession.query(LuxLayerInternalWMS).filter( LuxLayerInternalWMS.layer == layer).first() if internal_wms is not None and\ not self._is_authorized(internal_wms): return HTTPUnauthorized() if "longUrl" in spec["attributes"]: opener = urllib.request.build_opener(urllib.request.HTTPHandler()) data = urllib.parse.urlencode( {"url": spec["attributes"]["longUrl"]}) content = opener.open("https://map.geoportail.lu/short/create", data=data.encode('utf-8')).read() shortner = json.loads(content) spec["attributes"]["url"] = shortner["short_url"] spec["attributes"]["qrimage"] =\ "https://map.geoportail.lu/main/wsgi/qr?url=" + \ spec["attributes"]["url"] job = LuxPrintJob() job.spec = json.dumps(spec) if "longUrl" in spec["attributes"]: spec["attributes"].pop('longUrl', None) if "firstPagesUrls" in spec["attributes"]: spec["attributes"].pop('firstPagesUrls', None) self.request.body = str.encode(json.dumps(spec)) resp, content = self._proxy( "%s/report.%s" % (print_url, self.request.matchdict.get("format"))) job.id = json.loads(content)["ref"] job.print_url = print_url job.creation = datetime.now() DBSession.add(job) return self._build_response(resp, content, False, "print")
def require_authentication(self): token = self.request.userdb.authenticate(self.get_username(), self.request.json_body['password']) if 'error' in token: raise HTTPUnauthorized(token)
def login(self) -> pyramid.response.Response: self._referer_log() login = self.request.POST.get("login") password = self.request.POST.get("password") if login is None or password is None: raise HTTPBadRequest( "'login' and 'password' should be available in request params." ) username = self.request.registry.validate_user(self.request, login, password) if username is not None: user = models.DBSession.query( static.User).filter(static.User.username == username).one() if self.two_factor_auth: if "2fa_totp_secret" not in user.tech_data: user.is_password_changed = False if not user.is_password_changed: user.tech_data["2fa_totp_secret"] = pyotp.random_base32() if self.request.GET.get("type") == "oauth2": raise HTTPFound( location=self.request.route_url("notlogin")) return set_common_headers( self.request, "login", Cache.PRIVATE_NO, response=Response( json.dumps({ "username": user.username, "is_password_changed": False, "two_factor_enable": self.two_factor_auth, "two_factor_totp_secret": user.tech_data["2fa_totp_secret"], "otp_uri": pyotp.TOTP(user.tech_data["2fa_totp_secret"]). provisioning_uri( user.email, issuer_name=self.two_factor_issuer_name), }), headers=(("Content-Type", "text/json"), ), ), ) otp = self.request.POST.get("otp") if otp is None: raise HTTPBadRequest("The second factor is missing.") if not self._validate_2fa_totp(user, otp): LOG.info("The second factor is wrong for user '%s'.", user.username) raise HTTPUnauthorized("See server logs for details") user.update_last_login() user.tech_data["consecutive_failed"] = "0" if not user.is_password_changed: if self.request.GET.get("type") == "oauth2": raise HTTPFound( location=self.request.route_url("notlogin")) return set_common_headers( self.request, "login", Cache.PRIVATE_NO, response=Response( json.dumps({ "username": user.username, "is_password_changed": False, "two_factor_enable": self.two_factor_auth, }), headers=(("Content-Type", "text/json"), ), ), ) LOG.info("User '%s' logged in.", username) if self.request.GET.get("type") == "oauth2": self._oauth2_login(user) headers = remember(self.request, username) came_from = self.request.params.get("came_from") if came_from: return HTTPFound(location=came_from, headers=headers) headers.append(("Content-Type", "text/json")) return set_common_headers( self.request, "login", Cache.PRIVATE_NO, response=Response(json.dumps( self._user(self.request.get_user(username))), headers=headers), ) user = models.DBSession.query( static.User).filter(static.User.username == login).one_or_none() if user and not user.deactivated: if "consecutive_failed" not in user.tech_data: user.tech_data["consecutive_failed"] = "0" user.tech_data["consecutive_failed"] = str( int(user.tech_data["consecutive_failed"]) + 1) if int(user.tech_data["consecutive_failed"] ) >= self.request.registry.settings.get( "authentication", {}).get("max_consecutive_failures", sys.maxsize): user.deactivated = True user.tech_data["consecutive_failed"] = "0" if hasattr(self.request, "tm"): self.request.tm.commit() raise HTTPUnauthorized("See server logs for details")
def submit(self): request = self.request context = self.context if context.username == "root" and context.index == "pypi": abort_submit(request, 404, "cannot submit to pypi mirror") stage = self.context.stage if not request.has_permission("pypi_submit"): # if there is no authenticated user, then issue a basic auth challenge if not request.authenticated_userid: response = HTTPUnauthorized() response.headers.update(forget(request)) return response abort_submit(request, 403, "no permission to submit") try: action = request.POST[":action"] except KeyError: abort_submit(request, 400, ":action field not found") if action == "submit": self._set_versiondata_form(stage, request.POST) return Response("") elif action in ("doc_upload", "file_upload"): try: content = request.POST["content"] except KeyError: abort_submit(request, 400, "content file field not found") name = ensure_unicode(request.POST.get("name")) # version may be empty on plain doczip uploads version = ensure_unicode(request.POST.get("version") or "") project = normalize_name(name) if action == "file_upload": if not stage.has_project(name): abort_submit( request, 400, "no project named %r was ever registered" % (name)) self.log.debug("metadata in form: %s", list(request.POST.items())) # we only check for release files if version is # contained in the filename because for doczip files # we construct the filename ourselves anyway. if version and version not in content.filename: abort_submit( request, 400, "filename %r does not contain version %r" % ( content.filename, version)) abort_if_invalid_filename(request, name, content.filename) metadata = stage.get_versiondata_perstage(project, version) if not metadata: self._set_versiondata_form(stage, request.POST) metadata = stage.get_versiondata(project, version) if not metadata: abort_submit( request, 400, "could not process form metadata") file_content = content.file.read() try: link = stage.store_releasefile( project, version, content.filename, file_content) except stage.NonVolatile as e: if e.link.matches_checksum(file_content): abort_submit( request, 200, "Upload of identical file to non volatile index.", level="info") abort_submit( request, 409, "%s already exists in non-volatile index" % ( content.filename,)) link.add_log( 'upload', request.authenticated_userid, dst=stage.name) try: self.xom.config.hook.devpiserver_on_upload_sync( log=request.log, application_url=request.application_url, stage=stage, project=project, version=version) except Exception as e: abort_submit( request, 200, "OK, but a trigger plugin failed: %s" % e, level="warn") else: doczip = content.file.read() try: link = stage.store_doczip(project, version, doczip) except stage.MissesVersion as e: abort_submit( request, 400, "%s" % e) except stage.MissesRegistration: abort_submit( request, 400, "%s-%s is not registered" % (name, version)) except stage.NonVolatile as e: if e.link.matches_checksum(doczip): abort_submit( request, 200, "Upload of identical file to non volatile index.", level="info") abort_submit( request, 409, "%s already exists in non-volatile index" % ( content.filename,)) link.add_log( 'upload', request.authenticated_userid, dst=stage.name) else: abort_submit(request, 400, "action %r not supported" % action) return Response("")
def settings(request): if request.user.keyname == 'guest': return HTTPUnauthorized() return dict(title=_("User settings"))
def create_post(request): """ Create a new post in this discussion. We use post, not put, because we don't know the id of the post """ localizer = request.localizer request_body = json.loads(request.body) user_id = request.authenticated_userid if not user_id: raise HTTPUnauthorized() user = Post.default_db.query(User).filter_by(id=user_id).one() body = request_body.get('body', None) html = request_body.get('html', None) # BG: Is this used now? I cannot see it. reply_id = request_body.get('reply_id', None) idea_id = request_body.get('idea_id', None) subject = request_body.get('subject', None) publishes_synthesis_id = request_body.get('publishes_synthesis_id', None) message_classifier = request_body.get('message_classifier', None) if not body and not publishes_synthesis_id: # Should we allow empty messages otherwise? raise HTTPBadRequest(localizer.translate(_("Your message is empty"))) if reply_id: in_reply_to_post = Post.get_instance(reply_id) else: in_reply_to_post = None if idea_id: in_reply_to_idea = Idea.get_instance(idea_id) else: in_reply_to_idea = None discussion_id = int(request.matchdict['discussion_id']) discussion = Discussion.get_instance(discussion_id) if not discussion: raise HTTPNotFound( localizer.translate(_("No discussion found with id=%s")) % (discussion_id, )) ctx = DummyContext({Discussion: discussion}) if html: log.warning("Still using html") # how to guess locale in this case? body = LangString.create(sanitize_html(html)) # TODO: AssemblPosts are pure text right now. # Allowing HTML requires changes to the model. elif body: # TODO: Accept HTML body. for e in body['entries']: e['value'] = sanitize_text(e['value']) body = LangString.create_from_json(body, context=ctx, user_id=user_id) else: body = LangString.EMPTY(discussion.db) if subject: for e in subject['entries']: e['value'] = sanitize_text(e['value']) subject = LangString.create_from_json(subject, context=ctx, user_id=user_id) else: from assembl.models import Locale locale = Locale.UNDEFINED # print(in_reply_to_post.subject, discussion.topic) if in_reply_to_post and in_reply_to_post.get_title(): original_subject = in_reply_to_post.get_title().first_original() if original_subject: locale = original_subject.locale_code subject = (original_subject.value or '' if in_reply_to_post.get_title() else '') elif in_reply_to_idea: # TODO: THis should use a cascade like the frontend # also, some ideas have extra langstring titles subject = (in_reply_to_idea.short_title if in_reply_to_idea.short_title else '') locale = discussion.main_locale else: subject = discussion.topic if discussion.topic else '' locale = discussion.main_locale # print subject if subject is not None and len(subject): new_subject = "Re: " + restrip_pat.sub('', subject).strip() if (in_reply_to_post and new_subject == subject and in_reply_to_post.get_title()): # reuse subject and translations subject = in_reply_to_post.get_title().clone(discussion.db) else: # how to guess locale in this case? subject = LangString.create(new_subject, locale) else: capture_message( "A message is about to be written to the database with an " "empty subject. This is not supposed to happen.") subject = LangString.EMPTY(discussion.db) post_constructor_args = { 'discussion': discussion, 'creator_id': user_id, 'message_classifier': message_classifier, 'subject': subject, 'body': body } if publishes_synthesis_id: published_synthesis = Synthesis.get_instance(publishes_synthesis_id) post_constructor_args['publishes_synthesis'] = published_synthesis new_post = SynthesisPost(**post_constructor_args) new_post.finalize_publish() else: new_post = AssemblPost(**post_constructor_args) new_post.guess_languages() discussion.db.add(new_post) discussion.db.flush() if in_reply_to_post: new_post.set_parent(in_reply_to_post) if in_reply_to_idea: idea_post_link = IdeaRelatedPostLink(creator_id=user_id, content=new_post, idea=in_reply_to_idea) discussion.db.add(idea_post_link) idea = in_reply_to_idea while idea: idea.send_to_changes() parents = idea.get_parents() idea = next(iter(parents)) if parents else None else: discussion.root_idea.send_to_changes() for source in discussion.sources: if 'send_post' in dir(source): source.send_post(new_post) permissions = get_permissions(user_id, discussion_id) return new_post.generic_json('default', user_id, permissions)
def search_endpoint(context, request): if not indexing_active(): return HTTPServiceUnavailable("Indexing inactive") query = request.json_body # u'query': {u'bool': {u'filter': [{u'term': {u'discussion_id': u'23'}}]}} filters = [fil for fil in query['query']['bool']['filter']] discussion_id = [f.values()[0].values()[0] for f in filters if 'discussion_id' in f.values()[0].keys()][0] discussion = models.Discussion.get_instance(discussion_id) if discussion is None: raise HTTPUnauthorized() user_id = request.authenticated_userid or Everyone permissions = get_permissions(user_id, discussion_id) if not discussion.user_can(user_id, CrudPermissions.READ, permissions): raise HTTPUnauthorized() es = connect() index_name = get_index_settings(config)['index_name'] # print get_curl_query(query) result = es.search(index=index_name, body=query) # add creator_name in each hit creator_ids = set([hit['_source']['creator_id'] for hit in result['hits']['hits'] if hit['_source'].get('creator_id', None) is not None]) session = get_session_maker() creators = session.query(models.AgentProfile.id, models.AgentProfile.name ).filter(models.AgentProfile.id.in_(creator_ids)).all() creators_by_id = dict(creators) for hit in result['hits']['hits']: source = hit['_source'] creator_id = source.get('creator_id', None) # Remove inner_hits key to not leak posts from private discussion. # You can easily craft a query to get the participants of a public # discussion and do a has_child filter with inner_hits on a private discussion. if 'inner_hits' in hit: del hit['inner_hits'] if creator_id is not None: source['creator_name'] = creators_by_id.get(creator_id) if hit['_type'] == 'idea': idea = models.Idea.get_instance(source['id']) # The check is not really necessary because it's the same # 'read' permission as the discussion, but it doesn't cost anything # to check it and the READ permission may change in the future. if not idea.user_can(user_id, CrudPermissions.READ, permissions): raise HTTPUnauthorized source['num_posts'] = idea.num_posts source['num_contributors'] = idea.num_contributors elif hit['_type'] == 'user': agent_profile = models.AgentProfile.get_instance(source['id']) if not agent_profile.user_can(user_id, CrudPermissions.READ, permissions): raise HTTPUnauthorized source['num_posts'] = agent_profile.count_posts_in_discussion(discussion_id) # Don't do an extra request to verify the CrudPermissions.READ permission # for post or synthesis. # It's currently the same 'read' permission as the discussion. # elif hit['_type'] in ('synthesis', 'post'): # post = models.Post.get_instance(source['id']) # if not post.user_can(user_id, CrudPermissions.READ, permissions): # raise HTTPUnauthorized return result
def get_token(request): if 'access_code' in request.session: return {'access_code': request.session['access_code']} else: return HTTPUnauthorized()
def assembl_profile(request): session = AgentProfile.default_db localizer = request.localizer profile = get_profile(request) id_type = request.matchdict.get('type').strip() logged_in = request.authenticated_userid save = request.method == 'POST' # if some other user if not profile or not logged_in or logged_in != profile.id: if save: raise HTTPUnauthorized() # Add permissions to view a profile? return render_to_response( 'assembl:templates/view_profile.jinja2', dict(get_default_context(request), profile=profile, user=logged_in and session.query(User).get(logged_in))) confirm_email = request.params.get('confirm_email', None) if confirm_email: return HTTPTemporaryRedirect(location=request.route_url( 'confirm_emailid_sent', email_account_id=int(confirm_email))) errors = [] if save: user_id = profile.id redirect = False username = request.params.get('username', '').strip() if username and (profile.username is None or username != profile.username.username): # check if exists if session.query(Username).filter_by(username=username).count(): errors.append( localizer.translate(_('The username %s is already used')) % (username, )) else: old_username = profile.username if old_username is not None: # free existing username session.delete(old_username) session.flush() # add new username session.add(Username(username=username, user=profile)) if id_type == 'u': redirect = True name = request.params.get('name', '').strip() if name: profile.name = name p1, p2 = (request.params.get('password1', '').strip(), request.params.get('password2', '').strip()) if p1 != p2: errors.append( localizer.translate(_('The passwords are not identical'))) elif p1: profile.password_p = p1 add_email = request.params.get('add_email', '').strip() if add_email: if not is_email(add_email): return dict(get_default_context(request), error=localizer.translate( _("This is not a valid email"))) # No need to check presence since not validated yet email = EmailAccount(email=add_email, profile=profile) session.add(email) if redirect: return HTTPFound(location=request.route_url( 'profile_user', type='u', identifier=username)) profile = session.query(User).get(user_id) unverified_emails = [ (ea, session.query(AbstractAgentAccount).filter_by(email_ci=ea.email_ci, verified=True).first()) for ea in profile.email_accounts if not ea.verified ] get_route = create_get_route(request) providers = get_provider_data(get_route) return render_to_response( 'assembl:templates/profile.jinja2', dict(get_default_context(request), error='<br />'.join(errors), unverified_emails=unverified_emails, providers=providers, providers_json=json.dumps(providers), google_consumer_key=request.registry.settings.get( 'google.consumer_key', ''), the_user=profile, user=session.query(User).get(logged_in)))
def challenge(self, request, content="Unauthorized"): if self.authenticated_userid(request): return HTTPUnauthorized(content, headers=self.forget(request)) return HTTPForbidden(content, headers=self.forget(request))
def authenticated_userid(self, request): # Override current user in tests via ngw_auth_administrator fixture if self.test_user is not None: return User.by_keyname(self.test_user).id session = request.session # Session based authentication current = session.get('auth.policy.current') if current is not None: atype, user_id, exp = current[0:3] exp = timestamp_to_datetime(int(exp)) now = datetime.utcnow() expired = exp <= now if atype == 'OAUTH': if len(current) != 3: raise ValueError("Invalid OAuth session data") if expired: try: tresp = self.oauth.grant_type_refresh_token( refresh_token=session['auth.policy.refresh_token'], access_token=session['auth.policy.access_token']) self.remember(request, (user_id, tresp)) except OAuthTokenRefreshException: self.forget(request) return None return user_id elif atype == 'LOCAL': if expired: return None refresh, = current[3:] if timestamp_to_datetime(refresh) <= now: session['auth.policy.current'] = current[0:2] + ( int( datetime_to_timestamp( now + self.options['local.lifetime'])), int( datetime_to_timestamp( now + self.options['local.refresh'])), ) return user_id else: raise ValueError("Invalid authentication type: " + atype) # HTTP based authentication ahead = request.headers.get('Authorization') if ahead is not None: ahead = six.ensure_text(ahead) amode, value = ahead.split(' ') amode = amode.upper() if amode == 'BASIC': username, password = six.ensure_text( b64decode(value)).split(':') # Allow token authorization via basic when # username is empty (for legacy clients). if username == '': amode = 'BEARER' value = password else: user, _ = self.authenticate_with_password(username, password, oauth=False) return user.id if amode == 'BEARER' and self.oauth is not None: user = self.oauth.access_token_to_user(value) if user is not None: return user.id raise HTTPUnauthorized() return None
def safe_del(self, key, permissions=(P_READ, )): if not self.can_edit(key, permissions): raise HTTPUnauthorized("Cannot delete " + key) del self[key]
def mutate(root, args, context, info): EMBED_ATTACHMENT = models.AttachmentPurpose.EMBED_ATTACHMENT.value discussion_id = context.matchdict['discussion_id'] user_id = context.authenticated_userid or Everyone discussion = models.Discussion.get(discussion_id) post_id = args.get('post_id') post_id = int(Node.from_global_id(post_id)[1]) post = models.Post.get(post_id) cls = models.Post permissions = get_permissions(user_id, discussion_id) allowed = post.user_can(user_id, CrudPermissions.UPDATE, permissions) if not allowed: raise HTTPUnauthorized() changed = False subject = args.get('subject') if subject: subject = sanitize_text(subject) body = args.get('body') if body: body = sanitize_html(body) # TODO: Here, an assumption that the modification uses the same # language as the original. May need revisiting. original_subject_entry = post.subject.first_original() # subject is not required, be careful to not remove it if not specified if subject and subject != original_subject_entry.value: changed = True post.subject.add_value(subject, original_subject_entry.locale_code) # Edit subject for all descendants children = post.children[:] new_subject = u'Re: ' + restrip_pat.sub('', subject).strip() while children: child = children.pop() children.extend(child.children) child.subject.add_value( new_subject, child.subject.first_original().locale_code) original_body_entry = post.body.first_original() if body != original_body_entry.value: post.body.add_value(body, original_body_entry.locale_code) changed = True original_attachments = post.attachments original_attachments_doc_ids = [] if original_attachments: original_attachments_doc_ids = [ str(a.document_id) for a in original_attachments ] attachments = args.get('attachments', []) for document_id in attachments: if document_id not in original_attachments_doc_ids: document = models.Document.get(document_id) models.PostAttachment( document=document, discussion=discussion, creator_id=context.authenticated_userid, post=post, title=document.title, attachmentPurpose=EMBED_ATTACHMENT) # delete attachments that has been removed documents_to_delete = set(original_attachments_doc_ids) - set( attachments) # noqa: E501 for document_id in documents_to_delete: with cls.default_db.no_autoflush: document = models.Document.get(document_id) post_attachment = post.db.query( models.PostAttachment).filter_by( discussion_id=discussion_id, post_id=post_id, document_id=document_id).first() document.delete_file() post.db.delete(document) post.attachments.remove(post_attachment) post.db.flush() publication_state = models.PublicationStates.from_string( args.get('publication_state')) if args.get( 'publication_state') in models.PublicationStates.values( ) else None if publication_state and publication_state != post.publication_state: post.publication_state = publication_state changed = True # Update the creation date when switching from draft to published if post.publication_state == models.PublicationStates.DRAFT and publication_state == models.PublicationStates.PUBLISHED: post.creation_date = datetime.utcnow() if changed: post.modification_date = datetime.utcnow() post.body_mime_type = u'text/html' post.db.flush() post.db.expire(post.subject, ["entries"]) post.db.expire(post.body, ["entries"]) return UpdatePost(post=post)
def safe_set(self, key, value, permissions=(P_READ, )): if not self.can_edit(key, permissions): raise HTTPUnauthorized("Cannot edit " + key) self[key] = value
def lux_get_thumbnail(self): layer_id = self.request.params.get('layerid', 359) internal_wms = DBSession.query(LuxLayerInternalWMS).filter( LuxLayerInternalWMS.id == layer_id).first() x = float(self.request.params.get('x', '684675.0594454071')) y = float(self.request.params.get('y', '6379501.028468124')) scale = float(self.request.params.get('scale', '77166.59993240683')) center = [x, y] spec = None if internal_wms is not None: if 'PROXYWMSURL' in os.environ: base_url = os.environ.get('PROXYWMSURL') else: base_url = "https://wmsproxy.geoportail.lu/ogcproxywms" spec = { "attributes": { "map": { "dpi": 127, "rotation": 0, "center": center, "projection": "EPSG:3857", "scale": scale, "layers": [{ "baseURL": base_url, "imageFormat": "image/png", "layers": [internal_wms.layer], "customParams": { "TRANSPARENT": True, "MAP_RESOLUTION": 127 }, "type": "wms", "opacity": 1, "useNativeAngle": True }] } }, "format": "png", "layout": "thumbnail" } else: external_wms = DBSession.query(LuxLayerExternalWMS).filter( LuxLayerExternalWMS.id == layer_id).first() if external_wms is not None: base_url = "https://ws.geoportail.lu/mymaps" category_id = external_wms.category_id spec = { "attributes": { "map": { "dpi": 127, "rotation": 0, "center": center, "projection": "EPSG:3857", "scale": scale, "layers": [{ "baseURL": base_url, "imageFormat": "image/png", "layers": ["category"], "customParams": { "TRANSPARENT": True, "category_id": category_id, "MAP_RESOLUTION": 127 }, "type": "wms", "opacity": 1, "useNativeAngle": True }] } }, "format": "png", "layout": "thumbnail" } else: layer_wmts = DBSession.query(LayerWMTS).filter( LayerWMTS.id == layer_id).first() if layer_wmts is not None: image_type = layer_wmts.image_type image_ext = layer_wmts.image_type.split("/")[1] spec = { "attributes": { "map": { "dpi": 127, "rotation": 0, "center": center, "projection": "EPSG:3857", "scale": scale, "layers": [{ "baseURL": "https://wmts3.geoportail.lu/mapproxy_4_v3/wmts/{Layer}/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}." + image_ext, "dimensions": [], "dimensionParams": {}, "imageFormat": image_type, "layer": layer_wmts.layer, "matrices": [{ "identifier": "00", "matrixSize": [1, 1], "scaleDenominator": 559082264.029, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "01", "matrixSize": [2, 2], "scaleDenominator": 279541132.014, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "02", "matrixSize": [4, 4], "scaleDenominator": 139770566.007, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "03", "matrixSize": [8, 8], "scaleDenominator": 69885283.0036, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "04", "matrixSize": [16, 16], "scaleDenominator": 34942641.5018, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "05", "matrixSize": [32, 32], "scaleDenominator": 17471320.7509, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "06", "matrixSize": [64, 64], "scaleDenominator": 8735660.37545, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "07", "matrixSize": [128, 128], "scaleDenominator": 4367830.18772, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "08", "matrixSize": [256, 256], "scaleDenominator": 2183915.09386, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "09", "matrixSize": [512, 512], "scaleDenominator": 1091957.54693, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "10", "matrixSize": [1024, 1024], "scaleDenominator": 545978.773466, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "11", "matrixSize": [2048, 2048], "scaleDenominator": 272989.386733, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "12", "matrixSize": [4096, 4096], "scaleDenominator": 136494.693366, "tileSize": [256, 256], "topLeftCorner": [-20037508.3428, 20037508.3428] }, { "identifier": "13", "scaleDenominator": 68247.34668321429, "tileSize": [256, 256], "topLeftCorner": [ -20037508.342789244, 20037508.342789244 ], "matrixSize": [8191, 8191] }, { "identifier": "14", "scaleDenominator": 34123.673341607144, "tileSize": [256, 256], "topLeftCorner": [ -20037508.342789244, 20037508.342789244 ], "matrixSize": [16383, 16383] }, { "identifier": "15", "scaleDenominator": 17061.836670785713, "tileSize": [256, 256], "topLeftCorner": [ -20037508.342789244, 20037508.342789244 ], "matrixSize": [32767, 32767] }, { "identifier": "16", "scaleDenominator": 8530.918335392857, "tileSize": [256, 256], "topLeftCorner": [ -20037508.342789244, 20037508.342789244 ], "matrixSize": [65535, 65535] }, { "identifier": "17", "scaleDenominator": 4265.459167714285, "tileSize": [256, 256], "topLeftCorner": [ -20037508.342789244, 20037508.342789244 ], "matrixSize": [131071, 131071] }, { "identifier": "18", "scaleDenominator": 2132.7295838500004, "tileSize": [256, 256], "topLeftCorner": [ -20037508.342789244, 20037508.342789244 ], "matrixSize": [262143, 262143] }, { "identifier": "19", "scaleDenominator": 1066.3647919250002, "tileSize": [256, 256], "topLeftCorner": [ -20037508.342789244, 20037508.342789244 ], "matrixSize": [524287, 524287] }, { "identifier": "20", "scaleDenominator": 533.1823959625001, "tileSize": [256, 256], "topLeftCorner": [ -20037508.342789244, 20037508.342789244 ], "matrixSize": [1048575, 1048575] }, { "identifier": "21", "scaleDenominator": 266.59119798125005, "tileSize": [256, 256], "topLeftCorner": [ -20037508.342789244, 20037508.342789244 ], "matrixSize": [2097151, 2097151] }], "matrixSet": "GLOBAL_WEBMERCATOR_4_V3", "opacity": 1, "requestEncoding": "REST", "style": "default", "type": "WMTS", "version": "1.0.0" }] } }, "format": "png", "layout": "thumbnail" } if spec is None: return HTTPNotFound() for map_layer in spec["attributes"]["map"]["layers"]: if "baseURL" in map_layer and\ "ogcproxywms" in map_layer["baseURL"]: token = self.config["authtkt_secret"] if "customParams" in map_layer: map_layer["customParams"]["GP_TOKEN"] = token else: map_layer["customParams"] = {"GP_TOKEN": token} if self.request.user and\ self.request.user.ogc_role is not None and\ self.request.user.ogc_role != -1: if "customParams" in map_layer: map_layer["customParams"]["roleOGC"] =\ str(self.request.user.ogc_role) else: map_layer["customParams"] =\ {"roleOGC": str(self.request.user.ogc_role)} for layer in map_layer["layers"]: internal_wms = DBSession.query(LuxLayerInternalWMS).filter( LuxLayerInternalWMS.layer == layer).first() if internal_wms is not None and\ not self._is_authorized(internal_wms): return HTTPUnauthorized() print_servers = DBSession.query(LuxPrintServers).all() print_urls = [print_server.url for print_server in print_servers] urllib.request.getproxies = lambda: {} valid_print_urls = [] if print_urls is not None and len(print_urls) > 0: for url in print_urls: try: test_url = url.replace("/print/geoportailv3", "") urllib.request.urlopen(test_url) valid_print_urls.append(url) except Exception as e: log.exception(e) log.error("Print server not available : " + url) print_url = valid_print_urls[random.randint( 0, len(valid_print_urls) - 1)] else: print_url = self.config["print_url"] resp, content = self._proxy( "%s/buildreport.png" % (print_url), params="", method="POST", body=str.encode(dumps(spec)), headers={"Referer": "http://print.geoportail.lu/"}) resp["content-disposition"] = "filename=%s.png" % (str(layer_id)) return self._build_response(resp, content, NO_CACHE, "print")
def mutate(root, args, context, info): cls = models.Discussion discussion_id = context.matchdict['discussion_id'] discussion = cls.get(discussion_id) user_id = context.authenticated_userid or Everyone permissions = get_permissions(user_id, discussion_id) allowed = discussion.user_can( user_id, CrudPermissions.UPDATE, permissions) if not allowed: raise HTTPUnauthorized() with cls.default_db.no_autoflush as db: title_entries = args.get('title_entries') if title_entries is not None and len(title_entries) == 0: raise Exception( 'Title entries needs at least one entry') # Better to have this message than # 'NoneType' object has no attribute 'owner_object' # when creating the saobj below if title=None update_langstring_from_input_entries( discussion, 'title', title_entries) subtitle_entries = args.get('subtitle_entries') update_langstring_from_input_entries( discussion, 'subtitle', subtitle_entries) button_label_entries = args.get('button_label_entries') update_langstring_from_input_entries( discussion, 'button_label', button_label_entries) # add uploaded header image as an attachment to the discussion LANDING_PAGE_HEADER_IMAGE = models.AttachmentPurpose.LANDING_PAGE_HEADER_IMAGE.value image = args.get('header_image') if image is not None: header_images = [ att for att in discussion.attachments if att.attachmentPurpose == LANDING_PAGE_HEADER_IMAGE ] if image == 'TO_DELETE' and header_images: header_image = header_images[0] header_image.document.delete_file() db.delete(header_image.document) discussion.attachments.remove(header_image) else: filename = os.path.basename(context.POST[image].filename) mime_type = context.POST[image].type document = models.File( discussion=discussion, mime_type=mime_type, title=filename) document.add_file_data(context.POST[image].file) # if there is already an IMAGE, remove it with the # associated document if header_images: header_image = header_images[0] header_image.document.delete_file() db.delete(header_image.document) discussion.attachments.remove(header_image) db.add(models.DiscussionAttachment( document=document, discussion=discussion, creator_id=context.authenticated_userid, title=filename, attachmentPurpose=LANDING_PAGE_HEADER_IMAGE )) # add uploaded logo image as an attachment to the discussion LANDING_PAGE_LOGO_IMAGE = models.AttachmentPurpose.LANDING_PAGE_LOGO_IMAGE.value image = args.get('logo_image') if image is not None: logo_images = [ att for att in discussion.attachments if att.attachmentPurpose == LANDING_PAGE_LOGO_IMAGE ] if image == 'TO_DELETE' and logo_images: logo_image = logo_images[0] logo_image.document.delete_file() db.delete(logo_image.document) discussion.attachments.remove(logo_image) else: filename = os.path.basename(context.POST[image].filename) mime_type = context.POST[image].type document = models.File( discussion=discussion, mime_type=mime_type, title=filename) document.add_file_data(context.POST[image].file) # if there is already an IMAGE, remove it with the # associated document if logo_images: logo_image = logo_images[0] logo_image.document.delete_file() db.delete(logo_image.document) discussion.attachments.remove(logo_image) db.add(models.DiscussionAttachment( document=document, discussion=discussion, creator_id=context.authenticated_userid, title=filename, attachmentPurpose=LANDING_PAGE_LOGO_IMAGE )) db.flush() discussion = cls.get(discussion_id) return UpdateDiscussion(discussion=discussion)
def mutate(root, args, context, info): cls = models.Thematic discussion_id = context.matchdict['discussion_id'] discussion = models.Discussion.get(discussion_id) user_id = context.authenticated_userid or Everyone permissions = get_permissions(user_id, discussion_id) allowed = cls.user_can_cls(user_id, CrudPermissions.CREATE, permissions) if not allowed or (allowed == IF_OWNED and user_id == Everyone): raise HTTPUnauthorized() identifier = args.get('identifier') with cls.default_db.no_autoflush: title_entries = args.get('title_entries') if len(title_entries) == 0: raise Exception( 'Thematic titleEntries needs at least one entry') # Better to have this message than # 'NoneType' object has no attribute 'owner_object' # when creating the saobj below if title=None title_langstring = langstring_from_input_entries(title_entries) description_langstring = langstring_from_input_entries( args.get('description_entries')) kwargs = {} if description_langstring is not None: kwargs['description'] = description_langstring video = args.get('video') if video is not None: video_title = langstring_from_input_entries( video['title_entries']) if video_title is not None: kwargs['video_title'] = video_title video_description = langstring_from_input_entries( video['description_entries']) if video_description is not None: kwargs['video_description'] = video_description kwargs['video_html_code'] = video['html_code'] # Our thematic, because it inherits from Idea, needs to be # associated to the root idea of the discussion. # We create a hidden root thematic, corresponding to the # `identifier` phase, child of the root idea, # and add our thematic as a child of this root thematic. root_thematic = [ idea for idea in discussion.root_idea.get_children() if getattr(idea, 'identifier', '') == identifier ] if not root_thematic: short_title = u'Phase {}'.format(identifier) root_thematic = cls(discussion_id=discussion_id, short_title=short_title, title=langstring_from_input_entries([{ 'locale_code': 'en', 'value': short_title }]), identifier=identifier, hidden=True) discussion.root_idea.children.append(root_thematic) else: root_thematic = root_thematic[0] # take the first entry and set it for short_title short_title = title_entries[0]['value'] saobj = cls(discussion_id=discussion_id, title=title_langstring, short_title=short_title, identifier=identifier, **kwargs) root_thematic.children.append(saobj) db = saobj.db db.add(saobj) db.flush() questions_input = args.get('questions') if questions_input is not None: for question_input in questions_input: title_ls = langstring_from_input_entries( question_input['title_entries']) saobj.children.append( models.Question(title=title_ls, discussion_id=discussion_id)) db.flush() return CreateThematic(thematic=saobj)
def mutate(root, args, context, info): cls = models.Discussion discussion_id = context.matchdict['discussion_id'] discussion = models.Discussion.get(discussion_id) user_id = context.authenticated_userid or Everyone permissions = get_permissions(user_id, discussion_id) allowed = discussion.user_can( user_id, CrudPermissions.UPDATE, permissions) if not allowed: raise HTTPUnauthorized() with cls.default_db.no_autoflush as db: legal_notice_entries = args.get('legal_notice_entries') if legal_notice_entries is not None and len(legal_notice_entries) == 0: raise Exception( 'Legal notice entries needs at least one entry') # Better to have this message than # 'NoneType' object has no attribute 'owner_object' # when creating the saobj below if title=None update_langstring_from_input_entries( discussion, 'legal_notice', legal_notice_entries) terms_and_conditions_entries = args.get( 'terms_and_conditions_entries') if terms_and_conditions_entries is not None and len(terms_and_conditions_entries) == 0: raise Exception( 'Terms and conditions entries needs at least one entry') # Better to have this message than # 'NoneType' object has no attribute 'owner_object' # when creating the saobj below if title=None update_langstring_from_input_entries( discussion, 'terms_and_conditions', terms_and_conditions_entries) cookies_policy_entries = args.get('cookies_policy_entries') if cookies_policy_entries is not None and len(cookies_policy_entries) == 0: raise Exception( 'Cookies policy entries needs at least one entry') update_langstring_from_input_entries( discussion, 'cookies_policy', cookies_policy_entries) privacy_policy_entries = args.get('privacy_policy_entries') if privacy_policy_entries is not None and len(privacy_policy_entries) == 0: raise Exception( 'Privacy policy entries need to be at least one entry' ) update_langstring_from_input_entries( discussion, 'privacy_policy', privacy_policy_entries) user_guidelines_entries = args.get('user_guidelines_entries') if user_guidelines_entries is not None and len(user_guidelines_entries) == 0: raise Exception( 'User guidelines entries need to be at least one entry' ) update_langstring_from_input_entries( discussion, 'user_guidelines', user_guidelines_entries ) db.flush() legal_contents = LegalContents() return UpdateLegalContents(legal_contents=legal_contents)
def get(self): user_id = self.request.matchdict.get('user_id') if user_id != self.request.authenticated_userid.user_id: raise HTTPUnauthorized() user = User.get(user_id) return ReturnUser.build(user).serialize()
def twitter_callback(request): settings = request.registry.settings try: oauth_token = request.params['oauth_token'] except KeyError: return HTTPBadRequest('Missing required oauth_token') try: oauth_verifier = request.params['oauth_verifier'] except KeyError: return HTTPBadRequest('Missing required oauth_verifier') try: saved_oauth_token = request.session['oauth_token'] except KeyError: return HTTPBadRequest('No oauth_token was found in the session') if saved_oauth_token != oauth_token: return HTTPUnauthorized("OAuth tokens don't match") else: del request.session['oauth_token'] access_token_url = settings['twitter_access_token_url'] params = ( ('oauth_token', oauth_token), ('oauth_verifier', oauth_verifier), ) auth = auth_header('POST', access_token_url, params, settings, oauth_token) response = requests.post(access_token_url, headers={'Authorization': auth}) if response.status_code != 200: return HTTPUnauthorized(response.text) response_args = dict(urlparse.parse_qsl(response.text)) # moauth_token_secret = response_args['oauth_token_secret'] oauth_token = response_args['oauth_token'] user_id = response_args['user_id'] screen_name = response_args['screen_name'] existing_user = user_from_provider_id('twitter', user_id) if existing_user is None: # fetch Twitter info only if this is the first time for # the user sice Twitter has very strong limits for using # its APIs twitter_info = get_user_info(settings, user_id) first_name, last_name = split_name(twitter_info['name']) info = { 'screen_name': screen_name, 'first_name': first_name, 'last_name': last_name, } else: info = {} return register_or_update(request, 'twitter', user_id, info, request.route_path('home'))
def forbidden_view(request): resp = HTTPUnauthorized() resp.www_authenticate = 'Basic realm="Thinkhazard"' return resp
def unauthorized(request): if request.is_xhr: return HTTPUnauthorized() return HTTPFound( request.route_path('login', _query=[('came_from', request.url)]))
def forbidden_view(request): response = HTTPUnauthorized() response.headers.update(forget(request)) return response
def mutate(root, args, context, info): PROFILE_PICTURE = models.AttachmentPurpose.PROFILE_PICTURE.value cls = models.User discussion_id = context.matchdict['discussion_id'] discussion = models.Discussion.get(discussion_id) user_id = context.authenticated_userid or Everyone global_id = args.get('id') id_ = int(Node.from_global_id(global_id)[1]) user = cls.get(id_) permissions = get_permissions(user_id, discussion_id) allowed = user.user_can( user_id, CrudPermissions.UPDATE, permissions) if not allowed: raise HTTPUnauthorized("The authenticated user can't update this user") with cls.default_db.no_autoflush as db: username = args.get('username') if username and username != user.username_p: if db.query(models.Username).filter_by( username=username ).count(): raise Exception(u"001: We already have a user with this username.") user.username_p = username name = args.get('name') # only modify the name if it was given in parameter if name is not None: user.real_name_p = name old_password = args.get('old_password') new_password = args.get('new_password') new_password2 = args.get('new_password2') # only modify the password if it was given in parameter if old_password is not None and new_password is not None and new_password2 is not None: if not user.check_password(old_password): raise Exception(u"002: The entered password doesn't match your current password.") if new_password != new_password2: raise Exception(u"003: You entered two different passwords.") if old_password == new_password: raise Exception(u"004: The new password has to be different than the current password.") from ..auth.password import verify_password for p in user.old_passwords: if verify_password(new_password, p.password): raise Exception(u"005: The new password has to be different than the last 5 passwords you set.") user.password_p = new_password # add uploaded image as an attachment to the user image = args.get('image') if image is not None: filename = os.path.basename(context.POST[image].filename) mime_type = context.POST[image].type document = models.File( discussion=discussion, mime_type=mime_type, title=filename) document.add_file_data(context.POST[image].file) # if there is already an PROFILE_PICTURE, remove it with the # associated document images = [ att for att in user.profile_attachments if att.attachmentPurpose == PROFILE_PICTURE] if images: image = images[0] allowed = image.user_can( user_id, CrudPermissions.DELETE, permissions) if not allowed: raise HTTPUnauthorized("The authenticated user can't delete the existing AgentProfileAttachment") image.document.delete_file() db.delete(image.document) user.profile_attachments.remove(image) allowed = models.AgentProfileAttachment.user_can_cls( user_id, CrudPermissions.CREATE, permissions) if not allowed: raise HTTPUnauthorized("The authenticated user can't create an AgentProfileAttachment") discussion.db.add(models.AgentProfileAttachment( document=document, discussion=discussion, user=user, creator_id=context.authenticated_userid, title=filename, attachmentPurpose=PROFILE_PICTURE )) db.flush() return UpdateUser(user=user)