allow usage of OIDC authentication (via py-scopes) where appropriate, and provide corresponding views in loops/server/auth.zcml
This commit is contained in:
parent
80c83d5c9f
commit
1d264fc54f
9 changed files with 65 additions and 21 deletions
|
@ -24,6 +24,8 @@
|
|||
<include package="cyberapps.ccmkg" />
|
||||
<include package="cyberapps.knowledge" />-->
|
||||
|
||||
<include package="loops.server" file="auth.zcml" />
|
||||
|
||||
<!-- Override registrations -->
|
||||
<includeOverrides package="loops" file="overrides.zcml" />
|
||||
<includeOverrides file="overrides.zcml" />
|
||||
|
|
|
@ -9,6 +9,7 @@ server_id = getenv('SERVER_ID')
|
|||
zope_conf = getenv('ZOPE_CONF', 'zope.conf')
|
||||
server_port = getenv('SERVER_PORT',
|
||||
server_id and getenv(f'SERVER_PORT_{server_id}')) or '8080'
|
||||
base_url = getenv('BASE_URL', 'https://test.example.com')
|
||||
|
||||
shell_pw = (getenv('SHELL_PW', 'dummy'))
|
||||
loops_path = (getenv('LOOPS_PATH', 'loops/demo'))
|
||||
|
@ -20,3 +21,20 @@ dbname = getenv('DBNAME', 'demo')
|
|||
dbuser = getenv('DBUSER', 'demo')
|
||||
dbpassword = getenv('DBPASSWORD', 'secret')
|
||||
dbschema = getenv('DBSCHEMA', 'demo')
|
||||
|
||||
# OpenID Connect (OIDC, e.g. via zitadel) authentication settings
|
||||
oidc_provider = getenv('OIDC_PROVIDER', '') #'https://instance1-abcdef.zitadel.cloud')
|
||||
oidc_client_id = getenv('OIDC_CLIENT_ID', '12345')
|
||||
oidc_params = dict(
|
||||
op_config_url=oidc_provider + '/.well-known/openid-configuration',
|
||||
op_uris=None,
|
||||
op_keys=None,
|
||||
callback_url=getenv('OIDC_CALLBACK_URL', base_url + '/auth_callback'),
|
||||
client_id=oidc_client_id,
|
||||
principal_prefix=getenv('OIDC_PRINCIPAL_PREFIX', 'loops.'),
|
||||
cookie_name=getenv('OIDC_COOKIE_NAME', 'oidc_' + oidc_client_id),
|
||||
cookie_domain=getenv('OIDC_COOKIE_DOMAIN', None),
|
||||
cookie_lifetime=getenv('OIDC_COOKIE_LIFETIME', '86400'),
|
||||
cookie_crypt=getenv('OIDC_COOKIE_CRYPT', None)
|
||||
)
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ from loops.interfaces import HtmlText
|
|||
from loops.organize.util import getPrincipalFolder, getPrincipalForUserId
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
from scopes.web.auth import oidc
|
||||
|
||||
ANNOTATION_KEY = 'loops.organize.person'
|
||||
|
||||
|
@ -34,7 +33,7 @@ def raiseValidationError(info):
|
|||
|
||||
|
||||
class UserId(schema.TextLine):
|
||||
""" Obsolete, as member registration does not use zope.formlib any more.
|
||||
""" Note: member registration does not use zope.formlib any more.
|
||||
TODO: transfer validation to loops.organize.browser.
|
||||
"""
|
||||
|
||||
|
@ -44,11 +43,6 @@ class UserId(schema.TextLine):
|
|||
from loops.organize.party import getPersonForUser
|
||||
context = removeSecurityProxy(self.context).context
|
||||
principal = getPrincipalForUserId(userId, context)
|
||||
#auth = component.getUtility(IAuthentication, context=context)
|
||||
#try:
|
||||
#principal = auth.getPrincipal(userId)
|
||||
#except PrincipalLookupError:
|
||||
#principal = oidc.Principal(userId, dict(name=userId))
|
||||
if principal is None:
|
||||
raiseValidationError(_('User $userId does not exist',
|
||||
mapping={'userId': userId}))
|
||||
|
|
|
@ -33,7 +33,6 @@ from loops.security.common import getCurrentPrincipal
|
|||
from loops.security.interfaces import ISecuritySetter
|
||||
from loops.type import TypeInterfaceSourceList
|
||||
from loops import util
|
||||
from scopes.web.auth import oidc
|
||||
|
||||
|
||||
# register type interfaces - (TODO: use a function for this)
|
||||
|
@ -87,7 +86,6 @@ class Person(AdapterBase, BasePerson):
|
|||
setter = ISecuritySetter(self)
|
||||
if userId:
|
||||
principal = self.getPrincipalForUserId(userId)
|
||||
print('***', userId, principal)
|
||||
if principal is None:
|
||||
return
|
||||
person = getPersonForUser(self.context, principal=principal)
|
||||
|
@ -144,14 +142,6 @@ class Person(AdapterBase, BasePerson):
|
|||
def getPrincipalForUserId(self, userId=None):
|
||||
userId = userId or self.userId
|
||||
return getPrincipalForUserId(userId, self.context, self.authentication)
|
||||
if not userId:
|
||||
return None
|
||||
auth = self.authentication
|
||||
try:
|
||||
return auth.getPrincipal(userId)
|
||||
except PrincipalLookupError:
|
||||
return oidc.Principal(userId, dict(name=userId))
|
||||
#return None
|
||||
|
||||
|
||||
def getAuthenticationUtility(context):
|
||||
|
|
|
@ -15,7 +15,6 @@ from zope.traversing.api import getParents
|
|||
from loops.common import adapted
|
||||
from loops.security.common import getCurrentPrincipal
|
||||
from loops.type import getOptionsDict
|
||||
from scopes.web.auth import oidc
|
||||
|
||||
defaultAuthPluginId = 'loops'
|
||||
|
||||
|
@ -93,6 +92,7 @@ def getPrincipalForUserId(id, context=None, auth=None):
|
|||
try:
|
||||
return auth.getPrincipal(id)
|
||||
except PrincipalLookupError:
|
||||
from scopes.web.auth import oidc
|
||||
return oidc.Principal(id, dict(name=id))
|
||||
#return None
|
||||
|
||||
|
|
18
loops/server/auth.zcml
Normal file
18
loops/server/auth.zcml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<configure
|
||||
xmlns="http://namespaces.zope.org/zope"
|
||||
xmlns:browser="http://namespaces.zope.org/browser">
|
||||
|
||||
<browser:page
|
||||
for="zope.interface.Interface"
|
||||
name="auth_login"
|
||||
class="loops.server.auth.LoginView"
|
||||
permission="zope.Public" />
|
||||
|
||||
<browser:page
|
||||
for="zope.interface.Interface"
|
||||
name="auth_callback"
|
||||
class="loops.server.auth.CallbackView"
|
||||
permission="zope.Public" />
|
||||
|
||||
</configure>
|
||||
|
|
@ -15,7 +15,8 @@ import waitress
|
|||
from zope.app.wsgi import config, getWSGIApplication
|
||||
|
||||
def run(app, config):
|
||||
oidc.startup()
|
||||
if config.oidc_provider:
|
||||
oidc.startup()
|
||||
port = int(config.server_port)
|
||||
print(f'Serving on port {port}.')
|
||||
waitress.serve(app, port=port)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# py-scopes/demo/config.py
|
||||
# loops/tests/config.py
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from os import getenv
|
||||
from scopes.server.app import zope_app_factory
|
||||
from scopes.web.app import zope_app_factory
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
@ -18,3 +18,21 @@ dbuser = getenv('DBUSER', 'demo')
|
|||
dbpassword = getenv('DBPASSWORD', 'secret')
|
||||
dbschema = getenv('DBSCHEMA', 'demo')
|
||||
|
||||
base_url = 'test://'
|
||||
|
||||
# authentication settings
|
||||
oidc_provider = ''
|
||||
oidc_client_id = getenv('OIDC_CLIENT_ID', '12345')
|
||||
oidc_params = dict(
|
||||
op_config_url=oidc_provider + '/.well-known/openid-configuration',
|
||||
op_uris=None,
|
||||
op_keys=None,
|
||||
callback_url=getenv('OIDC_CALLBACK_URL', base_url + '/auth/callback'),
|
||||
client_id=oidc_client_id,
|
||||
principal_prefix=getenv('OIDC_PRINCIPAL_PREFIX', 'loops.'),
|
||||
cookie_name=getenv('OIDC_COOKIE_NAME', 'oidc_' + oidc_client_id),
|
||||
cookie_domain=getenv('OIDC_COOKIE_DOMAIN', None),
|
||||
cookie_lifetime=getenv('OIDC_COOKIE_LIFETIME', '86400'),
|
||||
cookie_crypt=getenv('OIDC_COOKIE_CRYPT', None)
|
||||
)
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
# loops.tests.test_loops
|
||||
|
||||
import os, sys
|
||||
sys.path = [os.path.dirname(__file__)] + sys.path
|
||||
|
||||
import unittest, doctest
|
||||
import warnings
|
||||
from zope.interface.verify import verifyClass
|
||||
|
|
Loading…
Add table
Reference in a new issue