Merge remote-tracking branch 'rohe/master' into ci_testing

Conflicts:
	setup.py
	src/oic/oauth2/provider.py
	src/oic/oic/provider.py
	src/oic/utils/sdb.py
This commit is contained in:
Manuel Jeckelmann 2014-11-24 16:10:23 +01:00
commit 7bd5fed021
21 changed files with 359 additions and 182 deletions

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICGTCCAYICCQCIs8fF+AnxUzANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJT
RTETMBEGA1UECBMKU29tZS1TdGF0ZTEMMAoGA1UEChMDVW1VMQwwCgYDVQQLEwNJ
VFMxETAPBgNVBAMTCHJvaGUwMDAyMB4XDTExMDkwNzA4MjMwOFoXDTEyMDkwNjA4
MjMwOFowUTELMAkGA1UEBhMCU0UxEzARBgNVBAgTClNvbWUtU3RhdGUxDDAKBgNV
BAoTA1VtVTEMMAoGA1UECxMDSVRTMREwDwYDVQQDEwhyb2hlMDAwMjCBnzANBgkq
hkiG9w0BAQEFAAOBjQAwgYkCgYEA5zbNbHIYIkGGJ3RGdRKkYmF4gOorv5eDuUKT
Vtuu3VvxrpOWvwnFV+NY0LgqkQSMMyVzodJE3SUuwQTUHPXXY5784vnkFqzPRx6b
HgPxKz7XfwQjEBTafQTMmOeYI8wFIOIHY5i0RWR+gxDbh/D5TXuUqScOOqR47vSp
IbUH+ncCAwEAATANBgkqhkiG9w0BAQUFAAOBgQDP9PE53utRqocZpFRxrhL+4vcI
vlQd3XonE7vMJwdl9FUW7QRMon19dpYKQ6LTCOBA4ZCwh2z/Om2X97zogMLKFPcE
LVqxzBVlrzuqAgOErEalYv9pCBzoFHGUHP6kTAUOCsoO9ZdQWgA6YkK2hYRSlLNX
Z0wHIHGaHe5xnFFpyQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDnNs1schgiQYYndEZ1EqRiYXiA6iu/l4O5QpNW267dW/Guk5a/
CcVX41jQuCqRBIwzJXOh0kTdJS7BBNQc9ddjnvzi+eQWrM9HHpseA/ErPtd/BCMQ
FNp9BMyY55gjzAUg4gdjmLRFZH6DENuH8PlNe5SpJw46pHju9KkhtQf6dwIDAQAB
AoGAKuSxy1KHQ6OgPaWGhKWGtXGbp17J6usy1qWRK+XpVMt/1IEw0BQB9kII8f+Y
dfq//6UNBJI7kEMbn1dD+nNpF4ncO9QWHE5oqacHgaZOl6+MF3ePy8aXkADhwiel
L7CtZjhwbcjGt5PI6AIcpFfmBAbu5Pf4gidr6bR+MoJGlhECQQDzfMaRqruJkqsz
Z5b9boIr08orx1xPoHTmE5g0ET9+UJy/BBgx7DNv+AQhJ2UC1ZaKcgqwetOwJhQs
u8Cbrct9AkEA8xiQSwqlM7ltpNl6L2VvSxzTd897it+FJElXbD6u80RvzMuo3Xw3
+M+F0kDobM4vsyBuZRw418/yOpnOv8x4AwJATj5WgRDgWwEqysYLGz2bzwGsAg16
eIwThKvfSTwRr0GwXSGvtLs2fFCy4wSJzTNdwPeMv9F4nS5fZVCgQGbE8QJAMZBG
iyZGfH9H/Z5hrRwvTs83xmvFMpFUIgvaCTXWkb7YVJcJfO8AsngNPssBGH4Jd6ob
F/5jEI1TQ+NsJerYZQJBAJdqDlnPQyqek4kdBvwh2hYo9EwOrgOchmruMOeP5lE6
2TLIyjYC3uVMPJj+ESayVcAMrgj4Enk4qh/WKVeMJ7c=
-----END RSA PRIVATE KEY-----

View File

@ -373,6 +373,7 @@ def application(environ, start_response):
request is done
:return: The response as a list of lines
"""
global OAS
#user = environ.get("REMOTE_USER", "")
@ -382,9 +383,8 @@ def application(environ, start_response):
if path == "robots.txt":
return static(environ, start_response, logger, "static/robots.txt")
environ["oic.oas"] = OAS
#remote = environ.get("REMOTE_ADDR")
#kaka = environ.get("HTTP_COOKIE", '')

View File

@ -526,8 +526,8 @@ if __name__ == '__main__':
else:
kwargs["verify_ssl"] = True
OAS = Provider(config.issuer, SessionDB(), cdb, ac, None, authz,
verify_client, config.SYM_KEY, **kwargs)
OAS = Provider(config.issuer, SessionDB(config.baseurl), cdb, ac, None,
authz, verify_client, config.SYM_KEY, **kwargs)
for authn in ac:
authn.srv = OAS

View File

@ -202,7 +202,9 @@ class OIDCClients(object):
return client
def dynamic_client(self, userid):
client = self.client_cls(client_authn_method=CLIENT_AUTHN_METHOD, verify_ssl=self.config.VERIFY_SSL)
client = self.client_cls(client_authn_method=CLIENT_AUTHN_METHOD,
verify_ssl=self.config.VERIFY_SSL)
issuer = client.wf.discovery_query(userid)
if issuer in self.client:
return self.client[issuer]

View File

@ -108,7 +108,6 @@ def clear_session(session):
def application(environ, start_response):
session = environ['beaker.session']
path = environ.get('PATH_INFO', '').lstrip('/')
if path == "robots.txt":
return static(environ, start_response, LOGGER, "static/robots.txt")

View File

@ -37,7 +37,7 @@ class PyTest(TestCommand):
setup(
name="oic",
version="0.6.gamma",
version="0.6.0",
description="Python implementation of OAuth2 and OpenID Connect",
author = "Roland Hedberg",
author_email = "roland.hedberg@adm.umu.se",
@ -50,8 +50,8 @@ setup(
"License :: OSI Approved :: Apache Software License",
"Topic :: Software Development :: Libraries :: Python Modules"],
install_requires = ['requests', "pycrypto>=2.6.1", "cherrypy==3.2.4",
"mako", "pyjwkest", "beaker", "alabaster", "importlib",
"argparse", "pyOpenSSL", "python-ldap"],
"mako", "pyjwkest>=0.5.1", "beaker", "alabaster",
"importlib", "argparse", "pyOpenSSL", "python-ldap"],
tests_require=['pytest'],
zip_safe=False,
cmdclass={'test': PyTest},

View File

@ -7,12 +7,12 @@ import requests
import random
import string
import cookielib
import logging
from Cookie import SimpleCookie
from oic.utils.keyio import KeyJar
from oic.utils.time_util import utc_time_sans_frac
from oic.exception import UnSupported
import logging
logger = logging.getLogger(__name__)
@ -667,8 +667,9 @@ class Client(PBase):
request_args["access_token"] = token.access_token
return self.construct_request(request, request_args, extra_args)
def get_or_post(self, uri, method, req,
content_type=DEFAULT_POST_CONTENT_TYPE, accept=None, **kwargs):
@staticmethod
def get_or_post(uri, method, req, content_type=DEFAULT_POST_CONTENT_TYPE,
accept=None, **kwargs):
if method == "GET":
_qp = req.to_urlencoded()
if _qp:
@ -687,7 +688,7 @@ class Client(PBase):
"Unsupported content type: '%s'" % content_type)
header_ext = {"Content-type": content_type}
if (accept):
if accept:
header_ext = {"Accept": accept}
if "headers" in kwargs.keys():

View File

@ -558,6 +558,11 @@ class Message(object):
if required:
raise MissingRequiredAttribute("%s" % attribute)
continue
else:
if not val:
if required:
raise MissingRequiredAttribute("%s" % attribute)
continue
if attribute not in _allowed:
continue

View File

@ -3,8 +3,7 @@ import traceback
import sys
import urllib
import urlparse
from oic.utils.sdb import AccessCodeUsed
from oic.utils.sdb import AccessCodeUsed, AuthnEvent
__author__ = 'rohe0002'
@ -485,6 +484,7 @@ class Provider(object):
return _authn(**authn_args)
else:
user = identity["uid"]
aevent = AuthnEvent(user, authn_info=acr)
# If I get this far the person is already authenticated
logger.debug("- authenticated -")
@ -495,7 +495,7 @@ class Provider(object):
except KeyError:
oidc_req = None
skey = self.sdb.create_authz_session(user, areq, oidreq=oidc_req)
skey = self.sdb.create_authz_session(aevent, areq, oidreq=oidc_req)
# Now about the authorization step.
try:

View File

@ -5,13 +5,11 @@ import urllib
import sys
from jwkest.jwe import JWE
from requests import ConnectionError
from jwkest import jws, jwe
from jwkest.jws import alg2keytype
from oic.utils import time_util
from oic.utils.authn.user import NoSuchAuthentication
from oic.utils.authn.user import ToOld
from oic.utils.authn.user import TamperAllert
from oic.utils.sdb import AuthnEvent
from oic.utils.time_util import utc_time_sans_frac
from oic.utils.keyio import KeyBundle, dump_jwks
from oic.utils.keyio import key_export
@ -373,6 +371,11 @@ class Provider(AProvider):
req_user = areq["id_token"]["sub"]
except KeyError:
pass
else:
try:
assert areq["client_id"] in areq["id_token"]["aud"]
except AssertionError:
req_user = "" # Not allow to use
return req_user
@ -542,6 +545,23 @@ class Provider(AProvider):
kwargs["cookie"] = cookie
return authn.verify(_req, **kwargs)
def setup_session(self, areq, authn_event, cinfo):
try:
oidc_req = areq["request"]
except KeyError:
oidc_req = None
sid = self.sdb.create_authz_session(authn_event, areq, oidreq=oidc_req)
kwargs = {}
for param in ["sector_id", "preferred_id_type"]:
try:
kwargs[param] = cinfo[param]
except KeyError:
pass
self.sdb.do_sub(sid, **kwargs)
return sid
def authorization_endpoint(self, request="", cookie=None, **kwargs):
""" The AuthorizationRequest endpoint
@ -590,7 +610,20 @@ class Provider(AProvider):
return areq
logger.debug("AuthzRequest+oidc_request: %s" % (areq.to_dict(),))
cinfo = self.cdb[areq["client_id"]]
req_user = self.required_user(areq)
if req_user:
try:
sids = self.sdb.sub2sid[req_user]
except KeyError:
pass
else:
# anyone will do
authn_event = self.sdb[sids[0]]["authn_event"]
# Is the authentication event to be regarded as valid ?
if authn_event.valid():
sid = self.setup_session(areq, authn_event, cinfo)
return self.authz_part2(authn_event.uid, areq, sid)
authn, authn_class_ref = self.pick_auth(areq)
if not authn:
@ -598,7 +631,6 @@ class Provider(AProvider):
if not authn:
authn, authn_class_ref = self.pick_auth(areq, "any")
logger.debug("Cookie: %s" % cookie)
try:
try:
_auth_info = kwargs["authn"]
@ -607,7 +639,6 @@ class Provider(AProvider):
identity = authn.authenticated_as(cookie,
authorization=_auth_info,
max_age=self.max_age(areq))
auth_time = time_util.utc_now()
except (NoSuchAuthentication, ToOld, TamperAllert):
identity = None
@ -616,7 +647,6 @@ class Provider(AProvider):
"as_user": req_user,
"authn_class_ref": authn_class_ref}
cinfo = self.cdb[areq["client_id"]]
for attr in ["policy_uri", "logo_uri"]:
try:
authn_args[attr] = cinfo[attr]
@ -647,16 +677,12 @@ class Provider(AProvider):
else:
return authn(**authn_args)
authn_event = AuthnEvent(identity["uid"], authn_info=authn_class_ref)
logger.debug("- authenticated -")
logger.debug("AREQ keys: %s" % areq.keys())
try:
oidc_req = areq["request"]
except KeyError:
oidc_req = None
sid = self.sdb.create_authz_session(user, areq, oidreq=oidc_req,
auth_time=auth_time)
sid = self.setup_session(areq, authn_event, cinfo)
return self.authz_part2(user, areq, sid)
def userinfo_in_id_token_claims(self, session):
@ -776,7 +802,7 @@ class Provider(AProvider):
try:
_idtoken = self.sign_encrypt_id_token(
_info, client_info, req, user_info=userinfo,
auth_time=_info["auth_time"])
auth_time=_info["authn_event"].authn_time)
except (JWEException, NoSuitableSigningKeys) as err:
logger.warning(str(err))
return self._error(error="access_denied",
@ -804,9 +830,9 @@ class Provider(AProvider):
if "openid" in _info["scope"]:
userinfo = self.userinfo_in_id_token_claims(_info)
_idtoken = self.sign_encrypt_id_token(_info, client_info, req,
user_info=userinfo,
auth_time=_info["auth_time"])
_idtoken = self.sign_encrypt_id_token(
_info, client_info, req, user_info=userinfo,
auth_time=_info["authn_event"].authn_time)
sid = _sdb.token.get_key(rtoken)
_sdb.update(sid, "id_token", _idtoken)
@ -893,7 +919,7 @@ class Provider(AProvider):
logger.debug("userinfo_claim: %s" % userinfo_claims.to_dict())
logger.debug("Session info: %s" % session)
info = self.userinfo(session["local_sub"], userinfo_claims)
info = self.userinfo(session["authn_event"].uid, userinfo_claims)
info["sub"] = session["sub"]
logger.debug("user_info_response: %s" % (info,))
@ -914,11 +940,15 @@ class Provider(AProvider):
except KeyError: # Fall back to default
algo = self.jwx_def["sign_alg"]["userinfo"]
# Use my key for signing
key = self.keyjar.get_signing_key(alg2keytype(algo), "", alg=algo)
if not key:
return self._error(error="access_denied",
descr="Missing signing key")
if algo == "none":
key = []
else:
# Use my key for signing
key = self.keyjar.get_signing_key(alg2keytype(algo), "", alg=algo)
if not key:
return self._error(error="access_denied",
descr="Missing signing key")
jinfo = userinfo.to_jwt(key, algo)
if "userinfo_encrypted_response_alg" in client_info:
# encrypt with clients public key
@ -1175,16 +1205,18 @@ class Provider(AProvider):
"invalid_configuration_parameter",
descr="%s pointed to illegal URL" % item)
# necessary keys ?
# Do I have the necessary keys
for item in ["id_token_signed_response_alg",
"userinfo_signed_response_alg"]:
if item in request:
if request[item] in self.capabilities[PREFERENCE2PROVIDER[item]]:
ktyp = jws.alg2keytype(request[item])
# do I have this ktyp and for EC type keys the curve
_k = self.keyjar.get_signing_key(ktyp, alg=request[item])
if not _k:
del _cinfo[item]
if ktyp not in ["none", "OCT"]:
_k = self.keyjar.get_signing_key(ktyp,
alg=request[item])
if not _k:
del _cinfo[item]
try:
self.keyjar.load_keys(request, client_id)
@ -1619,7 +1651,7 @@ class Provider(AProvider):
# or 'code id_token'
id_token = self.sign_encrypt_id_token(
_sinfo, client_info, areq, user_info=user_info,
auth_time=_sinfo["auth_time"], **hargs)
auth_time=_sinfo["authn_event"].authn_time, **hargs)
aresp["id_token"] = id_token
_sinfo["id_token"] = id_token

View File

@ -333,6 +333,9 @@ class KeyJar(object):
:param url: Where can the key/-s be found
"""
if not url:
raise KeyError("No jwks_uri")
if "/localhost:" in url or "/localhost/" in url:
kc = KeyBundle(source=url, verify_ssl=False)
else:

View File

@ -1,6 +1,7 @@
import copy
import uuid
import time
from oic.oic import AuthorizationRequest
@ -125,10 +126,33 @@ class Token(object):
return self._split_token(token)[0]
class AuthnEvent(object):
def __init__(self, uid, valid=3600, authn_info=None):
"""
Creates a representation of an authentication event.
:param uid: The local user identifier
:param valid: How long the authentication is expected to be valid
:param authn_info: Info about the authentication event
:return:
"""
self.uid = uid
self.authn_time = int(time.time())
self.valid_until = self.authn_time + int(valid)
self.authn_info = authn_info
def valid(self):
return self.valid_until > int(time.time())
def valid_for(self):
return self.valid_until - int(time.time())
class SessionDB(object):
def __init__(self, db=None, secret="Ab01FG65", token_expires_in=3600,
password="4-amino-1H-pyrimidine-2-one",
def __init__(self, base_url, db=None, secret="Ab01FG65",
token_expires_in=3600, password="4-amino-1H-pyrimidine-2-one",
grant_expires_in=600, seed=""):
self.base_url = base_url
if db:
self._db = db
else:
@ -136,7 +160,7 @@ class SessionDB(object):
self.token = Token(secret, password)
self.token_expires_in = token_expires_in
self.grant_expires_in = grant_expires_in
self.uid2sid = {}
self.sub2sid = {}
self.seed = seed or secret
def __getitem__(self, item):
@ -189,52 +213,67 @@ class SessionDB(object):
(typ, key) = self.token.type_and_key(token)
return self.update(key, attribute, value)
def do_userid(self, sid, sub, sector_id, preferred_id_type):
def do_sub(self, sid, sector_id="", preferred_id_type="public"):
"""
Construct a sub (subject identifier)
:param sid: Session identifier
:param uid: The local user identifier
:param sector_id: Possible sector identifier
:param preferred_id_type: 'public'/'pairwise'
:return:
"""
uid = self._db[sid]["authn_event"].uid
old = [""]
if preferred_id_type == "public":
uid = sub
sub = "%x" % hash(uid+self.base_url)
else:
uid = pairwise_id(sub, sector_id, self.seed)
sub = pairwise_id(uid, sector_id, self.seed)
old.append(sub)
logger.debug("uid: %s, old: %s" % (uid, old))
self.uid2sid[uid] = sid
logger.debug("sub: %s, old: %s" % (sub, old))
# since sub can be public, there can be more then one session
# that uses the same subject identifier
try:
self.sub2sid[sub].append(sid)
except KeyError:
self.sub2sid[sub] = [sid]
for old_id in old:
try:
del self.uid2sid[old_id]
del self.sub2sid[old_id]
except KeyError:
pass
logger.debug("uid2sid: %s" % self.uid2sid)
self._db[sid]["local_sub"] = sub
self._db[sid]["sub"] = uid
logger.debug("sub2sid: %s" % self.sub2sid)
self._db[sid]["sub"] = sub
return uid
return sub
def create_authz_session(self, sub, areq, id_token=None, oidreq=None,
def create_authz_session(self, aevent, areq, id_token=None, oidreq=None,
**kwargs):
"""
:param sub: Identifier for the user, this is the real identifier
:param aevent: An AuthnEvent instance
:param areq: The AuthorizationRequest instance
:param id_token: An IDToken instance
:param oidreq: An OpenIDRequest instance
:return: The session identifier, which is the database key
"""
sid = self.token.key(user=sub, areq=areq)
sid = self.token.key(user=aevent.uid, areq=areq)
access_grant = self.token(sid=sid)
_dic = {
"oauth_state": "authz",
"local_sub": sub,
"sub": sub,
"code": access_grant,
"code_used": False,
"authzreq": areq.to_json(),
"client_id": areq["client_id"],
"revoked": False,
"authn_event": aevent
}
_dic.update(kwargs)
@ -258,9 +297,12 @@ class SessionDB(object):
_dic["oidreq"] = oidreq.to_json()
self._db[sid] = _dic
self.uid2sid[sub] = sid
return sid
def get_authentication_event(self, sid):
return self._db[sid]["authn_event"]
def get_token(self, key):
if self._db[key]["oauth_state"] == "authz":
return self._db[key]["code"]
@ -338,7 +380,8 @@ class SessionDB(object):
else:
raise WrongTokenType("Not a refresh token!")
def is_expired(self, sess):
@staticmethod
def is_expired(sess):
if "token_expires_at" in sess:
if sess["token_expires_at"] < utc_time_sans_frac():
return True
@ -377,12 +420,6 @@ class SessionDB(object):
except KeyError:
return False
# def set_oir(self, key, oir):
# self._db[key] = oir.dictionary()
#
# def get_oir(self, key):
# return OpenIDRequest(**self._db[key])
def revoke_token(self, token):
# revokes either the refresh token or the access token
@ -405,32 +442,39 @@ class SessionDB(object):
self._db[sid]["revoked"] = True
def get_client_id(self, uid):
_dict = self._db[self.uid2sid[uid]]
def get_client_id(self, sub):
_dict = self._db[self.sub2sid[sub]]
return _dict["client_id"]
def get_verified_Logout(self, uid):
_dict = self._db[self.uid2sid[uid]]
def get_verified_Logout(self, sub):
_dict = self._db[self.sub2sid[sub]]
if "verified_logout" not in _dict:
return None
return _dict["verified_logout"]
def set_verify_logout(self, uid):
_dict = self._db[self.uid2sid[uid]]
def set_verify_logout(self, sub):
_dict = self._db[self.sub2sid[sub]]
_dict["verified_logout"] = uuid.uuid4().urn
def get_token_id(self, uid):
_dict = self._db[self.uid2sid[uid]]
def get_token_id(self, sub):
_dict = self._db[self.sub2sid[sub]]
return _dict["id_token"]
def is_revoke_uid(self, uid):
return self._db[self.uid2sid[uid]]["revoked"]
def is_revoke_uid(self, sub):
return self._db[self.sub2sid[sub]]["revoked"]
def revoke_uid(self, uid):
self._db[self.uid2sid[uid]]["revoked"] = True
def revoke_uid(self, sub):
self._db[self.sub2sid[sub]]["revoked"] = True
def get_sid_from_userid(self, uid):
return self.uid2sid[uid]
def get_sids_from_sub(self, sub):
"""
Returns list of identifiers for sessions that are connected to this
subject identifier
:param sub: subject identifier
:return: list of session identifiers
"""
return self.sub2sid[sub]
def duplicate(self, sinfo):
_dic = copy.copy(sinfo)
@ -450,7 +494,7 @@ class SessionDB(object):
pass
self._db[sid] = _dic
self.uid2sid[_dic["sub"]] = sid
self.sub2sid[_dic["sub"]] = sid
return sid
def read(self, token):

View File

@ -6,7 +6,7 @@ from oic.utils.webfinger import WebFinger
__author__ = 'rohe0002'
from oic.utils.sdb import SessionDB
from oic.utils.sdb import SessionDB, AuthnEvent
from oic.utils.time_util import utc_time_sans_frac
from oic.oic import Server
@ -43,7 +43,7 @@ ENDPOINT = {
class MyFakeOICServer(Server):
def __init__(self, name=""):
Server.__init__(self)
self.sdb = SessionDB()
self.sdb = SessionDB(name)
self.name = name
self.client = {}
self.registration_expires_in = 3600
@ -96,9 +96,10 @@ class MyFakeOICServer(Server):
def authorization_endpoint(self, query):
req = self.parse_authorization_request(query=query)
sid = self.sdb.create_authz_session(sub="user", areq=req)
aevent = AuthnEvent("user", authn_info="acr")
sid = self.sdb.create_authz_session(aevent, areq=req)
sub = self.sdb.do_sub(sid)
_info = self.sdb[sid]
_info["sub"] = _info["local_sub"]
if "code" in req["response_type"]:
if "token" in req["response_type"]:

View File

@ -109,6 +109,7 @@ AUTHZ = AuthzHandling()
SYMKEY = "symmetric key used to encrypt cookie info"
USERINFO = UserInfo(USERDB)
provider_init = Provider("pyoicserv", SessionDB(), CDB, AUTHN_BROKER, USERINFO,
provider_init = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, USERINFO,
AUTHZ, verify_client, SYMKEY, urlmap=URLMAP,
keyjar=KEYJAR)

View File

@ -89,21 +89,21 @@ def _eq(l1, l2):
def test_provider_init():
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
verify_client)
provider = Provider("pyoicserv", sdb.SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, AUTHZ, verify_client)
assert provider
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
verify_client,
provider = Provider("pyoicserv", sdb.SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, AUTHZ, verify_client,
urlmap={"client1": ["https://example.com/authz"]})
assert provider.urlmap["client1"] == ["https://example.com/authz"]
def test_provider_authorization_endpoint():
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
verify_client)
provider = Provider("pyoicserv", sdb.SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, AUTHZ, verify_client)
bib = {"scope": ["openid"],
"state": "id-6da9ca0cc23959f5f33e8becd9b08cae",
@ -121,8 +121,8 @@ def test_provider_authorization_endpoint():
def test_provider_authenticated():
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
verify_client, symkey=rndstr(16))
provider = Provider("pyoicserv", sdb.SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, AUTHZ, verify_client, symkey=rndstr(16))
_session_db = {}
cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
server_info=SERVER_INFO, **CONSUMER_CONFIG)
@ -154,8 +154,8 @@ def test_provider_authenticated():
def test_provider_authenticated_token():
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
verify_client, symkey=rndstr(16))
provider = Provider("pyoicserv", sdb.SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, AUTHZ, verify_client, symkey=rndstr(16))
_session_db = {}
cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
server_info=SERVER_INFO, **CONSUMER_CONFIG)
@ -176,8 +176,8 @@ def test_provider_authenticated_token():
def test_token_endpoint():
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
verify_client, symkey=rndstr(16))
provider = Provider("pyoicserv", sdb.SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, AUTHZ, verify_client, symkey=rndstr(16))
authreq = AuthorizationRequest(state="state",
redirect_uri="http://example.com/authz",
@ -212,7 +212,8 @@ def test_token_endpoint():
def test_token_endpoint_unauth():
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
provider = Provider("pyoicserv", sdb.SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, AUTHZ,
verify_client, symkey=rndstr(16))
authreq = AuthorizationRequest(state="state",

View File

@ -115,8 +115,8 @@ AUTHZ_ORG_URL = "http://example.org/authorization"
class TestOICConsumer():
def setup_class(self):
self.consumer = Consumer(SessionDB(), CONFIG, CLIENT_CONFIG,
SERVER_INFO)
self.consumer = Consumer(SessionDB(SERVER_INFO["issuer"]),
CONFIG, CLIENT_CONFIG, SERVER_INFO)
self.consumer.client_secret = CLIENT_SECRET
def test_init(self):
@ -306,7 +306,8 @@ class TestOICConsumer():
def test_complete_secret_auth():
consumer = Consumer(SessionDB(), CONFIG, CLIENT_CONFIG, SERVER_INFO)
consumer = Consumer(SessionDB(SERVER_INFO["issuer"]), CONFIG,
CLIENT_CONFIG, SERVER_INFO)
mfos = MyFakeOICServer("http://localhost:8088")
mfos.keyjar = SRVKEYS
consumer.http_request = mfos.http_request
@ -343,7 +344,8 @@ def test_complete_secret_auth():
def test_complete_auth_token():
consumer = Consumer(SessionDB(), CONFIG, CLIENT_CONFIG, SERVER_INFO)
consumer = Consumer(SessionDB(SERVER_INFO["issuer"]), CONFIG,
CLIENT_CONFIG, SERVER_INFO)
mfos = MyFakeOICServer("http://localhost:8088")
mfos.keyjar = SRVKEYS
consumer.http_request = mfos.http_request
@ -386,7 +388,8 @@ def test_complete_auth_token():
def test_complete_auth_token_idtoken():
consumer = Consumer(SessionDB(), CONFIG, CLIENT_CONFIG, SERVER_INFO)
consumer = Consumer(SessionDB(SERVER_INFO["issuer"]), CONFIG,
CLIENT_CONFIG, SERVER_INFO)
consumer.keyjar = CLIKEYS
mfos = MyFakeOICServer("http://localhost:8088")
mfos.keyjar = SRVKEYS
@ -427,7 +430,8 @@ def test_complete_auth_token_idtoken():
def test_userinfo():
consumer = Consumer(SessionDB(), CONFIG, CLIENT_CONFIG, SERVER_INFO)
consumer = Consumer(SessionDB(SERVER_INFO["issuer"]), CONFIG,
CLIENT_CONFIG, SERVER_INFO)
consumer.keyjar = CLIKEYS
mfos = MyFakeOICServer("http://localhost:8088")
mfos.keyjar = SRVKEYS

View File

@ -8,6 +8,7 @@ from oic.utils.authn.authn_context import AuthnBroker
from oic.utils.authn.client import verify_client
from oic.utils.authn.user import UserAuthnMethod
from oic.utils.authz import AuthzHandling
from oic.utils.http_util import Response
from oic.utils.userinfo import UserInfo
from oic.exception import RedirectURIError
@ -28,7 +29,7 @@ from oic.oic.message import CheckSessionRequest
from oic.oic.message import RegistrationRequest
from oic.oic.message import IdToken
from oic.utils.sdb import SessionDB
from oic.utils.sdb import SessionDB, AuthnEvent
from oic.oic import Client
from oic.oic import make_openid_request
@ -105,8 +106,8 @@ CDB = {
},
CLIENT_ID: {
"client_secret": CLIENT_SECRET,
"redirect_uris": [("http://localhost:8087/authz", None)]
}
}
USERDB = {
@ -142,7 +143,11 @@ class DummyAuthn(UserAuthnMethod):
self.user = user
def authenticated_as(self, cookie=None, **kwargs):
return {"uid": self.user}
if cookie == "FAIL":
return None
else:
return {"uid": self.user}
#AUTHN = UsernamePasswordMako(None, "login.mako", tl, PASSWD, "authenticated")
AUTHN_BROKER = AuthnBroker()
@ -153,7 +158,8 @@ AUTHZ = AuthzHandling()
SYMKEY = rndstr(16) # symmetric key used to encrypt cookie info
USERINFO = UserInfo(USERDB)
provider_init = Provider("pyoicserv", SessionDB(), CDB, AUTHN_BROKER, USERINFO,
provider_init = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, USERINFO,
AUTHZ, verify_client, SYMKEY, urlmap=URLMAP,
keyjar=KEYJAR)
@ -230,10 +236,13 @@ def test_server_authorization_endpoint_id_token():
redirect_uri="http://example.com/authz",
scope=["openid"], state="state000")
sdb = SessionDB()
sid = sdb.create_authz_session("userX", AREQ)
sdb = provider.sdb
ae = AuthnEvent("userX")
sid = sdb.create_authz_session(ae, AREQ)
sdb.do_sub(sid)
_info = sdb[sid]
# All this is jut removed when the id_token is constructed
# The proper information comes from the session information
_user_info = IdToken(iss="https://foo.example.om", sub="foo",
aud=bib["client_id"], exp=epoch_in_a_while(minutes=10),
acr="2", nonce=bib["nonce"])
@ -244,14 +253,23 @@ def test_server_authorization_endpoint_id_token():
user_info=_user_info)
req["id_token"] = idt
query_string = req.to_urlencoded()
QUERY_STRING = req.to_urlencoded()
resp = provider.authorization_endpoint(request=QUERY_STRING)
# client_id not in id_token["aud"] so login required
resp = provider.authorization_endpoint(request=query_string, cookie="FAIL")
print resp
assert "error=login_required" in resp.message
req["client_id"] = "client_1"
query_string = req.to_urlencoded()
# client_id is in id_token["aud"] so no login required
resp = provider.authorization_endpoint(request=query_string, cookie="FAIL")
print resp.message
assert resp.message.startswith("http://localhost:8087/authz")
def test_server_authenticated():
server = provider_init
@ -409,17 +427,18 @@ def test_token_endpoint():
_sdb = server.sdb
sid = _sdb.token.key(user="sub", areq=authreq)
access_grant = _sdb.token(sid=sid)
ae = AuthnEvent("user")
_sdb[sid] = {
"oauth_state": "authz",
"sub": "sub",
"authn_event": ae,
"authzreq": authreq.to_json(),
"client_id": CLIENT_ID,
"code": access_grant,
"code_used": False,
"scope": ["openid"],
"redirect_uri": "http://example.com/authz",
"auth_time": 1000000
}
_sdb.do_sub(sid)
# Construct Access token request
areq = AccessTokenRequest(code=access_grant, client_id=CLIENT_ID,
@ -446,9 +465,10 @@ def test_token_endpoint_unauth():
_sdb = server.sdb
sid = _sdb.token.key(user="sub", areq=authreq)
access_grant = _sdb.token(sid=sid)
ae = AuthnEvent("user")
_sdb[sid] = {
"authn_event": ae,
"oauth_state": "authz",
"sub": "sub",
"authzreq": "",
"client_id": "client_1",
"code": access_grant,
@ -456,6 +476,7 @@ def test_token_endpoint_unauth():
"scope": ["openid"],
"redirect_uri": "http://example.com/authz"
}
_sdb.do_sub(sid)
# Construct Access token request
areq = AccessTokenRequest(code=access_grant,
@ -495,7 +516,9 @@ def test_idtoken():
redirect_uri="http://example.com/authz",
scope=["openid"], state="state000")
sid = server.sdb.create_authz_session("sub", AREQ)
ae = AuthnEvent("sub")
sid = server.sdb.create_authz_session(ae, AREQ)
server.sdb.do_sub(sid)
session = server.sdb[sid]
id_token = server.id_token_as_signed_jwt(session)
@ -531,7 +554,7 @@ def test_userinfo_endpoint():
ident = OpenIDSchema().deserialize(resp3.message, "json")
print ident.keys()
assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email'])
assert ident["sub"] == USERDB["username"]["sub"]
assert ident["sub"] == hash(USERDB["username"]["sub"]+server.sdb.base_url)
def test_check_session_endpoint():
@ -577,8 +600,8 @@ def test_registration_endpoint():
def test_provider_key_setup():
provider = Provider("pyoicserv", SessionDB(), None, None, None, None, None,
"")
provider = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), None,
None, None, None, None, "")
provider.baseurl = "http://www.example.com/"
provider.key_setup("static", sig={"format": "jwk", "alg": "RSA"})
@ -714,4 +737,4 @@ def test_key_rollover():
assert len(provider2.keyjar.issuer_keys[""]) == 2
if __name__ == "__main__":
test_key_rollover()
test_server_authorization_endpoint_id_token()

View File

@ -6,7 +6,7 @@ import time
from pytest import raises
from oic.utils.sdb import SessionDB
from oic.utils.sdb import SessionDB, AuthnEvent
from oic.utils.sdb import ExpiredToken
from oic.oic.message import AuthorizationRequest
from oic.oic.message import OpenIDRequest
@ -31,23 +31,25 @@ OAUTH2_AREQ = AuthorizationRequest(response_type="code",
redirect_uri="http://example.com/authz",
scope=["openid"], state="state000")
BASE_URL = "https://exampl.com/"
def _eq(l1, l2):
return set(l1) == set(l2)
def test_token():
sdb = SessionDB()
sdb = SessionDB(BASE_URL)
sid = sdb.token.key(areq=AREQ)
assert len(sid) == 56
sdb = SessionDB({"a": "b"})
sdb = SessionDB(BASE_URL, {"a": "b"})
sid = sdb.token.key(areq=AREQ)
assert len(sid) == 56
def test_new_token():
sdb = SessionDB()
sdb = SessionDB(BASE_URL)
sid = sdb.token.key(areq=AREQ)
assert len(sid) == 56
@ -63,7 +65,7 @@ def test_new_token():
def test_type_and_key():
sdb = SessionDB()
sdb = SessionDB(BASE_URL)
sid = sdb.token.key(areq=AREQ)
code = sdb.token(sid=sid)
print sid
@ -74,7 +76,7 @@ def test_type_and_key():
def test_setitem():
sdb = SessionDB()
sdb = SessionDB(BASE_URL)
sid = sdb.token.key(areq=AREQ)
code = sdb.token(sid=sid)
@ -90,7 +92,7 @@ def test_setitem():
def test_update():
sdb = SessionDB()
sdb = SessionDB(BASE_URL)
sid = sdb.token.key(areq=AREQ)
code = sdb.token(sid=sid)
@ -111,33 +113,37 @@ def test_update():
def test_create_authz_session():
sdb = SessionDB()
sid = sdb.create_authz_session("sub", AREQ)
sdb = SessionDB(BASE_URL)
ae = AuthnEvent("uid")
sid = sdb.create_authz_session(ae, AREQ)
sdb.do_sub(sid)
info = sdb[sid]
print info
assert info["oauth_state"] == "authz"
sdb = SessionDB()
sdb = SessionDB(BASE_URL)
ae = AuthnEvent("sub")
# Missing nonce property
sid = sdb.create_authz_session("sub", OAUTH2_AREQ)
sid = sdb.create_authz_session(ae, OAUTH2_AREQ)
info = sdb[sid]
print info
assert info["oauth_state"] == "authz"
sid2 = sdb.create_authz_session("sub", AREQN)
ae = AuthnEvent("sub")
sid2 = sdb.create_authz_session(ae, AREQN)
info = sdb[sid2]
print info
assert info["nonce"] == "something"
sid3 = sdb.create_authz_session("sub", AREQN, id_token="id_token")
sid3 = sdb.create_authz_session(ae, AREQN, id_token="id_token")
info = sdb[sid3]
print info
assert info["id_token"] == "id_token"
sid4 = sdb.create_authz_session("sub", AREQN, oidreq=OIDR)
sid4 = sdb.create_authz_session(ae, AREQN, oidreq=OIDR)
info = sdb[sid4]
print info
@ -146,10 +152,10 @@ def test_create_authz_session():
def test_create_authz_session_with_sector_id():
sdb = SessionDB(seed="foo")
uid = "sub"
sid5 = sdb.create_authz_session(uid, AREQN, oidreq=OIDR)
sdb.do_userid(sid5, uid, "http://example.com/si.jwt", "pairwise")
sdb = SessionDB(BASE_URL, seed="foo")
ae = AuthnEvent("sub")
sid5 = sdb.create_authz_session(ae, AREQN, oidreq=OIDR)
sdb.do_sub(sid5, "http://example.com/si.jwt", "pairwise")
info_1 = sdb[sid5]
print info_1
@ -158,7 +164,7 @@ def test_create_authz_session_with_sector_id():
assert info_1["sub"] != "sub"
user_id1 = info_1["sub"]
sdb.do_userid(sid5, uid, "http://example.net/si.jwt", "pairwise")
sdb.do_sub(sid5, "http://example.net/si.jwt", "pairwise")
info_2 = sdb[sid5]
print info_2
@ -167,34 +173,35 @@ def test_create_authz_session_with_sector_id():
def test_upgrade_to_token():
sdb = SessionDB()
sid = sdb.create_authz_session("sub", AREQ)
sdb = SessionDB(BASE_URL)
ae1 = AuthnEvent("sub")
sid = sdb.create_authz_session(ae1, AREQ)
grant = sdb[sid]["code"]
_dict = sdb.upgrade_to_token(grant)
print _dict.keys()
assert _eq(_dict.keys(), ['code', 'authzreq', 'token_type', 'local_sub',
'client_id', 'oauth_state', 'refresh_token',
'revoked', 'sub', 'access_token',
'token_expires_at', 'expires_in', 'state',
'redirect_uri', 'code_used', 'scope',
'access_token_scope'])
assert _eq(_dict.keys(), ['authn_event', 'code', 'authzreq', 'revoked',
'access_token', 'token_expires_at', 'expires_in',
'token_type', 'state', 'redirect_uri',
'code_used', 'client_id', 'scope', 'oauth_state',
'refresh_token', 'access_token_scope'])
raises(Exception, 'sdb.upgrade_to_token(grant)')
raises(Exception, 'sdb.upgrade_to_token(_dict["access_token"]')
sdb = SessionDB()
sid = sdb.create_authz_session("another_user_id", AREQ)
sdb = SessionDB(BASE_URL)
ae2 = AuthnEvent("another_user_id")
sid = sdb.create_authz_session(ae2, AREQ)
grant = sdb[sid]["code"]
_dict = sdb.upgrade_to_token(grant, id_token="id_token", oidreq=OIDR)
print _dict.keys()
assert _eq(_dict.keys(), ['code', 'authzreq', 'id_token', 'token_type',
'local_sub', 'client_id', 'oauth_state',
'refresh_token', 'revoked', 'sub', 'oidreq',
'access_token', 'token_expires_at', 'expires_in',
'state', 'redirect_uri', 'code_used', 'scope',
assert _eq(_dict.keys(), ['authn_event', 'code', 'authzreq', 'revoked',
'oidreq', 'access_token', 'id_token',
'token_expires_at', 'expires_in', 'token_type',
'state', 'redirect_uri', 'code_used', 'client_id',
'scope', 'oauth_state', 'refresh_token',
'access_token_scope'])
assert _dict["id_token"] == "id_token"
@ -204,8 +211,9 @@ def test_upgrade_to_token():
def test_refresh_token():
sdb = SessionDB()
sid = sdb.create_authz_session("sub", AREQ)
sdb = SessionDB(BASE_URL)
ae = AuthnEvent("sub")
sid = sdb.create_authz_session(ae, AREQ)
grant = sdb[sid]["code"]
_dict = sdb.upgrade_to_token(grant)
dict1 = _dict.copy()
@ -222,8 +230,9 @@ def test_refresh_token():
def test_is_valid():
sdb = SessionDB()
sid = sdb.create_authz_session("sub", AREQ)
sdb = SessionDB(BASE_URL)
ae1 = AuthnEvent("sub")
sid = sdb.create_authz_session(ae1, AREQ)
grant = sdb[sid]["code"]
assert sdb.is_valid(grant)
@ -255,7 +264,8 @@ def test_is_valid():
dict2["access_token"] = token1
assert sdb.is_valid(token2) is False
sid = sdb.create_authz_session("another:user", AREQ)
ae = AuthnEvent("another:user")
sid = sdb.create_authz_session(ae, AREQ)
grant = sdb[sid]["code"]
gdict = sdb[grant]
@ -264,8 +274,9 @@ def test_is_valid():
def test_revoke_token():
sdb = SessionDB()
sid = sdb.create_authz_session("sub", AREQ)
sdb = SessionDB(BASE_URL)
ae1 = AuthnEvent("sub")
sid = sdb.create_authz_session(ae1, AREQ)
grant = sdb[sid]["code"]
_dict = sdb.upgrade_to_token(grant)
@ -291,9 +302,26 @@ def test_revoke_token():
# --- new token ----
sdb = SessionDB()
sid = sdb.create_authz_session("sub", AREQ)
sdb = SessionDB(BASE_URL)
ae2 = AuthnEvent("sub")
sid = sdb.create_authz_session(ae2, AREQ)
grant = sdb[sid]["code"]
sdb.revoke_token(grant)
assert sdb.is_valid(grant) is False
def test_sub_to_authn_event():
sdb = SessionDB(BASE_URL)
ae2 = AuthnEvent("sub")
sid = sdb.create_authz_session(ae2, AREQ)
sub = sdb.do_sub(sid)
# given the sub find out weather the authn event is still valid
sids = sdb.sub2sid[sub]
ae = sdb[sids[0]]["authn_event"]
assert ae.valid()
if __name__ == "__main__":
test_sub_to_authn_event()

View File

@ -144,7 +144,8 @@ def test_srv2():
req = cc.construct_UserClaimsRequest(
request_args={"sub": "diana", "claims_names": ["gender", "birthdate"]})
srv = ClaimsServer("pyoicserv", SessionDB(), CDB, USERINFO, verify_client,
srv = ClaimsServer("pyoicserv", SessionDB("https://example.com"), CDB,
USERINFO, verify_client,
keyjar=KEYJAR, dist_claims_mode=ClaimsMode(USER2MODE))
srv.keyjar[""] = keybundle_from_local_file("%s/rsa.key" % BASE_PATH, "rsa", ["ver", "sig"])

View File

@ -89,14 +89,16 @@ def _eq(l1, l2):
def test_provider_init():
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
provider = Provider("pyoicserv", sdb.SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, AUTHZ,
verify_client, client_info_url="https://example.com/as")
assert provider
def test_client_registration():
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
provider = Provider("pyoicserv", sdb.SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, AUTHZ,
verify_client,
client_info_url="https://example.com/as/")
@ -125,8 +127,8 @@ def test_client_registration_uri_error():
"jwks_uri": "https://client.example.org/my_public_keys.jwks"
}
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
verify_client,
provider = Provider("pyoicserv", sdb.SessionDB("https://example.org/"),
CDB, AUTHN_BROKER, AUTHZ, verify_client,
client_info_url="https://example.com/as/")
request = RegistrationRequest(**args)
@ -152,8 +154,8 @@ def test_client_registration_2():
"scope": "read write dolphin",
}
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
verify_client,
provider = Provider("pyoicserv", sdb.SessionDB("https://example.org/"),
CDB, AUTHN_BROKER, AUTHZ, verify_client,
client_info_url="https://example.com/as/",
client_authn_methods={
"client_secret_post": ClientSecretPost,
@ -183,8 +185,8 @@ def test_client_user_info_get():
"scope": "read write dolphin",
}
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
verify_client,
provider = Provider("pyoicserv", sdb.SessionDB("https://example.org/"),
CDB, AUTHN_BROKER, AUTHZ, verify_client,
client_info_url="https://example.com/as/",
client_authn_methods={
"client_secret_post": ClientSecretPost,
@ -225,8 +227,8 @@ def test_client_registration_update():
"scope": "read write dolphin",
}
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
verify_client,
provider = Provider("pyoicserv", sdb.SessionDB("https://example.org/"),
CDB, AUTHN_BROKER, AUTHZ, verify_client,
client_info_url="https://example.com/as/",
client_authn_methods={
"client_secret_post": ClientSecretPost,
@ -283,7 +285,8 @@ def test_client_registration_delete():
"scope": "read write dolphin",
}
provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
provider = Provider("pyoicserv", sdb.SessionDB(SERVER_INFO["issuer"]), CDB,
AUTHN_BROKER, AUTHZ,
verify_client,
client_info_url="https://example.com/as/",
client_authn_methods={