cco.member: provide OIDC authentication via loops.server.auth

This commit is contained in:
Helmut Merz 2025-10-27 16:29:01 +01:00
parent 110fa036f4
commit f27b0f952f
4 changed files with 37 additions and 6 deletions

View file

@ -9,6 +9,11 @@
i18n:translate="" i18n:translate=""
tal:content="request/error_message" /> tal:content="request/error_message" />
<h2 i18n:translate="title_login">Login</h2> <h2 i18n:translate="title_login">Login</h2>
<p i18n:domain="loops"
tal:condition="view/oidc_allowed">
<a tal:attributes="href string:/@@auth_login?camefrom=$camefrom"
i18n:translate="login-with-oidc">Login with OpenID Connect (Zitadel)</a>
</p>
<div> <div>
<p i18n:translate="description_login" <p i18n:translate="description_login"
tal:condition="python: principal == 'zope.anybody'"> tal:condition="python: principal == 'zope.anybody'">

View file

@ -23,6 +23,7 @@ from zope.publisher.interfaces.http import IHTTPRequest
from zope.security.interfaces import Unauthorized as DefaultUnauth from zope.security.interfaces import Unauthorized as DefaultUnauth
from zope.sendmail.interfaces import IMailDelivery from zope.sendmail.interfaces import IMailDelivery
from scopes.web.auth import oidc
from cco.member.auth import getCredentials, getPrincipalFromCredentials,\ from cco.member.auth import getCredentials, getPrincipalFromCredentials,\
getPrincipalForUsername, JWT_SECRET getPrincipalForUsername, JWT_SECRET
from cco.member.interfaces import IPasswordChange, IPasswordReset from cco.member.interfaces import IPasswordChange, IPasswordReset
@ -36,11 +37,9 @@ from loops.common import adapted
from loops.organize.interfaces import IMemberRegistrationManager from loops.organize.interfaces import IMemberRegistrationManager
from loops.organize.party import getPersonForUser from loops.organize.party import getPersonForUser
from loops.organize.util import getPrincipalForUserId, getPrincipalFolder from loops.organize.util import getPrincipalForUserId, getPrincipalFolder
from loops.server.auth import getAuthMethodCookieValue, getConfigAuthMethod
try: import config
import config
except ImportError:
config = None
log = logging.getLogger('cco.member.browser') log = logging.getLogger('cco.member.browser')
@ -60,14 +59,36 @@ def validateToken(token, secret=None):
return True return True
class LoginConcept(ConceptView): class LoginBase:
def __call__(self):
if self.authMethod == 'oidc':
return self.authOidc()
return super(LoginBase, self).__call__()
@Lazy
def authMethod(self):
if getConfigAuthMethod() == 'cookie':
return getAuthMethodCookieValue(self.request)
return 'legacy'
@Lazy
def oidc_Allowed(self):
return self.authMethod in ('select', 'oidc')
def authOidc(self):
oidc.Authenticator(self.request).login()
return ''
class LoginConcept(LoginBase, ConceptView):
@Lazy @Lazy
def macro(self): def macro(self):
return template.macros['login_form'] return template.macros['login_form']
class LoginForm(NodeView): class LoginForm(LoginBase, NodeView):
@Lazy @Lazy
def macro(self): def macro(self):

2
cco/member/config.py Normal file
View file

@ -0,0 +1,2 @@
# loops-ext: cco.member.config
# (for testing only)

View file

@ -3,6 +3,9 @@
""" Tests for the 'cco.member' package. """ Tests for the 'cco.member' package.
""" """
import os, sys
sys.path = [os.path.dirname(__file__)] + sys.path # for import of config.py
import os import os
import unittest, doctest import unittest, doctest
from zope import component from zope import component