I am trying to use keycloak with apache superset. I have spent hours on the links below but unable to replace the current login.
Using OpenID/Keycloak with Superset
2.Using KeyCloak(OpenID Connect) with Apache SuperSet
Using OpenID/Keycloak with Superset
I am using apache superset 0.34.5. While above links use 0.28 and below.
i am confused at inital step. let me explain the steps and see what i am missing.
I install superset using pip.
The structure i have is, i have config.py and security.py at the same level (i dont have security folder)
I renamed the security to oid_security.
I created a security.py with the following content.
from flask_appbuilder.security.manager import AUTH_OID
from superset.security import SupersetSecurityManager
from flask_oidc import OpenIDConnect
from flask_appbuilder.security.views import AuthOIDView
from flask_login import login_user
from urllib.parse import quote
from flask_appbuilder.views import ModelView, SimpleFormView, expose
import logging
class AuthOIDCView(AuthOIDView):
#expose('/login/', methods=['GET', 'POST'])
def login(self, flag=True):
sm = self.appbuilder.sm
oidc = sm.oid
#self.appbuilder.sm.oid.require_login
def handle_login():
user = sm.auth_user_oid(oidc.user_getfield('email'))
if user is None:
info = oidc.user_getinfo(['preferred_username', 'given_name', 'family_name', 'email'])
user = sm.add_user(info.get('preferred_username'), info.get('given_name'), info.get('family_name'), info.get('email'), sm.find_role('Gamma'))
login_user(user, remember=False)
return redirect(self.appbuilder.get_url_for_index)
return handle_login()
#expose('/logout/', methods=['GET', 'POST'])
def logout(self):
oidc = self.appbuilder.sm.oid
oidc.logout()
super(AuthOIDCView, self).logout()
redirect_url = request.url_root.strip('/') + self.appbuilder.get_url_for_login
return redirect(oidc.client_secrets.get('issuer') + '/protocol/openid-connect/logout?redirect_uri=' + quote(redirect_url))
class OIDCSecurityManager(SupersetSecurityManager):
authoidview = AuthOIDCView
def __init__(self,appbuilder):
super(OIDCSecurityManager, self).__init__(appbuilder)
if self.auth_type == AUTH_OID:
self.oid = OpenIDConnect(self.appbuilder.get_app)
I then created custom manager with the following
from flask_appbuilder.security.manager import AUTH_OID
from flask_appbuilder.security.sqla.manager import SecurityManager
from flask_oidc import OpenIDConnect
class OIDCSecurityManager(SecurityManager):
def __init__(self, appbuilder):
super(OIDCSecurityManager, self).__init__(appbuilder)
if self.auth_type == AUTH_OID:
self.oid = OpenIDConnect(self.appbuilder.get_app)
self.authoidview = AuthOIDCView
I created client secret.json with my credentials.
I edited config file as below.
from superset.security import OIDCSecurityManager
AUTH_TYPE = AUTH_OID
OIDC_CLIENT_SECRETS = 'client_secret.json'
OIDC_ID_TOKEN_COOKIE_SECURE = False
OIDC_REQUIRE_VERIFIED_EMAIL = False
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = 'Gamma'
CUSTOM_SECURITY_MANAGER = OIDCSecurityManager
One thing to mention here is have manager py in security folder in flask appbuilder which has Abstract Security Manager cls. I am getting an error security py
It says cannot import name SupersetSecurityManager from superset - security
anyone please?
I suggest you start afresh and follow the steps that worked for me:
Create a virtual environment within your superset directory and activate it.
Install the flask-oidc and superset plugins within your virtual environment. pip install flask-oidc
Have a oidc_security.py file with the script you pasted above i.e. security.py in your setup.
Have a client_secret.json file with your keycloak config.
Have a superset_config.py with the script you pasted above.
Add all three of these files to your pythonpath.
Run superset db upgrade & superset init commands.
Finally, execute superset run. After the initialization completes, navigate to http://localhost:8088 on your browser. Expected behaviour: you'll be redirected to keycloak to login/register. After successful sign in, you'll be redirected to superset app.
I hope this helps. Do post back incase you succeed or face an error.
I then created custom manager with the following
where to update this??
from flask_appbuilder.security.manager import AUTH_OID
from flask_appbuilder.security.sqla.manager import SecurityManager
from flask_oidc import OpenIDConnect
class OIDCSecurityManager(SecurityManager):
def __init__(self, appbuilder):
super(OIDCSecurityManager, self).__init__(appbuilder)
if self.auth_type == AUTH_OID:
self.oid = OpenIDConnect(self.appbuilder.get_app)
self.authoidview = AuthOIDCView
Related
So im running mitmproxy for windows and im trying to run a script that saves responses and requests into postgresql, for this im using sqlalchemy
But i cannot make it work with mimtproxy for some reason, when running seems like its using another python interpreter and my code is not working. Does mitmproxy use a different interpreter appart from the one you have installed?
Command running from mimtmproxy/bin folder:
mitmdump.exe -s C:\users\etc\{FULL_PATH}\mitmproxy.py
im getting
"No module instaled named SQLAlchemy"
i already tried to installing via pip and pip3 the module is telling me im missing(sqlalchemy) but its already installed
enter image description here
mimtproxy.py
from mitmproxy import http
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session
from entities.models.Request import RequestModel
from entities.models.Response import ResponseModel
from entities.models.Session import SessionModel
server = 'www.XXX.com'
world = 'XXX'
user = 'XXX'
version = None
engine = create_engine('postgresql://XXX:XXX#localhost:5432/XXX')
Base = declarative_base()
def createSession():
with Session(engine) as session:
http_session = SessionModel(server=server,world=world,version=version,user=user)
session.add(http_session)
# We add created object to our DB
session.flush()
# At this point, the object has been pushed to the DB,
# and has been automatically assigned a unique primary key id
session.refresh(http_session)
# refresh updates given object in the session with its state in the DB
# (and can also only refresh certain attributes - search for documentation)
return http_session
session_object = createSession()
with Session(engine) as session:
session.add(session_object)
session.commit()
def request(flow: http.HTTPFlow) -> None:
if flow.request.headers['x-ig-client-version'] and session_object.version == None:
session_object.version = flow.request.headers['x-ig-client-version']
with Session(engine) as session:
session.commit()
request_url = flow.request.url
request_cookies = None
if flow.request.cookies:
request_cookies = flow.request.cookies
Request = RequestModel(method=flow.request.method,url=request_url)
Request.headers = flow.request.headers
Request.cookies = request_cookies
Request.body = flow.request.content
Request.timestamp_start = flow.request.timestamp_start
Request.timestamp_end = flow.request.timestamp_end
Request.size = len(flow.request.content)
Response = ResponseModel(headers=flow.response.headers,
status_code=flow.response.status_code,body=flow.response.content)
Response.cookies = None
if flow.response.cookies:
Response.cookies = flow.response.cookies
Request.response = Response
session_object.requests.append([Request])
with Session(engine) as session:
session.commit()
all sqlalchemy models are here:
AttributeError: 'set' object has no attribute '_sa_instance_state' - SQLAlchemy
If you want to use Python packages that are not included in mitmproxy's own installation, you need to install mitmproxy via pip or pipx. The normal binaries include their own Python environment.
Source:
https://docs.mitmproxy.org/stable/overview-installation/#installation-from-the-python-package-index-pypi.
I am trying to write a Python application which simply adds a user as a delegate to another users mailbox.
I am following the API # Google API Documentation - Users.settings.delegates: create
However, I am struggling to find how to the parameters of:
User - an account which is TOBE added to a delegate Mailbox
Mailbox - the account which has the Mailbox I wish the account to become a delegate of.
I have currently tried making an API which has the delegate user. However, it does not seem to be interacting how I would expect. I am hoping Google will create a responsive API for the browser to support this. However, I am struggling with the code:
from googleapiclient import discovery
from oauth2client.service_account import ServiceAccountCredentials
def main(user_to_be_added, delegated_mailbox):
service_account_credentials = ServiceAccountCredentials.from_json_keyfile_name('credentials/service_account.json')
service_account_credentials = service_account_credentials.create_scoped('https://mail.google.com/ https://www.googleapis.com/auth/gmail.insert https://www.googleapis.com/auth/gmail.modify')
service_account_credentials = service_account_credentials.create_delegated(user_to_be_added)
service = discovery.build('gmail', 'v1', credentials=service_account_credentials)
response = service.users().settings().delegates().create().execute(userId=delegated_mailbox)
if __name__ == '__main__':
main('some_account_to_be_added#gmail.com', 'delegated_mailbox#gmail.com')
Am I interacting with this API completely wrong? If so, how has anyone else achieved this?
Thank you for your time.
Jordan
Working Solution:
from googleapiclient import discovery
from google.oauth2 import service_account
def _create_client(subject):
credentials = service_account.Credentials
credentials = credentials.from_service_account_file('credentials/service_account.json',
scopes=['https://www.googleapis.com/auth/gmail.settings.sharing',
'https://www.googleapis.com/auth/gmail.settings.basic'],
subject=subject)
service = discovery.build('gmail', 'v1', credentials=credentials)
return service
def add_delegate_to_email(user_to_be_added, delegated_mailbox):
service = _create_client(user_to_be_added)
body = {
"delegateEmail": delegated_mailbox,
"verificationStatus": "accepted"
}
try:
response = service.users().settings().delegates().create(userId='me', body=body).execute()
print(response)
except Exception as e:
print('Exception: {}'.format(e))
Main problem: from oauth2client.service_account import ServiceAccountCredentials is deprecated as Google took ownership with google-auth.
I'm trying to run the code below and it ends up with the error :
azure.graphrbac.models.graph_error.GraphErrorException: Insufficient
privileges to complete the operation.
prerequisite:
create an azure app with Microsoft Graph permissions
The code (python):
from azure.graphrbac import graph_rbac_management_client
from msrestazure.azure_active_directory import ServicePrincipalCredentials
class TestAzureStuff(object):
def __init__(self):
self.tenant = "**YOUR*tenant******"
self.client = "*****YOUR*client*****"
self.secret = "******YOUR*secret****"
self.subscription = "*****YOUR*subscription****"
self.credentials = ServicePrincipalCredentials(client_id=self.client,
secret=self.secret,
tenant=self.tenant,
resource="https://graph.windows.net")
def remove_app(self):
client = graph_rbac_management_client.GraphRbacManagementClient(self.credentials,
self.tenant)
client.users.list().next()
stuff = TestAzureStuff()
stuff.remove_app()
the only way it does work is when instead of the ServicePrincipalCredentials I use UserPassCredentials with my own credentials.
I also Checked maybe there are some permissions differences between the app and my own user and looks like they have same permissions.
Do you have any clue what permission is missing?
or maybe I'm missing something else here?
When testing my Pyramid application using WebTest, I have not been able to create/use a separate Session in my tests without getting warnings about a scoped session already being present.
Here is the main() function of the Pyramid application, which is where the database is configured.
# __init__.py of Pyramid application
from pyramid_sqlalchemy import init_sqlalchemy
from sqlalchemy import create_engine
def main(global_config, **settings):
...
db_url = 'some-url'
engine = create_engine(db_url)
init_sqlalchemy(engine) # Warning thrown here.
Here is the test code.
# test.py (Functional tests)
import transaction
from unittest import TestCase
from pyramid.paster import get_appsettings
from pyramid_sqlalchemy import init_sqlalchemy, Session
from sqlalchemy import create_engine
from webtest import TestApp
from app import main
from app.models.users import User
class BaseTestCase(TestCase):
def base_set_up(self):
# Create app using WebTest
settings = get_appsettings('test.ini', name='main')
app = main({}, **settings)
self.test_app = TestApp(app)
# Create session for tests.
db_url = 'same-url-as-above'
engine = create_engine(db_url)
init_sqlalchemy(engine)
# Note: I've tried both using pyramid_sqlalchemy approach here and
# creating a "plain, old" SQLAlchemy session here using sessionmaker.
def base_tear_down(self):
Session.remove()
class MyTests(BaseTestCase):
def setUp(self):
self.base_set_up()
with transaction.manager:
self.user = User('user#email.com', 'John', 'Smith')
Session.add(self.user)
Session.flush()
Session.expunge_all()
...
def tearDown(self):
self.base_tear_down()
def test_1(self):
# This is a typical workflow on my tests.
response = self.test_app.patch_json('/users/{0}'.format(self.user.id), {'email': 'new.email#email.com')
self.assertEqual(response.status_code, 200)
user = Session.query(User).filter_by(id=self.user.id).first()
self.assertEqual(user.email, 'new.email#email.com')
...
def test_8(self):
...
Running the tests gives me 8 passed, 7 warnings, where every test except the first one gives the following warning:
From Pyramid application: __init__.py -> main -> init_sqlalchemy(engine):
sqlalchemy.exc.SAWarning: At least one scoped session is already present. configure() can not affect sessions that have already been created.
If this is of any use, I believe I am seeing the same issue here, except I am using pyramid_sqlalchemy rather than creating my own DBSession.
https://github.com/Pylons/webtest/issues/5
Answering my own question: I'm not sure if this is the best approach, but one that worked for me.
Instead of trying to create a separate session within my tests, I am instead using the pyramid_sqlalchemy Session factory, which is configured in the application. As far as I can tell, calls to Session in both test and application code return the same registered scoped_session.
My original intent with creating a separate session for my tests was to confirm that records were being written to the database, and not just updated in the active SQLAlchemy session. With this new approach, I've managed to avoid these "caching" issues by issuing Session.expire_all() at points in the tests where I transition between test transactions and application transactions.
# test.py (Functional tests)
import transaction
from unittest import TestCase
from pyramid.paster import get_appsettings
from pyramid_sqlalchemy import Session
from webtest import TestApp
from app import main
from app.models.users import User
class BaseTestCase(TestCase):
def base_set_up(self):
# Create app using WebTest
settings = get_appsettings('test.ini', name='main')
app = main({}, **settings)
self.test_app = TestApp(app)
# Don't set up an additional session in the tests. Instead import
# and use pyramid_sqlalchemy.Session, which is set up in the application.
def base_tear_down(self):
Session.remove()
class MyTests(BaseTestCase):
def setUp(self):
self.base_set_up()
with transaction.manager:
self.user = User('user#email.com', 'John', 'Smith')
Session.add(self.user)
Session.flush()
Session.expunge_all()
Session.expire_all() # "Reset" your session.
def tearDown(self):
self.base_tear_down()
I follow the official docs, and set it step by step.
Using browser point to http://localhost:6543/sacrud/, here raise 403 Forbidden error. I'm trying to delete sa_home function's parameter permission in pyramid_sacrud/views/init.py to solve it, though It could be access but it hasn't login page in there.
Here is my app's ini file:
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.session import SignedCookieSessionFactory
from pyraid_blogr.models.models import BlogRecord, User
from .models.meta import (
DBSession,
Base,
)
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
DBSession.configure(bind=engine)
Base.metadata.bind = engine
authentication_policy = AuthTktAuthenticationPolicy('your_secret', hashalg='sha512')
authorization_policy = ACLAuthorizationPolicy()
config = Configurator(settings=settings,
authentication_policy=authentication_policy,
authorization_policy=authorization_policy
)
config.set_session_factory(SignedCookieSessionFactory('replace_your_secret'))
config.include('pyramid_mako',)
config.include('pyramid_sacrud',)
settings = config.registry.settings
settings['pyramid_sacrud.models'] = (('Group1', [BlogRecord]), ('Group2', [User]))
config.add_static_view('static', 'static', cache_max_age=3600)
config.add_route('home', '/')
config.add_route('blog', '/blog/{id:\d+}/{slug}', request_method='GET')
config.add_route('blog_action', '/blog/{action}', factory='pyraid_blogr.security.BlogRecordFactory')
config.add_route('auth', 'sign/{action}')
config.scan()
return config.make_wsgi_app()
Here is the debug info
permission pyramid_sacrud_home value 'pyramid_sacrud_home' Source
Line 45 of file
/Users/liu-minglei/Web-Dev/my_pyramid/pyraid_blogr/admin/views/init.py:
permission=PYRAMID_SACRUD_HOME References view function
admin.views.sa_home
I have created an example with authorization (https://github.com/ITCase/pyramid_sacrud/tree/master/example), in your case, you seem to have edit pyramid_sacrud/views/init.py file that is not location in your python env or not reload server. For your app you must add sacrud permission (http://pyramid-sacrud.readthedocs.org/en/latest/pages/permissions.html) to root_factory.