oidc auth: improvements, store info in cookie

This commit is contained in:
Helmut Merz 2025-03-26 15:43:50 +01:00
parent 0207d12b46
commit c1f07effee
2 changed files with 64 additions and 24 deletions

View file

@ -7,6 +7,7 @@ from scopes.server.app import zope_app_factory
load_dotenv() load_dotenv()
server_port = getenv('SERVER_PORT', '8099') server_port = getenv('SERVER_PORT', '8099')
base_url = getenv('BASE_URL', 'https://demo.cy7.de')
app_factory = zope_app_factory app_factory = zope_app_factory
@ -19,8 +20,14 @@ dbpassword = getenv('DBPASSWORD', 'secret')
dbschema = getenv('DBSCHEMA', 'demo') dbschema = getenv('DBSCHEMA', 'demo')
# authentication settings # authentication settings
oidc_provider = 'https://a1.cy7.de'
oidc_client_id = getenv('OIDC_CLIENT_ID', '311613119816392525')
oidc_params = dict( oidc_params = dict(
provider_url=getenv('OIDC_PROVIDER_URL', 'https://a1.cy7.de/oauth/v2/authorize'), auth_url=getenv('OIDC_PROVIDER_URL', oidc_provider + '/oauth/v2/authorize'),
client_id=getenv('OIDC_CLIENT_ID', '311613119816392525'), callback_url=getenv('OIDC_CALLBACK_URL', base_url + '/auth/callback'),
callback_url=getenv('OIDC_CALLBACK_URL', 'https://demo.cy7.de/auth/callback'), client_id = oidc_client_id,
cookie_name=getenv('OIDC_COOKIE_NAME', 'oidc_' + oidc_client_id),
cookie_domain=getenv('OIDC_COOKIE_DOMAIN', 'cy7.de'),
cookie_lifetime=getenv('OIDC_COOKIE_LIFETIME', '86400'),
) )

View file

@ -1,8 +1,10 @@
# scopes.server.auth # scopes.server.auth
from oic import oic, rndstr from email.utils import formatdate
import json
from oic import oic, rndstr, unreserved
from oic.oic.message import AuthorizationResponse from oic.oic.message import AuthorizationResponse
from time import time
from zope.authentication.interfaces import IAuthentication from zope.authentication.interfaces import IAuthentication
from zope.interface import implementer from zope.interface import implementer
from zope.publisher.interfaces import Unauthorized from zope.publisher.interfaces import Unauthorized
@ -53,48 +55,79 @@ class Authenticator(DummyFolder):
prefix = 'auth' prefix = 'auth'
def __init__(self, request):
self.request = request
self.params = config.oidc_params
def authenticate(request): def authenticate(request):
return None return None
def login(self, request): def login(self):
params = config.oidc_params req = self.request
print('*** login', self, request.getTraversalStack(), request['PATH_INFO']) print('*** login', self, req.getTraversalStack(), req['PATH_INFO'])
#print('***', dir(request)) #print('***', dir(req))
client = oic.Client() client = oic.Client()
#providerInfo = client.provider_config(params['provider_url']) #providerInfo = client.provider_config(params['provider_url'])
#print('***', providerInfo) #print('***', providerInfo)
#client.register(providerInfo['registration_endpoint'], application_type='web') state = rndstr()
requestArgs = dict( nonce = rndstr()
client_id=params['client_id'], args = dict(
client_id=self.params['client_id'],
response_type='code', # 'code id_token token', response_type='code', # 'code id_token token',
state=rndstr(), nonce=rndstr(), state=state, nonce=nonce,
scope=['openid', 'profile'], scope=['openid', 'profile'],
redirect_uri=params['callback_url'], redirect_uri=self.params['callback_url'],
) )
authReq = client.construct_AuthorizationRequest(request_args=requestArgs) addArgs, codeVerifyer = client.add_code_challenge()
#loginUrl = authReq.request(client.authorization_endpoint) args.update(addArgs)
loginUrl = authReq.request(params['provider_url']) self.storeSession(dict(state=state, nonce=nonce, codeVerifyer=codeVerifyer))
authReq = client.construct_AuthorizationRequest(request_args=args)
loginUrl = authReq.request(self.params['auth_url'])
print('***', loginUrl) print('***', loginUrl)
request.response.redirect(loginUrl, trusted=True) req.response.redirect(loginUrl, trusted=True)
def callback(self, request): def callback(self):
print('*** callback', self, request.form) req = self.request
code = request.form['code'] print('*** callback', self, req.form)
data = self.loadSession()
code = req.form['code']
client = oic.Client()
print('***', data, code, client)
def storeSession(self, data):
options = {}
lifetime = int(self.params['cookie_lifetime'])
options['expires'] = formatdate(time() + lifetime, localtime=False, usegmt=True)
options['max-age'] = lifetime
domain = self.params['cookie_domain']
if domain:
options['domain'] = domain
#options['httponly'] = True
name = self.params['cookie_name']
value = json.dumps(data)
self.request.response.setCookie(name, value, **options)
def loadSession(self):
cookie = self.request.getCookies().get(self.params['cookie_name'])
if cookie is None:
raise ValueError('Missing authentication cookie')
data = json.loads(cookie)
return data
@register('auth', Root) @register('auth', Root)
def authView(context, request): def authView(context, request):
print('*** auth', context, request['PATH_INFO']) print('*** auth', context, request['PATH_INFO'])
return Authenticator() return Authenticator(request)
@register('login', Authenticator) @register('login', Authenticator)
def login(context, request): def login(context, request):
context.login(request) context.login()
return DefaultView(context, request) return DefaultView(context, request)
@register('callback', Authenticator) @register('callback', Authenticator)
def callback(context, request): def callback(context, request):
context.callback(request) context.callback()
return DefaultView(context, request) return DefaultView(context, request)
@register('logout', Authenticator) @register('logout', Authenticator)