Logout fails in Turbogears 2.2.2 - python

I have app written in TG 2.2.2 with default authentication. Last days, I have problem with logging in and out. In safari, two authtkt cookies are created, one as "beta.domain.com", other ".beta.domain.com". After calling /logout_handler, cookie for domain "beta.domain.com" is deleted only but for wild domain remains. So after reloading page, user is still logged in. Problem is occuring on localhost as well on production.
Interesting is that other application on same lib version works normally, as well in other browsers, no virtualenv used.
I really don't know where the problem is so I will include any config file when requested. At beggining, app_config is included.
app_cfg.py
# -*- coding: utf-8 -*-
from tg.configuration import AppConfig
import cafeteria
from cafeteria import model
from cafeteria.lib import app_globals, helpers
base_config = AppConfig()
base_config.renderers = []
base_config.prefer_toscawidgets2 = True
base_config.package = cafeteria
base_config.renderers.append('json')
base_config.renderers.append('mako')
base_config.default_renderer = 'mako'
base_config.use_sqlalchemy = True
base_config.model = cafeteria.model
base_config.DBSession = cafeteria.model.DBSession
# Configure the authentication backend
# YOU MUST CHANGE THIS VALUE IN PRODUCTION TO SECURE YOUR APP
base_config.sa_auth.cookie_secret = "SOMESECRET"
base_config.auth_backend = 'sqlalchemy'
from tg.configuration.auth import TGAuthMetadata
# This tells to TurboGears how to retrieve the data for your user
class ApplicationAuthMetadata(TGAuthMetadata):
def __init__(self, sa_auth):
self.sa_auth = sa_auth
def get_user(self, identity, userid):
return self.sa_auth.dbsession.query(self.sa_auth.user_class).filter_by(user_name = userid).first()
def get_groups(self, identity, userid):
return (identity['user'].group.name,) if identity['user'].group_id else []
def get_permissions(self, identity, userid):
return [p.name for p in identity['user'].group.permissions] if identity['user'].group_id else []
base_config.sa_auth.dbsession = model.DBSession
base_config.sa_auth.user_class = model.User
# base_config.sa_auth.group_class = model.Group
# base_config.sa_auth.permission_class = model.Permission
base_config.sa_auth.translations.group_name = 'name'
base_config.sa_auth.translations.permission_name = 'name'
base_config.sa_auth.authmetadata = ApplicationAuthMetadata(base_config.sa_auth)
# base_config.sa_auth.authenticators = [('myauth', SomeAuthenticator()]
# base_config.sa_auth.mdproviders = [('myprovider', SomeMDProvider()]
base_config.sa_auth.form_plugin = None
base_config.sa_auth.charset = 'utf-8'
base_config.sa_auth.post_login_url = '/post_login'
base_config.sa_auth.post_logout_url = '/post_logout'

Remove all cookies of your domain. when you change your domain old cookies still remains and could cause this issue.
Why do you use both beta.domain.com and .beta.domain.com? if you don't need to use this cookie in subdomains remove the 2nd one else just use the .beta.domain.com.
If this doesn't help please attach the request and response header.

Related

Replacing def add_video(url, user_id=None, **kwargs): with a video service's api to embed videos in Python web app. What do I need to learn?

Looking to be pointed to the right direction to understand what exactly I need to learn next since there's so much info out there but I feel as if none are helping me at the moment so I'm trying to get a gist of what I need to understand more of to get this part covered.
I learned a bit of Python from Justin Mitchel from his 30 days of Python and from his Create a Video Membership Web App from Scratch with Python, NoSQL, & FastAPI 11 Hr video and I understand more but I realized that there's a few things I need help with.
I plan on learning more about htmx to get better with pages but using the pages for specifics videos via an api service has me baffled at the moment. The 2 apis I plan on using are Streamtape & Doodstream.
https://github.com/wahyubiman/DoodStream
https://github.com/scaldings/streamtape-api-python
My current requirement.txt are
fastapi
uvicorn
cassandra-driver
python-dotenv
email-validator
argon2-cffi
pytest
jinja2
python-multipart
python-jose[cryptography]
algoliasearch
doodstream
Had to manually install streamtape.
So the current code for my model.py for videos is
import uuid
from app.config import get_settings
from app.users.exceptions import InvalidUserIDException
from app.users.models import User
from app.shortcuts import templates
from cassandra.cqlengine import columns
from cassandra.cqlengine.models import Model
from cassandra.cqlengine.query import (DoesNotExist, MultipleObjectsReturned)
settings = get_settings()
from .exceptions import (
InvalidVideoURLException,
VideoAlreadyAddedException
)
# Unlisted Video -> video_id -> lock it down
class Video(Model):
__keyspace__ = settings.keyspace
host_id = columns.Text(primary_key=True) # Streamtape, Doodstream
db_id = columns.UUID(primary_key=True, default=uuid.uuid1) # UUID1
host_service = columns.Text(default='Doodstream')
title = columns.Text()
url = columns.Text() # secure
user_id = columns.UUID()
def __str__(self):
return self.__repr__()
def __repr__(self):
return f"Video(title={self.title}, host_id={self.host_id}, host_service={self.host_service})"
def render(self):
basename = self.host_service # streamtape, doodstream
template_name = f"videos/renderers/{basename}.html"
context = {"host_id": self.host_id}
t = templates.get_template(template_name)
return t.render(context)
def as_data(self):
return {f"{self.host_service}_id": self.host_id, "path": self.path, "title": self.title}
#property
def path(self):
return f"/videos/{self.host_id}"
#staticmethod
def get_or_create(url, user_id=None, **kwargs):
host_id = extract_video_id(url)
obj = None
created = False
try:
obj = Video.objects.get(host_id=host_id)
except MultipleObjectsReturned:
q = Video.objects.allow_filtering().filter(host_id=host_id)
obj = q.first()
except DoesNotExist:
obj = Video.add_video(url, user_id=user_id, **kwargs)
created = True
except:
raise Exception("Invalid Request")
return obj, created
#staticmethod
def add_video(url, user_id=None, **kwargs):
# extract video_id from url
# video_id = host_id
# Service API - Streamtape / Doostream / etc
host_id = extract_video_id(url)
if host_id is None:
raise InvalidVideoURLException("Invalid Video URL")
user_exists = User.check_exists(user_id)
if user_exists is None:
raise InvalidUserIDException("Invalid user_id")
# user_obj = User.by_user_id(user_id)
# user_obj.display_name
q = Video.objects.allow_filtering().filter(host_id=host_id) # , user_id=user_id)
if q.count() != 0:
raise VideoAlreadyAddedException("Video already added")
return Video.create(host_id=host_id, user_id=user_id, url=url, **kwargs)
# class PrivateVideo(Video):
# pass
What I'm trying to figure out is
How can I replace the static method with my API so it can pull on search requests if that makes sense? Like if someone is searching for something specific it brings them to a search page that pulls to whatever's close to what's looked for from Streamtape/Doodstream.
Or if I want to have preset tags for them to click on it shows all the videos available to be played, in which they can choose either the Streamtape server or the Doodstream server.
For the tags, would it be wise to make a separate html page per tag, to where it pulls from the specific folder of videos I want it to pull from? Like on the navigation bar has categories, and when clicking on categories it shows different ones like Education, Travel, etc and when they click on one it shows all the videos available that matches the folder from Stream/Dood that I want it to pull from.
What do I need to learn to get anywhere close to achieving something like that?

django rest framework parser returns before all statements are executed

I am using django and django-rest-framework at the latest versions available on the stable channel on pipy - though, the issue is reproducible on older codebases (django version 2.x) as well.
The issue is when I try to define a custom parser (as per here) and an example that illustrates the issue is shown below:
import logging
import json
import jsonschema
from rest_framework.exceptions import ParseError
from rest_framework.parsers import JSONParser
log = logging.getLogger('logger')
class JSONCustomParser(JSONParser):
def parse(self, stream, media_type=None, parser_context=None):
data = super(JSONCustomParser, self). \
parse(stream, media_type, parser_context)
try:
# these are executed normally
a = 1
b = 2
# problematic bits: un-comment either of these and execution ends early.
# data = json.load(stream.read())
# data = json.load("{}")
# data = JSONParser().parse(stream)
# auth_name = str(parser_context['request'].auth.application)
# sample commands not executed if they are *after* the above and either if them is
# un-commented
a = a + a
b = a + 2
except ValueError:
log.error("Value error")
except Exception as generic_exception:
log.error(str(generic_exception))
else:
return data
And a very simple test view that you can use:
class TestView(APIView):
"""
Simple test view to test the parser
"""
parser_classes = (JSONCustomParser,)
permission_classes = ()
def post(self, request):
content_length = request.META['CONTENT_LENGTH']
return Response({'received': content_length})
I assume the two stream consume operations force a return, although not too sure since the stream is consumed by JSONParser anyway in the super call... However, I am not certain why the others pose an issue...

Robobrowser and flask errors

I am trying to create a script for myself to use on a few classified sites and starting with cl, I am using flask web framework and robobrowser but not going so well.
The Goal It will take my preset values and put them in the fields from that classifieds websites. Doesnt seem like a difficult concept however after 5 hours of reading online different code and trial and error I remembered the best developers are on stack...
I should inform you I am new to Python and still have alot to learn so any help would be greatly appreciated.
The error I get is:
assert isinstance(form, 'str')
TypeError: isinstance() arg 2 must be a type or tuple of types
but I dont see how to fix this and completely lost. HELP!!!
thanks in advance
# autosubmit to site
from flask import Flask
from robobrowser import RoboBrowser
app = Flask(__name__)
#app.route('/', methods = ['GET', 'POST'])
class My_RoboBrowser(RoboBrowser):
def __init__(self, auth=None, parser=None, headers=None, user_agent=None, history=True):
RoboBrowser.__init__(self, parser=None, user_agent=None, history=True)
def Open(self, vURL, vVerify=True):
response = self.session.get(vURL, verify=vVerify)
self._update_state(response)
browser = My_RoboBrowser(RoboBrowser, "html.parser");
urlL = 'https://accounts.craigslist.org/login'
browser.Open(urlL)
form = browser.get_form(id='login')
assert isinstance(form, 'str')
form['username'] = 'username'
form['password'] = 'password'
browser.submit_form(form)
urlQ = 'https://post.craigslist.org/k/qGDv7K4q5RGD0B5ZEBgXOQ/GLzgd?s=edit'
browser.open(urlQ)
#Question_Tag = browser.find_all(class_="not_answered")[0]
#ID = Question_Tag.get('data-qid')
#Get the form to fill out
Form = browser.get_form(id='formpost')
Form['PostingTitle'].value = 'Create this advertise ment in py'
Form['Postal_code'].value = ['10543']
Form['PostingBody'].value = 'TOGETHER WE INNOVATE Stress free communication with developers that are in the United States. We pride ourselves in bringing your web and app ideas to life and keeping your data secured'
browser.submit_form(Form)
if __name__ == "__main__":
app.run()
isinstance returns true if the first argument is an instance (or subclass) of the second argument otherwise false. In your assertion the form variable is of type robobrowser.forms.form.Form. You can see this with the following code:
print(type(form)) # should print <class 'robobrowser.forms.form.Form'>
Your particular assertion will pass if you update the second argument to indicate this robobrowser Form class:
# Add the following to your imports
import robobrowser
# ... existing code below imports
# The following should be true if form is valid
assert isinstance(form, robobrowser.forms.form.Form)
You can also import the Form class directly but you'll have to update the assertion accordingly:
from robobrowser.forms.form import Form
# ... existing code below imports
assert isinstance(form, Form)
Edit:
Below is the code to properly get the form from that page. There are no forms with an id of 'login' but you can select it by using its action or grabbing the first form on the page.
# ... previous code ...
form = browser.get_form(action='https://accounts.craigslist.org/login')
# you can also use: form = browser.get_form(0)
# It looks like you aren't selecting the fields by their proper names either.
form['inputEmailHandle'] = 'fill in username here'
form['inputPassword'] = 'fill in password here'
browser.submit_form(form)
See if the added code above helps.

Add Entries Python-LDAP

I'm trying to add entries with python ldap. I'm getting a naming convention error. My code is
import ldap
import ldap.modlist as modlist
LOGIN = ""
PASSWORD = ''
LDAP_URL = "ldap://127.0.0.1:389"
user='grant'
l = ldap.initialize(LDAP_URL)
l.bind(LOGIN, PASSWORD)
dn="ou=Enki Users,dc=enki,dc=local"
attrs = {}
attrs['objectclass'] = ['top','organizationalRole','simpleSecurityObject']
attrs['cn'] = 'test'
attrs['userPassword'] = 'test'
attrs['description'] = 'User object for replication using slurpd'
# Convert our dict to nice syntax for the add-function using modlist-module
ldif = modlist.addModlist(attrs)
# Do the actual synchronous add-operation to the ldapserver
l.add_s(dn,ldif)
# Its nice to the server to disconnect and free resources when done
l.unbind_s()
The error is:
ldap.NAMING_VIOLATION: {'info': "00002099: NameErr: DSID-0305109C, problem 2005 (NAMING_VIOLATION), data 0, best match of:\n\t'dc=enki,dc=local'\n", 'desc': 'Naming violation'}
The code that runs but doesn't insert the user into the correc organizational unit is the following code. However even though it runs I can't find the user in active directory. Please help me find whats wrong. I'm basically making a django webform for user management.
import ldap
import ldap.modlist as modlist
LOGIN = ""
PASSWORD = ''
LDAP_URL = "ldap://127.0.0.1:389"
user='grant'
l = ldap.initialize(LDAP_URL)
l.bind(LOGIN, PASSWORD)
dn="cn=test,ou=Enki Users,dc=enki,dc=local"
attrs = {}
attrs['objectclass'] = ['top','organizationalRole','simpleSecurityObject']
attrs['cn'] = 'test'
attrs['userPassword'] = 'test'
attrs['description'] = 'User object for replication using slurpd'
# Convert our dict to nice syntax for the add-function using modlist-module
ldif = modlist.addModlist(attrs)
# Do the actual synchronous add-operation to the ldapserver
l.add_s(dn,ldif)
# Its nice to the server to disconnect and free resources when done
l.unbind_s()
I speculate (but have not tested to prove it) that the root cause of your error is that your entry does not contain a "naming attribute" that matches the leftmost attribute in the DN of your entry, which in your case is ou=Enki Users. To add this naming attribute to the entry, you can add the following line in the part of your code that populates the attrs dict.
attrs['ou'] = 'Enki Users'

Retrieve an app configuration setting in a non-request context in Pyramid

In a pyramid app I am building (called pyplay), I need to retrieve an application setting that I have in development.ini. The problem is that the place where I am trying to get that setting cannot access the request variable (e.g. at the top level of a module file).
So, after looking at this example in the documentation: http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration/django_settings.html I started doing something very simple and hardcoded at first just to make it work.
Since my development.ini has this section: [app:main], then the simple example I tried is as follows:
from paste.deploy.loadwsgi import appconfig
config = appconfig('config:development.ini', 'main', relative_to='.')
but the application refuses to start and displays the following error:
ImportError: <module 'pyplay' from '/home/pish/projects/pyplay/__init__.pyc'> has no 'main' attribute
So, thinking that maybe I should put 'pyplay' instead of 'main', I went ahead, but I get this error instead:
LookupError: No section 'pyplay' (prefixed by 'app' or 'application' or 'composite' or 'composit' or 'pipeline' or 'filter-app') found in config ./development.ini
At this point I am a bit stuck and I don't know what am I doing wrong. Can someone please give me a hand on how to do this?
Thanks in advance!
EDIT: The following are the contents of my development.ini file (note that pish.theparam is the setting I am trying to get):
###
# app configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
use = egg:pyplay
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en_US.utf8
pyramid.includes =
pyramid_debugtoolbar
pyramid_tm
sqlalchemy.url = mysql://user:passwd#localhost/pyplay?charset=utf8
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
debugtoolbar.hosts = 127.0.0.1 ::1
pish.theparam = somevalue
###
# wsgi server configuration
###
[server:main]
use = egg:waitress#main
host = 0.0.0.0
port = 6543
###
# logging configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
keys = root, pyplay, sqlalchemy
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = INFO
handlers = console
[logger_pyplay]
level = DEBUG
handlers =
qualname = pyplay
[logger_sqlalchemy]
level = INFO
handlers =
qualname = sqlalchemy.engine
# "level = INFO" logs SQL queries.
# "level = DEBUG" logs SQL queries and results.
# "level = WARN" logs neither. (Recommended for production systems.)
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s
The reason it's difficult to do in pyramid is because it's always a bad idea to have module-level settings. It means your module can only ever be used in one way per-process (different code-paths can't use your library in different ways). :-)
A hack around not having access to the request object is to at least hide your global behind a function call, so that the global can be different per-thread (which is basically per-request).
def get_my_param(registry=None):
if registry is None:
registry = pyramid.threadlocals.get_current_registry()
return registry.settings['pyplay.theparam']
Step 1: create a singleton class say in a file xyz_file
class Singleton:
def __init__(self, klass):
self.klass = klass
self.instance = None
def __call__(self, *args, **kwds):
if self.instance == None:
self.instance = self.klass(*args, **kwds)
return self.instance
#Singleton
class ApplicationSettings(object):
def __init__(self, app_settings=None):
if app_settings is not None :
self._settings = app_settings
def get_appsettings_object(self):
return self
def get_application_configuration(self):
return self._settings
Step 2: in "__ init__.py"
def main(global_config, **settings):
....
.......
app_settings = ApplicationSettings(settings)
Step 3: You should be able to access in any part of the code.
from xyz_file import ApplicationSettings
app_settings = ApplicationSettings().get_application_configuration()
Basically, if you don't have access to the request object, you're "off the rails" in Pyramid. To do things the Pyramid way, we make components and figure out where they belong in the Pyramid lifecycle, and they should always have direct access to either or both of the registry (the ZCA) and the request.
If what you're doing doesn't fit in the the request lifecycle, then it's probably something that should be instantiated at server start up time, normally in your init.py where you build and fill the configurator (our access to the registry). Don't be afraid to use the registry to allow other components to get at things 'pseudo-globally' later. So probably you want to make some kind of factory for your thing, call the factory in your start up code, perhaps passing in a reference to the registry as an argument, and then attach the object to the registry. If your component needs to interface with request-lifecycle code, give it a method that takes request as a param. Later anything that needs at this object can get it from registry, and anything this object needs to get at can be done either through registry or request.
You can totally use the hack in the other answer to get at the current global registry, but needing to do so is a code smell, you can def figure out a better design to eliminate that.
pseudo code example, in the server start up code:
# in in the init block where our Configurator has been built
from myfactory import MyFactory
registry.my_component = MyFactory(config.registry)
# you can now get at my_component from anywhere in a pyramid system
your component:
class MyFactory(oject):
def __init__(self, registry):
# server start up lifecycle stuff here
self.registry = registry
def get_something(self, request):
# do stuff with the rest of the system
setting_wanted = self.registry.settings['my_setting']
Pyramid Views work this way. They are actually ZCA multi-adapters of request and context. Their factory is registered in the registry, and then when the view look up process kicks off, the factory instantiates a view passing in request as a param.

Categories

Resources