From cfd0b6e81688abe886e5d2b48f9ff6cb7450febf Mon Sep 17 00:00:00 2001 From: Michael Schlenker Date: Tue, 2 May 2023 14:02:37 +0200 Subject: [PATCH] Repair some oauth_examples and get rid of the outdated jquery file (#857) * More cleanup * Add oauth_example to quality checks Signed-off-by: Michael Schlenker * Update CHANGELOG.md --------- Signed-off-by: Michael Schlenker Co-authored-by: Michael Schlenker --- .gitignore | 4 + CHANGELOG.md | 4 + Makefile | 12 +- oauth_example/as/as.py | 169 +++++++++++---------- oauth_example/as/authn_setup.py | 33 ++-- oauth_example/as/config.py | 79 +++++----- oauth_example/as/htdocs/login.mako | 8 - oauth_example/as/templates/root.mako | 12 -- oauth_example/as/tre.py | 13 +- oauth_example/rp/__init__.py | 2 +- oauth_example/rp/conf.py | 15 +- oauth_example/rp/htdocs/as_choice.mako | 18 +-- oauth_example/rp/modules/as_choice.mako.py | 54 ------- oauth_example/rp/rp.py | 122 ++++++++------- oauth_example/rp/templates/root.mako | 11 -- 15 files changed, 242 insertions(+), 314 deletions(-) delete mode 100644 oauth_example/rp/modules/as_choice.mako.py diff --git a/.gitignore b/.gitignore index aad2dc4f3..93f20b260 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,8 @@ oidc_example/op1/client_db.db oidc_example/op1/oc_config.py oidc_example/rp3/conf.py oidc_example/rp3/modules/ +oauth_example/rp/modules/ +oauth_example/as/modules/ +oauth_example/as/static/jwks.json +oauth_example/as/client_db.* update diff --git a/CHANGELOG.md b/CHANGELOG.md index 573afdc5e..0e53732e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,13 @@ The format is based on the [KeepAChangeLog] project. - [#847] Using pydantic for settings instead of custom class - [#851], [#852] Add `authn_method` to `Consumer.complete` +## Fixed +- [#857] Made oauth_example less broken + [#847]: https://github.com/CZ-NIC/pyoidc/pull/847 [#851]: https://github.com/CZ-NIC/pyoidc/issues/851 [#852]: https://github.com/CZ-NIC/pyoidc/pull/852 +[#857]: https://github.com/CZ-NIC/pyoidc/pull/857 ## 1.5.0 [2022-12-14] diff --git a/Makefile b/Makefile index 20bfff522..6ecc1dce5 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,8 @@ BUILDDIR = doc/_build DOCDIR = doc/ OICDIR = src/oic TESTDIR = tests +OAUTH_EXAMPLE = oauth_example + help: @echo "Please use \`make ' where is one of" @@ -43,17 +45,17 @@ test: .PHONY: test isort: - @pipenv run isort $(OICDIR) $(TESTDIR) + @pipenv run isort $(OICDIR) $(TESTDIR) $(OAUTH_EXAMPLE) check-isort: - @pipenv run isort --diff --check-only $(OICDIR) $(TESTDIR) + @pipenv run isort --diff --check-only $(OICDIR) $(TESTDIR) $(OAUTH_EXAMPLE) .PHONY: isort check-isort blacken: - @pipenv run black src/ tests/ + @pipenv run black src/ tests/ oauth_example/ check-black: - @pipenv run black src/ tests/ --check + @pipenv run black src/ tests/ oauth_example/ --check .PHONY: blacken check-black bandit: @@ -61,7 +63,7 @@ bandit: .PHONY: bandit check-pylama: - @pipenv run pylama $(OICDIR) $(TESTDIR) + @pipenv run pylama $(OICDIR) $(TESTDIR) $(OAUTH_EXAMPLE) .PHONY: check-pylama release: diff --git a/oauth_example/as/as.py b/oauth_example/as/as.py index 05cf1a65f..ec2f61aa2 100755 --- a/oauth_example/as/as.py +++ b/oauth_example/as/as.py @@ -4,13 +4,13 @@ """ import json import logging +import os import re import sys import traceback +import cherrypy from authn_setup import authn_setup -from cherrypy.wsgiserver.ssl_builtin import BuiltinSSLAdapter -from otest import as_unicode from requests.packages import urllib3 from oic.extension.provider import IntrospectionEndpoint @@ -30,23 +30,22 @@ urllib3.disable_warnings() -__author__ = 'roland' +__author__ = "roland" # ============================================================================ # First define how logging is supposed to be done # ============================================================================ LOGGER = logging.getLogger("") -LOGFILE_NAME = 'oauth2_as.log' +LOGFILE_NAME = "oauth2_as.log" hdlr = logging.FileHandler(LOGFILE_NAME) -base_formatter = logging.Formatter( - "%(asctime)s %(name)s:%(levelname)s %(message)s") +base_formatter = logging.Formatter("%(asctime)s %(name)s:%(levelname)s %(message)s") hdlr.setFormatter(base_formatter) LOGGER.addHandler(hdlr) LOGGER.setLevel(logging.INFO) -JWKS_FILE_NAME = "static/jwks.json" +JWKS_FILE_NAME = os.path.join(os.path.dirname(__file__), "static/jwks.json") # --------------------------------------------------------------------------- @@ -57,20 +56,21 @@ def static(environ, start_response, path): LOGGER.info("[static]sending: %s" % (path,)) try: - text = open(path, 'rb').read() + with open(path, "rb") as fd: + content = fd.read() if path.endswith(".ico"): - start_response('200 OK', [('Content-Type', "image/x-icon")]) + start_response("200 OK", [("Content-Type", "image/x-icon")]) elif path.endswith(".html"): - start_response('200 OK', [('Content-Type', 'text/html')]) + start_response("200 OK", [("Content-Type", "text/html")]) elif path.endswith(".json"): - start_response('200 OK', [('Content-Type', 'application/json')]) + start_response("200 OK", [("Content-Type", "application/json")]) elif path.endswith(".txt"): - start_response('200 OK', [('Content-Type', 'text/plain')]) + start_response("200 OK", [("Content-Type", "text/plain")]) elif path.endswith(".css"): - start_response('200 OK', [('Content-Type', 'text/css')]) + start_response("200 OK", [("Content-Type", "text/css")]) else: - start_response('200 OK', [('Content-Type', "text/xml")]) - return [text] + start_response("200 OK", [("Content-Type", "text/xml")]) + return [content] except IOError: resp = NotFound() return resp(environ, start_response) @@ -90,12 +90,12 @@ def __init__(self, oas): TokenEndpoint(self.token), RegistrationEndpoint(self.registration), IntrospectionEndpoint(self.introspection), - RevocationEndpoint(self.revocation) + RevocationEndpoint(self.revocation), ] self.urls = [ - (r'^verify', self.verify), - (r'.well-known/openid-configuration', self.config) + (r"^verify", self.verify), + (r".well-known/openid-configuration", self.config), ] for endp in self.endpoints: @@ -111,28 +111,23 @@ def token(self, environ, start_response): # noinspection PyUnusedLocal def authorization(self, environ, start_response): - return wsgi_wrapper(environ, start_response, - self.oas.authorization_endpoint) + return wsgi_wrapper(environ, start_response, self.oas.authorization_endpoint) # noinspection PyUnusedLocal def config(self, environ, start_response): - return wsgi_wrapper(environ, start_response, - self.oas.providerinfo_endpoint) + return wsgi_wrapper(environ, start_response, self.oas.providerinfo_endpoint) # noinspection PyUnusedLocal def registration(self, environ, start_response): - return wsgi_wrapper(environ, start_response, - self.oas.registration_endpoint) + return wsgi_wrapper(environ, start_response, self.oas.registration_endpoint) # noinspection PyUnusedLocal def introspection(self, environ, start_response): - return wsgi_wrapper(environ, start_response, - self.oas.introspection_endpoint) + return wsgi_wrapper(environ, start_response, self.oas.introspection_endpoint) # noinspection PyUnusedLocal def revocation(self, environ, start_response): - return wsgi_wrapper(environ, start_response, - self.oas.revocation_endpoint) + return wsgi_wrapper(environ, start_response, self.oas.revocation_endpoint) def application(self, environ, start_response): """ @@ -149,8 +144,7 @@ def application(self, environ, start_response): :return: The response as a list of lines """ - # user = environ.get("REMOTE_USER", "") - path = environ.get('PATH_INFO', '').lstrip('/') + path = environ.get("PATH_INFO", "").lstrip("/") LOGGER.info("path: %s" % path) if path == "robots.txt": @@ -163,9 +157,9 @@ def application(self, environ, start_response): match = re.search(regex, path) if match is not None: try: - environ['oic.url_args'] = match.groups()[0] + environ["oic.url_args"] = match.groups()[0] except IndexError: - environ['oic.url_args'] = path + environ["oic.url_args"] = path LOGGER.debug("callback: %s" % callback) try: @@ -191,24 +185,23 @@ def application(self, environ, start_response): if __name__ == "__main__": import argparse - import shelve # nosec import importlib - - from cherrypy import wsgiserver + import shelve # nosec # This is where session information is stored # This serve is stateful. from oic import rndstr - from oic.utils.sdb import SessionDB, DefaultToken + from oic.utils.sdb import DefaultToken + from oic.utils.sdb import SessionDB # Parse the command arguments parser = argparse.ArgumentParser() - parser.add_argument('-d', dest='debug', action='store_true') - parser.add_argument('-k', dest='insecure', action='store_true') - parser.add_argument('-p', dest='port', default=80, type=int) + parser.add_argument("-d", dest="debug", action="store_true") + parser.add_argument("-k", dest="insecure", action="store_true") + parser.add_argument("-p", dest="port", default=80, type=int) # Who it should report as being responsible for the authentication - parser.add_argument('-A', dest='authn_as', default="") - parser.add_argument('-c', dest='conf_path') + parser.add_argument("-A", dest="authn_as", default="") + parser.add_argument("-c", dest="conf_path") parser.add_argument(dest="config") args = parser.parse_args() @@ -247,16 +240,25 @@ def application(self, environ, start_response): capabilities = None if args.insecure: - kwargs = {'verify_ssl': False} + kwargs = {"verify_ssl": False} else: kwargs = {} # Initiate the Provider - oas = Provider(config.issuer, None, cdb, broker, authz, - baseurl=config.issuer, client_authn=verify_client, - symkey=config.SYM_KEY, hostname=config.HOST, - capabilities=capabilities, - behavior=config.BEHAVIOR, **kwargs) + oas = Provider( + config.issuer, + None, + cdb, + broker, + authz, + baseurl=config.issuer, + client_authn=verify_client, + symkey=config.SYM_KEY, + hostname=config.HOST, + capabilities=capabilities, + behavior=config.BEHAVIOR, + **kwargs + ) try: jwks = keyjar_init(oas, config.keys, kid_template="op%d") @@ -264,30 +266,41 @@ def application(self, environ, start_response): LOGGER.error("Key setup failed: {}".format(err)) print("Key setup failed: {}".format(err)) exit() - # oas.key_setup("static", sig={"format": "jwk", "alg": "rsa"}) else: jwks_file_name = JWKS_FILE_NAME - f = open(jwks_file_name, "w") - for key in jwks["keys"]: - for k in key.keys(): - key[k] = as_unicode(key[k]) + with open(jwks_file_name, "w") as f: + for key in jwks["keys"]: + for k in key.keys(): + key[k] = key[k] + f.write(json.dumps(jwks)) - f.write(json.dumps(jwks)) - f.close() oas.jwks_uri = "{}/{}".format(oas.baseurl, jwks_file_name) # Initiate the SessionDB - _code = DefaultToken(rndstr(32), rndstr(32), typ='A', lifetime=600) - _token = JWTToken('T', oas.keyjar, {'code': 3600, 'token': 900}, - iss=config.issuer, sign_alg='RS256') - _refresh_token = JWTToken('R', oas.keyjar, {'': 86400}, iss=config.issuer, - sign_alg='RS256') - oas.sdb = SessionDB(config.SERVICE_URL, - db={}, - code_factory=_code, - token_factory=_token, - refresh_token_factory=_refresh_token) + _code = DefaultToken(rndstr(32), rndstr(32), typ="A", lifetime=600) + _token = JWTToken( + "T", + oas.keyjar, + {"code": 3600, "token": 900}, + iss=config.issuer, + sign_alg="RS256", + ) + _refresh_token = JWTToken( + "R", + oas.keyjar, + {"": 86400}, + iss=config.issuer, + sign_alg="RS256", + token_storage={}, + ) + oas.sdb = SessionDB( + config.SERVICE_URL, + db={}, + code_factory=_code, + token_factory=_token, + refresh_token_factory=_refresh_token, + ) # set some parameters try: @@ -324,25 +337,27 @@ def application(self, environ, start_response): pass else: for ent in extern: - iss = ent['iss'] + iss = ent["iss"] kb = KeyBundle() - kb.imp_jwks = json.load(open(ent['jwks'])) - kb.do_keys(kb.imp_jwks['keys']) + kb.imp_jwks = json.load(open(ent["jwks"])) + kb.do_keys(kb.imp_jwks["keys"]) oas.keyjar.add_kb(iss, kb) + # Initiate the web server + cherrypy.config.update({"server.socket_port": args.port}) + _app = Application(oas) + cherrypy.tree.graft(_app.application, "/") - # Initiate the web server - SRV = wsgiserver.CherryPyWSGIServer(('0.0.0.0', args.port), _app.application) # nosec - https = "" if config.SERVICE_URL.startswith("https"): https = " using HTTPS" - # SRV.ssl_adapter = ssl_pyopenssl.pyOpenSSLAdapter( - # config.SERVER_CERT, config.SERVER_KEY, config.CERT_CHAIN) - SRV.ssl_adapter = BuiltinSSLAdapter(config.SERVER_CERT, - config.SERVER_KEY, - config.CERT_CHAIN) + cherrypy.config.update( + { + "cherrypy.server.ssl_certificate": config.SERVER_CERT, + "cherrypy.server.ssl_private_key": config.SERVER_KEY, + } + ) _info = START_MESG.format(args.port, config.HOST) if https: @@ -350,6 +365,6 @@ def application(self, environ, start_response): LOGGER.info(_info) print(_info) try: - SRV.start() + cherrypy.engine.start() except KeyboardInterrupt: - SRV.stop() + pass diff --git a/oauth_example/as/authn_setup.py b/oauth_example/as/authn_setup.py index 7b00e18e2..9bb7ca9d0 100644 --- a/oauth_example/as/authn_setup.py +++ b/oauth_example/as/authn_setup.py @@ -1,6 +1,6 @@ from oic.utils.authn.authn_context import AuthnBroker -__author__ = 'roland' +__author__ = "roland" def ldap_validation(config): @@ -10,9 +10,7 @@ def ldap_validation(config): return UserLDAPMemberValidation(**config["args"]) -VALIDATOR = { - "LDAP": ldap_validation -} +VALIDATOR = {"LDAP": ldap_validation} def cas_setup(item): @@ -26,30 +24,23 @@ def cas_setup(item): _func = VALIDATOR[v_cnf["type"].upper()](item) _cnf = item["config"] - return CasAuthnMethod(None, _cnf["cas_server"], item["URL"], - _cnf["return_to"], _func) + return CasAuthnMethod( + None, _cnf["cas_server"], item["URL"], _cnf["return_to"], _func + ) def userpwd_setup(item): from oic.utils.authn.user import UsernamePasswordMako _conf = item["config"] - return UsernamePasswordMako(None, "login.mako", _conf["lookup"], - _conf["passwd"], _conf["return_to"]) - - -# def ldap_setup(item): -# from oic.utils.authn.user import LDAPAuthn -# -# _conf = item["config"] -# return LDAPAuthn(None, _conf["ldap_server"], _conf["return_to"], -# _conf["dn_pattern"], "login.mako", _conf["lookup"]) + return UsernamePasswordMako( + None, "login.mako", _conf["lookup"], _conf["passwd"], _conf["return_to"] + ) AUTH_METHOD = { "UserPassword": userpwd_setup, "CAS": cas_setup, - #"LDAP": ldap_setup, } @@ -63,7 +54,11 @@ def authn_setup(config): except KeyError: pass else: - broker.add(method_conf["ACR"], func(method_conf), - method_conf["WEIGHT"], method_conf["URL"]) + broker.add( + method_conf["ACR"], + func(method_conf), + method_conf["WEIGHT"], + method_conf["URL"], + ) return broker diff --git a/oauth_example/as/config.py b/oauth_example/as/config.py index 0d999cccd..23caf19aa 100644 --- a/oauth_example/as/config.py +++ b/oauth_example/as/config.py @@ -1,8 +1,8 @@ +import os + from mako.lookup import TemplateLookup HOST = "localhost" -# HOST = "lingon.ladok.umu.se" -# HOST = "lingon.catalogix.se" baseurl = "https://%s" % HOST issuer = "%s:%%d" % baseurl @@ -26,8 +26,8 @@ }, "args": { "verifyAttr": "eduPersonAffiliation", - "verifyAttrValid": ['employee', 'staff', 'student'] - } + "verifyAttrValid": ["employee", "staff", "student"], + }, } # ============================================================================ @@ -36,13 +36,15 @@ # case is. # ============================================================================ -PASSWD = {"diana": "krall", - "babs": "howes", - "upper": "crust", - "rohe0002": "StevieRay", - "haho0032": "qwerty"} +PASSWD = { + "diana": "krall", + "babs": "howes", + "upper": "crust", + "rohe0002": "StevieRay", + "haho0032": "qwerty", +} -ROOT = './' +ROOT = "./" # ACR = Authentication Class Reference # WEIGHT = your view on the strength of the method, higher value = better @@ -55,61 +57,62 @@ "WEIGHT": 1, "URL": SERVICE_URL, "config": { - "lookup": TemplateLookup(directories=[ROOT + 'templates', - ROOT + 'htdocs'], - module_directory=ROOT + 'modules', - input_encoding='utf-8', - output_encoding='utf-8'), + "lookup": TemplateLookup( + directories=[ROOT + "templates", ROOT + "htdocs"], + module_directory=ROOT + "modules", + input_encoding="utf-8", + output_encoding="utf-8", + ), "passwd": PASSWD, - "return_to": RETURN_TO - } + "return_to": RETURN_TO, + }, }, } AUTHN = "Simple" -COOKIENAME = 'pyoic' +COOKIENAME = "pyoic" COOKIETTL = 4 * 60 # 4 hours SYM_KEY = "IfIwerelookingfo" # 16 bytes for AES_128 which is the default SERVER_CERT = "%s/certs/server.crt" % ROOT SERVER_KEY = "%s/certs/server.key" % ROOT -# CERT_CHAIN="certs/chain.pem" CERT_CHAIN = None keys = [ {"type": "RSA", "key": "keys/key.pem", "use": ["enc", "sig"]}, {"type": "EC", "crv": "P-256", "use": ["sig"]}, - {"type": "EC", "crv": "P-256", "use": ["enc"]} + {"type": "EC", "crv": "P-256", "use": ["enc"]}, ] CAPABILITIES = { "token_endpoint_auth_methods_supported": ["private_key_jwt"], - "grant_types_supported": ["authorization_code", "implicit", - 'client_credentials'], + "grant_types_supported": ["authorization_code", "implicit", "client_credentials"], "scopes_supported": ["offline_access"], - 'response_types_supported': ['code', 'token'] + "response_types_supported": ["code", "token"], } BEHAVIOR = { - 'client_registration':{ - 'map': { - 'grant_type2response_type': { - 'authorization_code': 'code', - 'implicit': 'token' + "client_registration": { + "map": { + "grant_type2response_type": { + "authorization_code": "code", + "implicit": "token", } }, - 'single': ['response_types'], - 'allow': { - 'grant_types': [ - 'authorization_code', - 'implicit', + "single": ["response_types"], + "allow": { + "grant_types": [ + "authorization_code", + "implicit", # 'client_credentials' Not allowed ] - } + }, } } -TRUSTED_REGISTRATION_ENTITIES = [{ - 'iss': 'https://has.example.com/tre', - 'jwks': 'tre.jwks', -}] +TRUSTED_REGISTRATION_ENTITIES = [ + { + "iss": "https://has.example.com/tre", + "jwks": os.path.join(os.path.dirname(__file__), "tre.jwks"), + } +] diff --git a/oauth_example/as/htdocs/login.mako b/oauth_example/as/htdocs/login.mako index 6ea2c1bcc..0cd55c81c 100644 --- a/oauth_example/as/htdocs/login.mako +++ b/oauth_example/as/htdocs/login.mako @@ -28,11 +28,3 @@ Client policy % endif - -<%def name="add_js()"> - - diff --git a/oauth_example/as/templates/root.mako b/oauth_example/as/templates/root.mako index de49deeb2..173fdb3f7 100644 --- a/oauth_example/as/templates/root.mako +++ b/oauth_example/as/templates/root.mako @@ -1,13 +1,3 @@ -<% self.seen_css = set() %> -<%def name="css_link(path, media='')" filter="trim"> - % if path not in self.seen_css: - - % endif - <% self.seen_css.add(path) %> - -<%def name="css()" filter="trim"> - ${css_link('/css/main.css', 'screen')} - <%def name="pre()" filter="trim">

Login

@@ -29,8 +19,6 @@ ${self.css()} ${pre()} -## ${comps.dict_to_table(pageargs)} -##

${next.body()} ${post()} diff --git a/oauth_example/as/tre.py b/oauth_example/as/tre.py index 7fbcbcdfe..1690922f3 100644 --- a/oauth_example/as/tre.py +++ b/oauth_example/as/tre.py @@ -1,19 +1,10 @@ -import json - from oic.utils.keyio import build_keyjar from oic.utils.keyio import dump_jwks -__author__ = 'roland' +__author__ = "roland" key_conf = [{"type": "RSA", "use": ["enc", "sig"]}] pub_jwks, keyjar, kdd = build_keyjar(key_conf, "tre%d", None, None) -dump_jwks(keyjar.issuer_keys[''], 'tre.jwks') - -# # To get the private keys -# priv_jwks = keyjar.export_jwks(private=True) -# -# f = open('tre.jwks', 'w') -# f.write(json.dumps(priv_jwks)) -# f.close() +dump_jwks(keyjar.issuer_keys[""], "tre.jwks") diff --git a/oauth_example/rp/__init__.py b/oauth_example/rp/__init__.py index 16f3a7968..c09b22136 100644 --- a/oauth_example/rp/__init__.py +++ b/oauth_example/rp/__init__.py @@ -1 +1 @@ -__author__ = 'roland' +__author__ = "roland" diff --git a/oauth_example/rp/conf.py b/oauth_example/rp/conf.py index 8ac93941d..81e888df7 100644 --- a/oauth_example/rp/conf.py +++ b/oauth_example/rp/conf.py @@ -6,22 +6,25 @@ BASE = "http://%s:%d/" % (HOST, PORT) # If BASE is https these has to be specified -SERVER_KEY = '' -SERVER_CERT = '' +SERVER_KEY = "" +SERVER_CERT = "" CA_BUNDLE = None SCOPE = [] ROOT = "./" -LOOKUP = TemplateLookup(directories=[ROOT + 'templates', ROOT + 'htdocs'], - module_directory=ROOT + 'modules', - input_encoding='utf-8', output_encoding='utf-8') +LOOKUP = TemplateLookup( + directories=[ROOT + "templates", ROOT + "htdocs"], + module_directory=ROOT + "modules", + input_encoding="utf-8", + output_encoding="utf-8", +) AS_CONF = { "AuthzServer@DIG": { "authorization_endpoint": "https://localhost:8080/authorization", "token_endpoint": "https://localhost:8080/token", "client_id": "YWwQiwQNWaeI", - "client_secret": "cdb8c2f40110a5fdefe7e26ea26a0bd51fb3d1b9593d6a054c75abcb" + "client_secret": "cdb8c2f40110a5fdefe7e26ea26a0bd51fb3d1b9593d6a054c75abcb", } } diff --git a/oauth_example/rp/htdocs/as_choice.mako b/oauth_example/rp/htdocs/as_choice.mako index 1854b45cc..7784a33e7 100644 --- a/oauth_example/rp/htdocs/as_choice.mako +++ b/oauth_example/rp/htdocs/as_choice.mako @@ -14,18 +14,10 @@ def as_choice(as_list): OAuth2 RP Example - - - - - @@ -40,12 +32,6 @@ def as_choice(as_list):
- - - - - - - + - \ No newline at end of file + diff --git a/oauth_example/rp/modules/as_choice.mako.py b/oauth_example/rp/modules/as_choice.mako.py deleted file mode 100644 index f7f0f794b..000000000 --- a/oauth_example/rp/modules/as_choice.mako.py +++ /dev/null @@ -1,54 +0,0 @@ -from mako import cache -from mako import filters -from mako import runtime - -UNDEFINED = runtime.UNDEFINED -STOP_RENDERING = runtime.STOP_RENDERING -__M_dict_builtin = dict -__M_locals_builtin = locals -_magic_number = 10 -_modified_time = 1474925155.284777 -_enable_loop = True -_template_filename = 'htdocs/as_choice.mako' -_template_uri = 'as_choice.mako' -_source_encoding = 'utf-8' -_exports = [] - - - -def as_choice(as_list): - """ - Creates a dropdown list of authorization servers - """ - element = "" - return element - - -def render_body(context,**pageargs): - __M_caller = context.caller_stack._push_frame() - try: - __M_locals = __M_dict_builtin(pageargs=pageargs) - action = context.get('action', UNDEFINED) - method = context.get('method', UNDEFINED) - as_list = context.get('as_list', UNDEFINED) - __M_writer = context.writer() - __M_writer('\n\n\n \n OAuth2 RP Example\n \n \n \n \n\n \n \n \n \n\n
\n \n
\n
\n

Choose the Authorization Server:

\n ') - __M_writer(str(as_choice(as_list))) - __M_writer('\n
\n
\n \n
\n
\n\n
\n \n \n \n \n\n \n') - return '' - finally: - context.caller_stack._pop_frame() - - -""" -__M_BEGIN_METADATA -{"source_encoding": "utf-8", "uri": "as_choice.mako", "line_map": {"16": 1, "48": 42, "36": 11, "37": 35, "38": 35, "39": 35, "40": 35, "41": 37, "42": 37, "28": 0}, "filename": "htdocs/as_choice.mako"} -__M_END_METADATA -""" diff --git a/oauth_example/rp/rp.py b/oauth_example/rp/rp.py index 6f10e9b91..e43a0c36f 100644 --- a/oauth_example/rp/rp.py +++ b/oauth_example/rp/rp.py @@ -1,13 +1,13 @@ -from urllib.parse import parse_qs -from urllib.parse import unquote - import argparse import importlib import logging import sys +import uuid +from urllib.parse import parse_qs +from urllib.parse import unquote +import cherrypy from beaker.middleware import SessionMiddleware -from cherrypy import wsgiserver from oic.oauth2.consumer import Consumer from oic.utils.http_util import NotFound @@ -20,10 +20,9 @@ # ============================================================================ LOGGER = logging.getLogger("") -LOGFILE_NAME = 'rp.log' +LOGFILE_NAME = "rp.log" hdlr = logging.FileHandler(LOGFILE_NAME) -base_formatter = logging.Formatter( - "%(asctime)s %(name)s:%(levelname)s %(message)s") +base_formatter = logging.Formatter("%(asctime)s %(name)s:%(levelname)s %(message)s") hdlr.setFormatter(base_formatter) LOGGER.addHandler(hdlr) @@ -34,46 +33,39 @@ RP_CONF = None CONSUMER = {} -#class Httpd(object): -# def http_request(self, url): -# return requests.get(url, verify=False) - - # ============================================================================ # Endpoint functions # ============================================================================ + def as_choice(environ, start_response): - resp = Response(mako_template="as_choice.mako", - template_lookup=RP_CONF.LOOKUP, - headers=[]) - argv = { - "as_list": RP_CONF.AS_CONF.keys(), - "action": "as", - "method": "POST" - } + resp = Response( + mako_template="as_choice.mako", template_lookup=RP_CONF.LOOKUP, headers=[] + ) + argv = {"as_list": RP_CONF.AS_CONF.keys(), "action": "as", "method": "POST"} return resp(environ, start_response, **argv) -#noinspection PyUnresolvedReferences +# noinspection PyUnresolvedReferences def static(environ, start_response, path): LOGGER.info("[static]sending: %s" % (path,)) try: - text = open(path).read() + with open(path, "rb") as fd: + content = fd.read() if path.endswith(".ico"): - start_response('200 OK', [('Content-Type', "image/x-icon")]) + start_response("200 OK", [("Content-Type", "image/x-icon")]) elif path.endswith(".html"): - start_response('200 OK', [('Content-Type', 'text/html')]) + start_response("200 OK", [("Content-Type", "text/html")]) elif path.endswith(".json"): - start_response('200 OK', [('Content-Type', 'application/json')]) + start_response("200 OK", [("Content-Type", "application/json")]) elif path.endswith(".txt"): - start_response('200 OK', [('Content-Type', 'text/plain')]) + start_response("200 OK", [("Content-Type", "text/plain")]) elif path.endswith(".css"): - start_response('200 OK', [('Content-Type', 'text/css')]) + start_response("200 OK", [("Content-Type", "text/css")]) else: - start_response('200 OK', [('Content-Type', "text/xml")]) - return [text] + start_response("200 OK", [("Content-Type", "text/xml")]) + return [content] except IOError: resp = NotFound() return resp(environ, start_response) @@ -84,12 +76,23 @@ def static(environ, start_response, path): # ============================================================================ Token = {} +Clients = {} + + +def store_client(cli): + lookup_key = str(uuid.uuid4()) + Clients[lookup_key] = cli + return lookup_key + + +def get_client(lookup_key): + return Clients.get(lookup_key) def application(environ, start_response): - session = environ['beaker.session'] + session = environ["beaker.session"] - path = environ.get('PATH_INFO', '').lstrip('/') + path = environ.get("PATH_INFO", "").lstrip("/") if path == "robots.txt": return static(environ, start_response, "static/robots.txt") @@ -105,25 +108,26 @@ def application(environ, start_response): session["callback"] = True request = parse_qs(get_or_post(environ)) _cli = CONSUMER[unquote(request["authzsrv"][0])] - session["client"] = _cli - resp = SeeOther(_cli.begin(RP_CONF.BASE, path)) + session["client"] = store_client(_cli) + sid, redirect_uri = _cli.begin(RP_CONF.BASE, path) + resp = SeeOther(redirect_uri) return resp(environ, start_response) if path == "rp": session["callback"] = True request = parse_qs(get_or_post(environ)) _cli = CONSUMER[unquote(request["iss"][0])] - session["client"] = _cli - resp = SeeOther(_cli.begin(RP_CONF.BASE, path)) + session["client"] = store_client(_cli) + sid, redirect_uri = _cli.begin(RP_CONF.BASE, path) + resp = SeeOther(redirect_uri) return resp(environ, start_response) if path == "authz_cb": - _cli = session["client"] + _cli = get_client(session["client"]) request = get_or_post(environ) aresp = _cli.handle_authorization_response(request) rargs = {"code": aresp["code"]} atresp = _cli.do_access_token_request(request_args=rargs) - #extra_args=None, http_args=None,) # Access token should be stored somewhere for later usage Token[atresp["state"]] = atresp resp = Response("Got access token: %s" % atresp["access_token"]) @@ -131,23 +135,23 @@ def application(environ, start_response): return as_choice(environ, start_response) + # ============================================================================ # Below is what's needed to start the server # ============================================================================ START_MESG = "OAuth2 relaying party listening on port:%s at %s" -if __name__ == '__main__': +if __name__ == "__main__": session_opts = { - 'session.type': 'memory', - 'session.cookie_expires': True, - #'session.data_dir': './data', - 'session.auto': True, - 'session.timeout': 900 + "session.type": "memory", + "session.cookie_expires": True, + "session.auto": True, + "session.timeout": 900, } parser = argparse.ArgumentParser() - parser.add_argument('-c', dest='conf_path') + parser.add_argument("-c", dest="conf_path") parser.add_argument(dest="config") args = parser.parse_args() @@ -165,27 +169,33 @@ def application(environ, start_response): c_conf = {"client_id": info["client_id"]} CONSUMER[name] = Consumer( - session_db={}, client_config=c_conf, + session_db={}, + client_config=c_conf, server_info={ "authorization_endpoint": info["authorization_endpoint"], - "token_endpoint": info["token_endpoint"]}, - authz_page="authz_cb", response_type="code") + "token_endpoint": info["token_endpoint"], + }, + authz_page="authz_cb", + response_type="code", + ) CONSUMER[name].client_secret = info["client_secret"] - SRV = wsgiserver.CherryPyWSGIServer(('0.0.0.0', RP_CONF.PORT), # nosec - SessionMiddleware(application, - session_opts)) + app = SessionMiddleware(application, session_opts) + cherrypy.config.update({"server.socket_port": RP_CONF.PORT}) + cherrypy.tree.graft(app, "/") if RP_CONF.BASE.startswith("https"): - from cherrypy.wsgiserver import ssl_pyopenssl - - SRV.ssl_adapter = ssl_pyopenssl.pyOpenSSLAdapter( - RP_CONF.SERVER_CERT, RP_CONF.SERVER_KEY, RP_CONF.CA_BUNDLE) + cherrypy.config.update( + { + "cherrypy.server.ssl_certificate": RP_CONF.SERVER_CERT, + "cherrypy.server.ssl_private_key": RP_CONF.SERVER_KEY, + } + ) LOGGER.info(START_MESG % (RP_CONF.PORT, RP_CONF.HOST)) print(START_MESG % (RP_CONF.PORT, RP_CONF.HOST)) try: - SRV.start() + cherrypy.engine.start() except KeyboardInterrupt: - SRV.stop() + pass diff --git a/oauth_example/rp/templates/root.mako b/oauth_example/rp/templates/root.mako index 8e73d447c..7ad2c9b64 100644 --- a/oauth_example/rp/templates/root.mako +++ b/oauth_example/rp/templates/root.mako @@ -1,13 +1,3 @@ -<% self.seen_css = set() %> -<%def name="css_link(path, media='')" filter="trim"> - % if path not in self.seen_css: - - % endif - <% self.seen_css.add(path) %> - -<%def name="css()" filter="trim"> - ${css_link('/css/main.css', 'screen')} - <%def name="pre()" filter="trim">

Login

@@ -24,7 +14,6 @@ ##"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> OAuth test -${self.css()}