示例#1
0
def test_server_authenticated_1():
    server = provider_init
    _session_db = {}
    cons = Consumer(
        _session_db,
        CONSUMER_CONFIG,
        CLIENT_CONFIG,
        server_info=SERVER_INFO,
    )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    state, location = cons.begin("openid",
                                 "code",
                                 path="http://localhost:8087")

    resp = server.authorization_endpoint(request=location.split("?")[1])

    print resp
    aresp = cons.parse_response(AuthorizationResponse,
                                location,
                                sformat="urlencoded")

    print aresp.keys()
    assert aresp.type() == "AuthorizationResponse"
    assert _eq(aresp.keys(), [
        'request', 'state', 'redirect_uri', 'claims', 'response_type',
        'client_id', 'scope'
    ])
示例#2
0
def test_userinfo_endpoint():
    server = provider_init

    _session_db = {}
    cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG,
                    server_info=SERVER_INFO)
    cons.debug = True
    cons.client_secret = "drickyoughurt"
    cons.config["response_type"] = ["token"]
    cons.config["request_method"] = "parameter"
    cons.keyjar[""] = KC_RSA

    location = cons.begin("openid", "token", path="http://localhost:8087")

    resp = server.authorization_endpoint(request=location.split("?")[1])

    line = resp.message
    path, query = line.split("?")

    # redirect
    atr = AuthorizationResponse().deserialize(query, "urlencoded")

    uir = UserInfoRequest(access_token=atr["access_token"], schema="openid")

    resp3 = server.userinfo_endpoint(request=uir.to_urlencoded())
    ident = OpenIDSchema().deserialize(resp3.message, "json")
    print ident.keys()
    assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email'])
    assert ident["sub"] == USERDB["username"]["sub"]
示例#3
0
def test_server_authenticated_token():
    server = provider_init

    _session_db = {}
    cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG,
                    server_info=SERVER_INFO, )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    cons.config["response_type"] = ["token"]
    environ = BASE_ENVIRON

    location = cons.begin(environ, start_response)

    environ = BASE_ENVIRON.copy()
    environ["QUERY_STRING"] = location.split("?")[1]

    resp = server.authorization_endpoint(environ, start_response)

    sid = resp[0][len("<form>"):-len("</form>")]
    environ2 = create_return_form_env("user", "password", sid)

    resp2 = server.authenticated(environ2, start_response)

    assert len(resp2) == 1
    txt = resp2[0]
    assert "access_token=" in txt
    assert "token_type=Bearer" in txt
示例#4
0
def test_server_authenticated_none():
    server = provider_init
    _session_db = {}
    cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG,
                    server_info=SERVER_INFO, )
    cons.debug = True
    cons.keyjar[""] = KC_RSA
    cons.response_type = "none"
    environ = BASE_ENVIRON

    location = cons.begin(environ, start_response)

    environ = BASE_ENVIRON.copy()
    environ["QUERY_STRING"] = location.split("?")[1]

    resp = server.authorization_endpoint(environ, start_response)

    sid = resp[0][len("<form>"):-len("</form>")]
    environ2 = create_return_form_env("user", "password", sid)

    resp2 = server.authenticated(environ2, start_response)

    assert len(resp2) == 1
    txt = resp2[0]
    pos0 = txt.index("<title>") + len("<title>Redirecting to ")
    pos1 = txt.index("</title>")
    location = txt[pos0:pos1]
    print location

    assert location.startswith("http://localhost:8087/authz")
    query = location.split("?")[1]
    print query
    assert "token_type=Bearer" in query
示例#5
0
def test_userinfo_endpoint():
    server = provider_init

    _session_db = {}
    cons = Consumer(_session_db,
                    CONSUMER_CONFIG,
                    CLIENT_CONFIG,
                    server_info=SERVER_INFO)
    cons.debug = True
    cons.client_secret = "drickyoughurt"
    cons.config["response_type"] = ["token"]
    cons.config["request_method"] = "parameter"
    cons.keyjar[""] = KC_RSA

    state, location = cons.begin("openid",
                                 "token",
                                 path="http://localhost:8087")

    resp = server.authorization_endpoint(request=location.split("?")[1])

    line = resp.message
    path, query = line.split("#")

    # redirect
    atr = AuthorizationResponse().deserialize(query, "urlencoded")

    uir = UserInfoRequest(access_token=atr["access_token"], schema="openid")

    resp3 = server.userinfo_endpoint(request=uir.to_urlencoded())
    ident = OpenIDSchema().deserialize(resp3.message, "json")
    print ident.keys()
    assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email'])
示例#6
0
文件: FakeOp.py 项目: borgand/SATOSA
    def setup_userinfo_endpoint(self):
        cons = Consumer({}, CONSUMER_CONFIG, {"client_id": CLIENT_ID},
                        server_info=SERVER_INFO, )
        cons.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]}
        cons.keyjar[""] = KC_RSA

        cons.client_secret = "drickyoughurt"
        state, location = cons.begin("openid", "token",
                                     path=TestConfiguration.get_instance().rp_base)

        resp = self.provider.authorization_endpoint(
            request=urlparse(location).query)

        # redirect
        atr = AuthorizationResponse().deserialize(
            urlparse(resp.message).fragment, "urlencoded")

        uir = UserInfoRequest(access_token=atr["access_token"], schema="openid")
        resp = self.provider.userinfo_endpoint(request=uir.to_urlencoded())
        responses.add(
            responses.POST,
            self.op_base + "userinfo",
            body=resp.message,
            status=200,
            content_type='application/json')
示例#7
0
文件: FakeOp.py 项目: borgand/SATOSA
    def setup_userinfo_endpoint(self):
        cons = Consumer(
            {},
            CONSUMER_CONFIG,
            {"client_id": CLIENT_ID},
            server_info=SERVER_INFO,
        )
        cons.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        cons.keyjar[""] = KC_RSA

        cons.client_secret = "drickyoughurt"
        state, location = cons.begin(
            "openid", "token", path=TestConfiguration.get_instance().rp_base)

        resp = self.provider.authorization_endpoint(
            request=urlparse(location).query)

        # redirect
        atr = AuthorizationResponse().deserialize(
            urlparse(resp.message).fragment, "urlencoded")

        uir = UserInfoRequest(access_token=atr["access_token"],
                              schema="openid")
        resp = self.provider.userinfo_endpoint(request=uir.to_urlencoded())
        responses.add(responses.POST,
                      self.op_base + "userinfo",
                      body=resp.message,
                      status=200,
                      content_type='application/json')
示例#8
0
def test_server_authenticated():
    server = provider_init
    _session_db = {}
    cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG,
                    server_info=SERVER_INFO, )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    environ = BASE_ENVIRON

    location = cons.begin(environ, start_response)

    environ = BASE_ENVIRON.copy()
    environ["QUERY_STRING"] = location.split("?")[1]

    resp = server.authorization_endpoint(environ, start_response)

    sid = resp[0][len("<form>"):-len("</form>")]
    environ2 = create_return_form_env("user", "password", sid)

    resp2 = server.authenticated(environ2, start_response)

    print resp2[0]
    assert len(resp2) == 1
    txt = resp2[0]
    pos0 = txt.index("<title>") + len("<title>Redirecting to ")
    pos1 = txt.index("</title>")
    location = txt[pos0:pos1]
    print location

    assert location.startswith("http://localhost:8087/authz")

    environ = BASE_ENVIRON.copy()
    environ["QUERY_STRING"] = location

    part = cons.parse_authz(environ, start_response)
    
    aresp = part[0]
    assert part[1] is None
    assert part[2] is None

    #aresp = client.parse_response(AuthorizationResponse, location,
    #                              format="urlencoded",
    #                              state="id-6da9ca0cc23959f5f33e8becd9b08cae")

    print aresp.keys()
    assert aresp.type() == "AuthorizationResponse"
    assert _eq(aresp.keys(), ['code', 'state', 'scope'])

    print cons.grant[cons.state].keys()
    assert _eq(cons.grant[cons.state].keys(), ['code', 'id_token', 'tokens',
                                               'exp_in',
                                               'grant_expiration_time', 'seed'])
示例#9
0
def register(environ, start_response, logger, kaka=None):
    """
    Initialize the OAuth2 flow
    """
    _session_db = environ["oic.session_db"]
    _cc = environ["oic.client_config"]
    _conc = environ["oic.consumer.config"]
    _server_info = environ["oic.server.info"]

    # get the redirect to the authorization server endpoint
    _oac = Consumer(_session_db, _conc, _cc, _server_info)
    location = _oac.begin(environ, start_response, logger)

    logger.info("[1] %s" % (_oac.__dict__,))
    resp = http_util.Redirect(location)
    return resp(environ, start_response)
示例#10
0
def test_server_authenticated_2():
    server = provider_init
    server.baseurl = server.name
    _session_db = {}
    cons = Consumer(
        _session_db,
        CONSUMER_CONFIG,
        CLIENT_CONFIG,
        server_info=SERVER_INFO,
    )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    _state, location = cons.begin(scope="openid email claims_in_id_token",
                                  response_type="code id_token",
                                  path="http://localhost:8087")

    print location
    resp = server.authorization_endpoint(request=location.split("?")[1])

    print resp.message

    part = cons.parse_authz(resp.message)

    print part
    aresp = part[0]
    assert part[1] is None
    assert part[2] is not None

    #aresp = cons.parse_response(AuthorizationResponse, location,
    #                            sformat="urlencoded")

    print aresp.keys()
    assert aresp.type() == "AuthorizationResponse"
    assert _eq(aresp.keys(), ['scope', 'state', 'code', 'id_token'])

    print cons.grant[_state].keys()
    assert _eq(cons.grant[_state].keys(), [
        'code', 'id_token', 'tokens', 'exp_in', 'grant_expiration_time', 'seed'
    ])
    id_token = part[2]
    assert isinstance(id_token, IdToken)
    print id_token.keys()
    assert _eq(id_token.keys(), [
        'nonce', 'c_hash', 'sub', 'iss', 'acr', 'exp', 'auth_time', 'iat',
        'aud'
    ])
示例#11
0
def test_sign_userinfo():
    consumer = Consumer(SessionDB(SERVER_INFO["issuer"]), CONFIG,
                        CLIENT_CONFIG, SERVER_INFO)
    consumer.keyjar = CLIKEYS

    mfos = MyFakeOICServer("http://localhost:8088")
    mfos.keyjar = SRVKEYS
    mfos.userinfo_signed_response_alg = "RS256"

    consumer.http_request = mfos.http_request
    consumer.redirect_uris = ["http://example.com/authz"]
    _state = "state0"
    consumer.nonce = rndstr()
    consumer.secret_type = "basic"
    consumer.set_client_secret("hemligt")
    consumer.keyjar = CLIKEYS
    consumer.client_prefs = {"userinfo_signed_response_alg": "RS256"}
    consumer.provider_info = {
        "userinfo_endpoint": "http://localhost:8088/userinfo",
        "issuer": "http://localhost:8088/"
    }
    del consumer.config["request_method"]

    args = {
        "client_id": consumer.client_id,
        "response_type": "code",
        "scope": ["openid"],
    }

    sid, location = consumer.begin("openid", "code")
    print location

    result = consumer.do_authorization_request(state=_state, request_args=args)
    assert result.status_code == 302
    assert result.headers["location"].startswith(consumer.redirect_uris[0])
    _, query = result.headers["location"].split("?")

    consumer.parse_response(AuthorizationResponse,
                            info=query,
                            sformat="urlencoded")

    consumer.complete(_state)

    result = consumer.get_user_info(_state)
    print result
    assert result.type() == "OpenIDSchema"
    assert _eq(result.keys(), ['name', 'email', 'verified', 'nickname', 'sub'])
示例#12
0
def test_sign_userinfo():
    consumer = Consumer(SessionDB(SERVER_INFO["issuer"]), CONFIG,
                        CLIENT_CONFIG, SERVER_INFO)
    consumer.keyjar = CLIKEYS

    mfos = MyFakeOICServer("http://localhost:8088")
    mfos.keyjar = SRVKEYS
    mfos.userinfo_signed_response_alg = "RS256"

    consumer.http_request = mfos.http_request
    consumer.redirect_uris = ["http://example.com/authz"]
    _state = "state0"
    consumer.nonce = rndstr()
    consumer.secret_type = "basic"
    consumer.set_client_secret("hemligt")
    consumer.keyjar = CLIKEYS
    consumer.client_prefs = {"userinfo_signed_response_alg": "RS256"}
    consumer.provider_info = {
        "userinfo_endpoint": "http://localhost:8088/userinfo",
        "issuer": "http://localhost:8088/"}
    del consumer.config["request_method"]

    args = {
        "client_id": consumer.client_id,
        "response_type": "code",
        "scope": ["openid"],
    }

    sid, location = consumer.begin("openid", "code")
    print location

    result = consumer.do_authorization_request(state=_state,
                                               request_args=args)
    assert result.status_code == 302
    assert result.headers["location"].startswith(consumer.redirect_uris[0])
    _, query = result.headers["location"].split("?")

    consumer.parse_response(AuthorizationResponse, info=query,
                            sformat="urlencoded")

    consumer.complete(_state)

    result = consumer.get_user_info(_state)
    print result
    assert result.type() == "OpenIDSchema"
    assert _eq(result.keys(), ['name', 'email', 'verified', 'nickname', 'sub'])
示例#13
0
def test_server_authenticated_none():
    server = provider_init
    _session_db = {}
    cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG,
                    server_info=SERVER_INFO, )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    location = cons.begin("openid", response_type="none",
                          path="http://localhost:8087")

    resp = server.authorization_endpoint(request=location.split("?")[1])

    assert resp.message.startswith("http://localhost:8087/authz")
    query_part = resp.message.split("?")[1]
    print query_part
    assert "state" in query_part
示例#14
0
def test_server_authenticated_token():
    server = provider_init

    _session_db = {}
    cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG,
                    server_info=SERVER_INFO, )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    location = cons.begin("openid", response_type="token",
                          path="http://localhost:8087")

    resp = server.authorization_endpoint(request=location.split("?")[1])

    txt = resp.message
    assert "access_token=" in txt
    assert "token_type=Bearer" in txt
示例#15
0
def test_server_authenticated():
    server = provider_init
    _session_db = {}
    cons = Consumer(
        _session_db,
        CONSUMER_CONFIG,
        CLIENT_CONFIG,
        server_info=SERVER_INFO,
    )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    _state, location = cons.begin("openid",
                                  "code",
                                  path="http://localhost:8087")

    QUERY_STRING = location.split("?")[1]
    print QUERY_STRING
    resp = server.authorization_endpoint(request=QUERY_STRING)

    print resp.message

    assert resp.message.startswith("http://localhost:8087/authz")

    part = cons.parse_authz(query=location)

    aresp = part[0]
    assert part[1] is None
    assert part[2] is None

    #aresp = client.parse_response(AuthorizationResponse, location,
    #                              format="urlencoded",
    #                              state="id-6da9ca0cc23959f5f33e8becd9b08cae")

    print aresp.keys()
    assert aresp.type() == "AuthorizationResponse"
    assert _eq(aresp.keys(), [
        'request', 'state', 'redirect_uri', 'response_type', 'client_id',
        'claims', 'scope'
    ])

    print cons.grant[_state].keys()
    assert _eq(cons.grant[_state].keys(), [
        'code', 'tokens', 'id_token', 'exp_in', 'seed', 'grant_expiration_time'
    ])
示例#16
0
def test_userinfo_endpoint():
    server = provider_init

    _session_db = {}
    cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG,
                    server_info=SERVER_INFO)
    cons.debug = True
    cons.client_secret = "drickyoughurt"
    cons.config["response_type"] = ["token"]
    cons.config["request_method"] = "parameter"
    cons.keyjar[""] = KC_RSA

    environ = BASE_ENVIRON

    location = cons.begin(environ, start_response)

    environ = BASE_ENVIRON.copy()
    environ["QUERY_STRING"] = location.split("?")[1]

    resp = server.authorization_endpoint(environ, start_response)

    sid = resp[0][len("<form>"):-len("</form>")]
    environ2 = create_return_form_env("user", "password", sid)

    resp2 = server.authenticated(environ2, start_response)
    line = resp2[0]
    start = line.index("<title>")
    start += len("<title>Redirecting to ")
    stop = line.index("</title>")
    path, query = line[start:stop].split("?")

    # redirect
    atr = AuthorizationResponse().deserialize(query, "urlencoded")

    uir = UserInfoRequest(access_token=atr["access_token"], schema="openid")

    environ = BASE_ENVIRON.copy()
    environ["QUERY_STRING"] = uir.to_urlencoded()

    resp3 = server.userinfo_endpoint(environ, start_response)
    ident = OpenIDSchema().deserialize(resp3[0], "json")
    print ident.keys()
    assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email'])
    assert ident["sub"] == USERDB["user"]["sub"]
示例#17
0
def test_server_authenticated_1():
    server = provider_init
    _session_db = {}
    cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG,
                    server_info=SERVER_INFO, )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    location = cons.begin("openid", "code", path="http://localhost:8087")

    resp = server.authorization_endpoint(request=location.split("?")[1])

    print resp
    aresp = cons.parse_response(AuthorizationResponse, location,
                                sformat="urlencoded")

    print aresp.keys()
    assert aresp.type() == "AuthorizationResponse"
    assert _eq(aresp.keys(), ['request', 'state', 'redirect_uri', 'claims',
                              'response_type', 'client_id', 'scope'])
示例#18
0
def test_server_authenticated_2():
    server = provider_init
    server.baseurl = server.name
    _session_db = {}
    cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG,
                    server_info=SERVER_INFO, )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    location = cons.begin(scope="openid email claims_in_id_token",
                          response_type="code id_token",
                          path="http://localhost:8087")

    print location
    resp = server.authorization_endpoint(request=location.split("?")[1])

    print resp.message

    part = cons.parse_authz(resp.message)

    print part
    aresp = part[0]
    assert part[1] is None
    assert part[2] is not None

    #aresp = cons.parse_response(AuthorizationResponse, location,
    #                            sformat="urlencoded")

    print aresp.keys()
    assert aresp.type() == "AuthorizationResponse"
    assert _eq(aresp.keys(), ['scope', 'state', 'code', 'id_token'])

    print cons.grant[cons.state].keys()
    assert _eq(cons.grant[cons.state].keys(), ['code', 'id_token', 'tokens',
                                               'exp_in',
                                               'grant_expiration_time', 'seed'])
    id_token = part[2]
    assert isinstance(id_token, IdToken)
    print id_token.keys()
    assert _eq(id_token.keys(), ['c_hash', 'sub', 'iss', 'acr', 'exp', 'iat',
                                 'aud', 'nonce'])
示例#19
0
def test_server_authenticated_token():
    server = provider_init

    _session_db = {}
    cons = Consumer(
        _session_db,
        CONSUMER_CONFIG,
        CLIENT_CONFIG,
        server_info=SERVER_INFO,
    )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    _state, location = cons.begin("openid",
                                  response_type="token",
                                  path="http://localhost:8087")

    resp = server.authorization_endpoint(request=location.split("?")[1])

    txt = resp.message
    assert "access_token=" in txt
    assert "token_type=Bearer" in txt
示例#20
0
def test_server_authenticated_none():
    server = provider_init
    _session_db = {}
    cons = Consumer(
        _session_db,
        CONSUMER_CONFIG,
        CLIENT_CONFIG,
        server_info=SERVER_INFO,
    )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    _state, location = cons.begin("openid",
                                  response_type="none",
                                  path="http://localhost:8087")

    resp = server.authorization_endpoint(request=location.split("?")[1])

    assert resp.message.startswith("http://localhost:8087/authz")
    query_part = resp.message.split("?")[1]
    print query_part
    assert "state" in query_part
示例#21
0
def test_server_authenticated_1():
    server = provider_init
    _session_db = {}
    cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG,
                    server_info=SERVER_INFO, )
    cons.debug = True
    cons.keyjar[""] = KC_RSA
    environ = BASE_ENVIRON

    location = cons.begin(environ, start_response)

    environ = BASE_ENVIRON.copy()
    environ["QUERY_STRING"] = location.split("?")[1]

    _ = server.authorization_endpoint(environ, start_response)

    #sid = resp[0][len("FORM with "):]
    environ2 = create_return_form_env("user", "password", "abcd")

    resp2 = server.authenticated(environ2, start_response)
    print resp2
    assert resp2 == ['<html>Could not find session</html>']
示例#22
0
def test_server_authenticated():
    server = provider_init
    _session_db = {}
    cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG,
                    server_info=SERVER_INFO, )
    cons.debug = True
    cons.keyjar[""] = KC_RSA

    location = cons.begin("openid", "code", path="http://localhost:8087")

    QUERY_STRING = location.split("?")[1]
    print QUERY_STRING
    resp = server.authorization_endpoint(request=QUERY_STRING)

    print resp.message

    assert resp.message.startswith("http://localhost:8087/authz")

    part = cons.parse_authz(query=location)
    
    aresp = part[0]
    assert part[1] is None
    assert part[2] is None

    #aresp = client.parse_response(AuthorizationResponse, location,
    #                              format="urlencoded",
    #                              state="id-6da9ca0cc23959f5f33e8becd9b08cae")

    print aresp.keys()
    assert aresp.type() == "AuthorizationResponse"
    assert _eq(aresp.keys(), ['request', 'state', 'redirect_uri',
                              'response_type', 'client_id', 'claims', 'scope'])

    print cons.grant[cons.state].keys()
    assert _eq(cons.grant[cons.state].keys(), ['tokens', 'id_token', 'exp_in',
                                               'seed', 'grant_expiration_time'])
示例#23
0
def register(environ, start_response):
    _oac = Consumer(SESSION_DB, CONSUMER_CONFIG, CLIENT_CONFIG, SERVER_INFO)
    location = _oac.begin(environ, start_response, DEVNULL())
    resp = http_util.Redirect(location)
    return resp(environ, start_response)
示例#24
0
class TestProvider(object):
    CDB = {
        "number5": {
            "password":
            "******",
            "client_secret":
            "drickyoughurt",
            "redirect_uris": [("http://localhost:8087/authz", None)],
            "post_logout_redirect_uris":
            [("https://example.com/post_logout", None)],
            "client_salt":
            "salted",
            "response_types": [
                "code",
                "token",
                "code id_token",
                "none",
                "code token",
                "id_token",
            ],
        },
        "a1b2c3": {
            "redirect_uris": [("http://localhost:8088/authz", None)],
            "client_salt": "salted",
            "client_secret": "very_secret",
            "response_types": ["code", "token", "code id_token"],
        },
        "client0": {
            "redirect_uris": [("http://www.example.org/authz", None)],
            "client_secret":
            "very_secret",
            "post_logout_redirect_uris":
            [("https://www.example.org/post_logout", None)],
            "client_salt":
            "salted",
            "response_types": ["code", "token", "code id_token"],
        },
        CLIENT_ID: {
            "client_secret": CLIENT_SECRET,
            "redirect_uris": [("http://localhost:8087/authz", None)],
            "client_salt": "salted",
            "token_endpoint_auth_method": "client_secret_post",
            "response_types": ["code", "token", "code id_token"],
        },
    }  # type: Dict[str, Dict[str, Any]]

    @pytest.fixture(autouse=True)
    def create_provider(self, session_db_factory):
        self.provider = Provider(
            SERVER_INFO["issuer"],
            session_db_factory(SERVER_INFO["issuer"]),
            self.CDB,
            AUTHN_BROKER,
            USERINFO,
            AUTHZ,
            verify_client,
            SYMKEY,
            urlmap=URLMAP,
            keyjar=KEYJAR,
        )
        self.provider.baseurl = self.provider.name
        self.provider.logout_verify_url = "https://127.0.0.1/logout_verify.html"

        self.cons = Consumer(
            DictSessionBackend(),
            CONSUMER_CONFIG.copy(),
            CLIENT_CONFIG,
            server_info=SERVER_INFO,
        )
        self.cons.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        self.cons.keyjar[""] = KC_RSA
        self.cons.keyjar.import_jwks(self.provider.keyjar.export_jwks(),
                                     self.cons.issuer)

        self.cons2 = Consumer({},
                              CONSUMER_CONFIG.copy(),
                              CLIENT_CONFIG_2,
                              server_info=SERVER_INFO)
        self.cons2.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        self.cons2.keyjar[""] = KC_RSA

    def _code_auth(self):
        state, location = self.cons.begin("openid",
                                          "code",
                                          path="http://localhost:8087")
        return self.provider.authorization_endpoint(
            request=location.split("?")[1])

    def _code_auth2(self):
        state, location = self.cons2.begin("openid",
                                           "code",
                                           path="http://www.example.org")
        return self.provider.authorization_endpoint(
            request=location.split("?")[1])

    def _auth_with_id_token(self):
        state, location = self.cons.begin("openid",
                                          "id_token",
                                          path="http://localhost:8087")
        resp = self.provider.authorization_endpoint(
            request=location.split("?")[1])
        aresp = self.cons.parse_response(AuthorizationResponse,
                                         resp.message,
                                         sformat="urlencoded")
        return aresp["id_token"]

    def _create_cookie(self, user, client_id, c_type="sso"):
        cd = CookieDealer(self.provider)
        set_cookie = cd.create_cookie("{}][{}".format(user, client_id), c_type,
                                      self.provider.sso_cookie_name)
        cookies_string = set_cookie[1]
        all_cookies = SimpleCookie()  # type: SimpleCookie

        try:
            cookies_string = cookies_string.decode()
        except (AttributeError, UnicodeDecodeError):
            pass

        all_cookies.load(cookies_string)

        return all_cookies

    def test_missing_post_logout_redirect_uri(self):
        esr = EndSessionRequest(state="foo")
        assert self.provider.verify_post_logout_redirect_uri(esr,
                                                             CLIENT_ID) is None

    def test_wrong_post_logout_redirect_uri(self):
        self.provider.cdb[CLIENT_ID]["post_logout_redirect_uris"] = [
            "https://example.com/plru"
        ]
        esr = EndSessionRequest(
            state="foo",
            post_logout_redirect_uri="https://localhost:8087/plru")
        assert self.provider.verify_post_logout_redirect_uri(esr,
                                                             CLIENT_ID) is None

    def test_no_post_logout_redirect_uri(self):
        self.provider.cdb[CLIENT_ID]["post_logout_redirect_uris"] = [
            "https://example.com/plru",
            "https://example.com/plru2",
        ]
        esr = EndSessionRequest(state="foo")

        assert self.provider.verify_post_logout_redirect_uri(esr,
                                                             CLIENT_ID) is None

    def test_let_user_verify_logout(self):
        self.provider.cdb[CLIENT_ID]["post_logout_redirect_uris"] = [
            "https://localhost:8087/plru"
        ]
        esr = EndSessionRequest(
            state="foo",
            post_logout_redirect_uri="https://localhost:8087/plru")
        res = self.provider.let_user_verify_logout("user", esr, None, None)
        assert isinstance(res, Response)
        assert res.headers == [("Content-type", "text/html")]
        assert res.status_code == 200

    def test_let_user_verify_logout_with_cookie(self):
        self.provider.cdb[CLIENT_ID]["post_logout_redirect_uris"] = [
            "https://localhost:8087/plru"
        ]
        esr = EndSessionRequest(
            state="foo",
            post_logout_redirect_uri="https://localhost:8087/plru")
        res = self.provider.let_user_verify_logout("user", esr,
                                                   [("Set-Cookie", "kaka")],
                                                   None)
        assert isinstance(res, Response)
        assert set(res.headers) == {
            ("Content-type", "text/html"),
            ("Set-Cookie", "kaka"),
        }
        assert res.status_code == 200

    def test_let_user_verify_logout_with_redirect(self):
        self.provider.cdb[CLIENT_ID]["post_logout_redirect_uris"] = [
            "https://localhost:8087/plru"
        ]
        esr = EndSessionRequest(
            state="foo",
            post_logout_redirect_uri="https://localhost:8087/plru")
        res = self.provider.let_user_verify_logout(
            "user", esr, None, "https://example.com/redirect")
        assert isinstance(res, Response)
        assert set(res.headers) == {("Content-type", "text/html")}
        assert res.status_code == 200
        # make sure the redirect was propagated
        txt = '<input type="hidden" name="{}" value="{}"/>'.format(
            "post_logout_redirect_uri", "https://localhost:8087/plru")
        assert txt in res.message

    def test_let_user_verify_logout_with_id_token_hint(self):
        self.provider.cdb[CLIENT_ID]["post_logout_redirect_uris"] = [
            "https://localhost:8087/plru"
        ]

        esr = EndSessionRequest(
            state="foo",
            post_logout_redirect_uri="https://localhost:8087/plru",
            id_token_hint="J.W.S",
        )
        res = self.provider.let_user_verify_logout("user", esr, None, None)
        assert isinstance(res, Response)
        assert set(res.headers) == {("Content-type", "text/html")}
        assert res.status_code == 200
        # make sure the id_token_hint was propagated
        txt = '<input type="hidden" name="{}" value="{}"/>'.format(
            "id_token_hint", "J.W.S")
        assert txt in res.message

    def test_end_session_endpoint_with_cookie(self):
        self.provider.events = DummyEventStore()

        self._code_auth()
        cookie = self._create_cookie("username", "number5")

        resp = self.provider.end_session_endpoint(urlencode({"state":
                                                             "abcde"}),
                                                  cookie=cookie)

        # returns a SeeOther instance
        p = urlparse(resp.message)
        qs = parse_qs(p.query)

        jwt_info = self.provider.unpack_signed_jwt(qs["sjwt"][0])

        assert jwt_info["state"] == "abcde"
        assert jwt_info["uid"] == "username"
        assert jwt_info["client_id"] == "number5"
        assert jwt_info["redirect_uri"] == "https://example.com/post_logout"

    def test_end_session_endpoint_with_wrong_cookie(self):
        # Need cookie and ID Token to figure this out
        id_token = self._auth_with_id_token()
        assert session_get(self.provider.sdb, "sub",
                           id_token["sub"])  # verify we got valid session

        id_token_hint = id_token.to_jwt(algorithm="none")
        cookie = self._create_cookie("diggins", "number5")

        resp = self.provider.end_session_endpoint(urlencode(
            {"id_token_hint": id_token_hint}),
                                                  cookie=cookie)

        assert isinstance(resp, Response)
        _err = ErrorResponse().from_json(resp.message)
        assert _err["error"] == "invalid_request"
        assert _err["error_description"] == "Wrong user"

    def test_end_session_endpoint_with_cookie_wrong_user(self):
        # Need cookie and ID Token to figure this out
        id_token = self._auth_with_id_token()
        assert session_get(self.provider.sdb, "sub", id_token["sub"])

        id_token_hint = id_token.to_jwt(algorithm="none")
        cookie = self._create_cookie("diggins", "number5")

        resp = self.provider.end_session_endpoint(urlencode(
            {"id_token_hint": id_token_hint}),
                                                  cookie=cookie)

        assert isinstance(resp, Response)
        _err = ErrorResponse().from_json(resp.message)
        assert _err["error"] == "invalid_request"
        assert _err["error_description"] == "Wrong user"

    def test_end_session_endpoint_with_cookie_wrong_client(self):
        # Need cookie and ID Token to figure this out
        id_token = self._auth_with_id_token()
        assert session_get(self.provider.sdb, "sub", id_token["sub"])

        id_token_hint = id_token.to_jwt(algorithm="none")
        # Wrong client_id
        cookie = self._create_cookie("username", "a1b2c3")

        resp = self.provider.end_session_endpoint(urlencode(
            {"id_token_hint": id_token_hint}),
                                                  cookie=cookie)

        assert isinstance(resp, Response)
        _err = ErrorResponse().from_json(resp.message)
        assert _err["error"] == "invalid_request"

    def test_end_session_endpoint_with_cookie_dual_login(self):
        self._code_auth()
        self._code_auth2()
        cookie = self._create_cookie("username", "client0")

        resp = self.provider.end_session_endpoint(urlencode({"state":
                                                             "abcde"}),
                                                  cookie=cookie)

        # returns a SeeOther instance
        p = urlparse(resp.message)
        qs = parse_qs(p.query)

        jwt_info = self.provider.unpack_signed_jwt(qs["sjwt"][0])

        assert jwt_info["state"] == "abcde"
        assert jwt_info["uid"] == "username"
        assert jwt_info["client_id"] == "client0"
        assert jwt_info[
            "redirect_uri"] == "https://www.example.org/post_logout"

    def test_end_session_endpoint_with_cookie_dual_login_wrong_client(self):
        self._code_auth()
        self._code_auth2()
        # The cookie states that a user has a session at a client and this
        # statement is false.
        cookie = self._create_cookie("username", "a1b2c3")

        resp = self.provider.end_session_endpoint(urlencode({"state":
                                                             "abcde"}),
                                                  cookie=cookie)

        assert isinstance(resp, Response)
        _err = ErrorResponse().from_json(resp.message)
        assert _err["error"] == "invalid_request"

    def test_end_session_endpoint_with_id_token_hint_only(self):
        id_token = self._auth_with_id_token()
        assert session_get(self.provider.sdb, "sub", id_token["sub"])

        id_token_hint = id_token.to_jwt(algorithm="none")

        resp = self.provider.end_session_endpoint(
            urlencode({"id_token_hint": id_token_hint}))

        # returns a SeeOther instance
        p = urlparse(resp.message)
        qs = parse_qs(p.query)

        jwt_info = self.provider.unpack_signed_jwt(qs["sjwt"][0])

        assert jwt_info["uid"] == "username"
        assert jwt_info["client_id"] == "number5"
        assert jwt_info["redirect_uri"] == "https://example.com/post_logout"

    def test_end_session_endpoint_with_id_token_hint_and_cookie(self):
        id_token = self._auth_with_id_token()
        assert session_get(self.provider.sdb, "sub", id_token["sub"])

        id_token_hint = id_token.to_jwt(algorithm="none")
        cookie = self._create_cookie("username", "number5")

        resp = self.provider.end_session_endpoint(urlencode(
            {"id_token_hint": id_token_hint}),
                                                  cookie=cookie)

        # returns a SeeOther instance
        p = urlparse(resp.message)
        qs = parse_qs(p.query)

        jwt_info = self.provider.unpack_signed_jwt(qs["sjwt"][0])

        assert jwt_info["uid"] == "username"
        assert jwt_info["client_id"] == "number5"
        assert jwt_info["redirect_uri"] == "https://example.com/post_logout"

    def test_end_session_endpoint_with_post_logout_redirect_uri(self):
        self._code_auth()
        cookie = self._create_cookie("username", "number5")

        post_logout_redirect_uri = self.CDB[str(
            CLIENT_CONFIG["client_id"])]["post_logout_redirect_uris"][0][0]
        resp = self.provider.end_session_endpoint(
            urlencode({
                "post_logout_redirect_uri": post_logout_redirect_uri,
                "state": "abcde"
            }),
            cookie=cookie,
        )

        # returns a SeeOther instance
        p = urlparse(resp.message)
        qs = parse_qs(p.query)

        jwt_info = self.provider.unpack_signed_jwt(qs["sjwt"][0])

        assert jwt_info["state"] == "abcde"
        assert jwt_info["uid"] == "username"
        assert jwt_info["client_id"] == "number5"
        assert jwt_info["redirect_uri"] == "https://example.com/post_logout"

    def test_end_session_endpoint_without_post_logout_redirect_uri(self):
        # default post logout page registered
        self.provider.post_logout_page = "https://foo.example.com/def_post"
        # No post_logout_redirect_uris registered
        _plru = self.provider.cdb["number5"]["post_logout_redirect_uris"]
        del self.provider.cdb["number5"]["post_logout_redirect_uris"]
        self._code_auth()
        cookie = self._create_cookie("username", "number5")

        resp = self.provider.end_session_endpoint(urlencode({"state":
                                                             "abcde"}),
                                                  cookie=cookie)

        # returns a SeeOther instance
        p = urlparse(resp.message)
        qs = parse_qs(p.query)

        jwt_info = self.provider.unpack_signed_jwt(qs["sjwt"][0])
        assert jwt_info["state"] == "abcde"
        assert jwt_info["uid"] == "username"
        assert jwt_info["client_id"] == "number5"
        assert jwt_info["redirect_uri"] == "https://foo.example.com/def_post"

        # restore
        self.provider.cdb["number5"]["post_logout_redirect_uris"] = _plru

    def test_end_session_endpoint_without_post_logout_redirect_uri_no_default(
            self):
        # No post_logout_redirect_uris registered
        _plru = self.provider.cdb["number5"]["post_logout_redirect_uris"]
        del self.provider.cdb["number5"]["post_logout_redirect_uris"]
        self._code_auth()
        cookie = self._create_cookie("username", "number5")

        resp = self.provider.end_session_endpoint(urlencode({"state":
                                                             "abcde"}),
                                                  cookie=cookie)

        assert isinstance(resp, Response)
        _err = ErrorResponse().from_json(resp.message)
        assert _err["error"] == "server_error"
        # restore
        self.provider.cdb["number5"]["post_logout_redirect_uris"] = _plru

    def test_end_session_endpoint_bogus_sjwt(self):
        self._code_auth()
        cookie = self._create_cookie("username", "number5")

        post_logout_redirect_uri = self.CDB[str(
            CLIENT_CONFIG["client_id"])]["post_logout_redirect_uris"][0][0]
        resp = self.provider.end_session_endpoint(
            urlencode({
                "post_logout_redirect_uri": post_logout_redirect_uri,
                "state": "abcde"
            }),
            cookie=cookie,
        )

        # returns a SeeOther instance
        p = urlparse(resp.message)
        qs = parse_qs(p.query)

        _sjwt = qs["sjwt"][0]
        _sjwt = ".".join(_sjwt.split(".")[:2]) + "."  # Not signed
        with pytest.raises(ValueError):
            self.provider.unpack_signed_jwt(_sjwt)

    def test_end_session_endpoint_with_wrong_post_logout_redirect_uri(self):
        self._code_auth()
        cookie = self._create_cookie("username", "number5")

        post_logout_redirect_uri = "https://www.example.com/logout"
        resp = self.provider.end_session_endpoint(
            urlencode({
                "post_logout_redirect_uri": post_logout_redirect_uri,
                "state": "abcde"
            }),
            cookie=cookie,
        )

        assert isinstance(resp, Response)
        _err = ErrorResponse().from_json(resp.message)
        assert _err["error"] == "invalid_request"

    def test_end_session_endpoint_with_registered_post_logout_redirect_uri_with_query_part(
        self, ):
        self._code_auth()
        cookie = self._create_cookie("username", "number5")

        self.provider.cdb["number5"]["post_logout_redirect_uris"] = [
            ("https://www.example.com/logout", {
                "foo": ["bar"]
            })
        ]

        # No post_logout_redirect_uri in request
        resp = self.provider.end_session_endpoint(urlencode({"state":
                                                             "abcde"}),
                                                  cookie=cookie)

        assert isinstance(resp, Response)
        _qp = parse_qs(resp.message.split("?")[1])
        _jwt = self.provider.unpack_signed_jwt(_qp["sjwt"][0])
        assert _jwt["redirect_uri"] == "https://www.example.com/logout?foo=bar"

    def test_back_channel_logout_no_uri(self):
        self._code_auth()

        res = self.provider.do_back_channel_logout(
            self.provider.cdb[CLIENT_ID], "username", "sid")
        assert res is None

    def test_back_channel_logout(self):
        self._code_auth()

        _cdb = copy.copy(self.provider.cdb[CLIENT_ID])
        _cdb["backchannel_logout_uri"] = "https://example.com/bc_logout"
        _cdb["client_id"] = CLIENT_ID
        res = self.provider.do_back_channel_logout(_cdb, "username", "_sid_")
        assert isinstance(res, tuple)
        assert res[0] == "https://example.com/bc_logout"
        _jwt = self.provider.unpack_signed_jwt(res[1])
        assert _jwt
        assert _jwt["iss"] == SERVER_INFO["issuer"]
        assert _jwt["aud"] == [CLIENT_ID]
        assert _jwt["sub"] == "username"
        assert _jwt["sid"] == "_sid_"

    def test_front_channel_logout(self):
        self._code_auth()

        _cdb = copy.copy(self.provider.cdb[CLIENT_ID])
        _cdb["frontchannel_logout_uri"] = "https://example.com/fc_logout"
        _cdb["client_id"] = CLIENT_ID
        res = self.provider.do_front_channel_logout_iframe(
            _cdb, str(SERVER_INFO["issuer"]), "_sid_")
        assert res == '<iframe src="https://example.com/fc_logout">'

    def test_front_channel_logout_session_required(self):
        self._code_auth()

        _cdb = copy.copy(self.provider.cdb[CLIENT_ID])
        _cdb["frontchannel_logout_uri"] = "https://example.com/fc_logout"
        _cdb["frontchannel_logout_session_required"] = True
        _cdb["client_id"] = CLIENT_ID
        res = self.provider.do_front_channel_logout_iframe(
            _cdb, str(SERVER_INFO["issuer"]), "_sid_")
        m = re.match(r'<iframe src="([^"]+)">', str(res))
        assert m
        _q = parse_qs(str(m.group(1)).split("?")[1])
        assert set(_q.keys()) == {"iss", "sid"}

    def test_front_channel_logout_session_required_uri_query(self):
        self._code_auth()

        _cdb = copy.copy(self.provider.cdb[CLIENT_ID])
        _cdb[
            "frontchannel_logout_uri"] = "https://example.com/fc_logout?foo=bar"
        _cdb["frontchannel_logout_session_required"] = True
        _cdb["client_id"] = CLIENT_ID
        res = self.provider.do_front_channel_logout_iframe(
            _cdb, str(SERVER_INFO["issuer"]), "_sid_")
        m = re.match(r'<iframe src="([^"]+)">', str(res))
        assert m
        _q = parse_qs(str(m.group(1)).split("?")[1])
        assert set(_q.keys()) == {"foo", "iss", "sid"}

    def test_front_channel_logout_missing_url(self):
        self._code_auth()

        _cdb = copy.copy(self.provider.cdb[CLIENT_ID])
        _cdb["client_id"] = CLIENT_ID
        res = self.provider.do_front_channel_logout_iframe(
            _cdb, str(SERVER_INFO["issuer"]), "_sid_")
        assert res is None

    def test_logout_from_client_bc(self):
        self._code_auth()
        self.provider.cdb[CLIENT_ID][
            "backchannel_logout_uri"] = "https://example.com/bc_logout"
        self.provider.cdb[CLIENT_ID]["client_id"] = CLIENT_ID
        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]
        res = self.provider.logout_info_for_one_client(_sid, CLIENT_ID)
        assert set(res.keys()) == {"back_channel", "front_channel"}
        assert res["back_channel"] != {}
        assert res["front_channel"] == {}
        assert set(res["back_channel"].keys()) == {CLIENT_ID}
        _spec = res["back_channel"][CLIENT_ID]
        assert _spec[0] == "https://example.com/bc_logout"
        _jwt = self.provider.unpack_signed_jwt(_spec[1])
        assert _jwt
        assert _jwt["iss"] == SERVER_INFO["issuer"]
        assert _jwt["aud"] == [CLIENT_ID]
        assert _jwt["sid"] == _sid

    def test_logout_from_client_fc(self):
        self._code_auth()
        del self.provider.cdb[CLIENT_ID]["backchannel_logout_uri"]
        self.provider.cdb[CLIENT_ID][
            "frontchannel_logout_uri"] = "https://example.com/fc_logout"
        self.provider.cdb[CLIENT_ID]["client_id"] = CLIENT_ID
        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]
        res = self.provider.logout_info_for_one_client(_sid, CLIENT_ID)
        assert set(res.keys()) == {"front_channel", "back_channel"}
        assert res["back_channel"] == {}
        assert set(res["front_channel"].keys()) == {CLIENT_ID}
        _spec = res["front_channel"][CLIENT_ID]
        assert _spec == '<iframe src="https://example.com/fc_logout">'

    def test_logout_from_client(self):
        self._code_auth()
        self._code_auth2()

        # client0
        self.provider.cdb["client0"][
            "backchannel_logout_uri"] = "https://example.com/bc_logout"
        self.provider.cdb["client0"]["client_id"] = "client0"
        self.provider.cdb["number5"][
            "frontchannel_logout_uri"] = "https://example.com/fc_logout"
        self.provider.cdb["number5"]["client_id"] = CLIENT_ID

        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]
        res = self.provider.logout_info_for_all_clients(sid=_sid)
        assert res
        assert set(res.keys()) == {"back_channel", "front_channel"}
        assert set(res["front_channel"].keys()) == {"number5"}
        _spec = res["front_channel"]["number5"]
        assert _spec == '<iframe src="https://example.com/fc_logout">'
        assert set(res["back_channel"].keys()) == {"client0"}
        _spec = res["back_channel"]["client0"]
        assert _spec[0] == "https://example.com/bc_logout"
        _jwt = self.provider.unpack_signed_jwt(_spec[1])
        assert _jwt
        assert _jwt["iss"] == SERVER_INFO["issuer"]
        assert _jwt["aud"] == ["client0"]

    def test_logout_spec_all(self):
        self._code_auth()
        self._code_auth2()

        # client0
        self.provider.cdb["client0"][
            "backchannel_logout_uri"] = "https://example.com/bc_logout"
        self.provider.cdb["client0"]["client_id"] = "client0"
        self.provider.cdb["number5"][
            "frontchannel_logout_uri"] = "https://example.com/fc_logout"
        self.provider.cdb["number5"]["client_id"] = CLIENT_ID

        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]

        logout_spec_all = self.provider.logout_info_for_all_clients(sid=_sid)

        assert set(logout_spec_all.keys()) == {"back_channel", "front_channel"}
        assert set(logout_spec_all["back_channel"].keys()) == {"client0"}
        assert set(logout_spec_all["front_channel"].keys()) == {"number5"}

    def test_do_verified_logout_all(self):
        self._code_auth()
        self._code_auth2()

        # client0
        self.provider.cdb["client0"][
            "backchannel_logout_uri"] = "https://example.com/bc_logout"
        self.provider.cdb["client0"]["client_id"] = "client0"
        self.provider.cdb["number5"][
            "frontchannel_logout_uri"] = "https://example.com/fc_logout"
        self.provider.cdb["number5"]["client_id"] = CLIENT_ID

        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]

        with responses.RequestsMock() as rsps:
            rsps.add(rsps.POST, "https://example.com/bc_logout", status=200)
            res = self.provider.do_verified_logout(_sid, CLIENT_ID, alla=True)

        assert set(res.keys()) == {"iframe", "cookie"}

    def test_do_verified_logout_just_the_one(self):
        self.provider.events = DummyEventStore()

        self._code_auth()
        self._code_auth2()

        # client0
        self.provider.cdb["client0"][
            "backchannel_logout_uri"] = "https://example.com/bc_logout"
        self.provider.cdb["client0"]["client_id"] = "client0"
        self.provider.cdb["number5"][
            "frontchannel_logout_uri"] = "https://example.com/fc_logout"
        self.provider.cdb["number5"]["client_id"] = CLIENT_ID

        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]

        # There is no back channel logout, hence there should be no HTTP POST
        exception = requests.ConnectionError()
        with responses.RequestsMock(
                assert_all_requests_are_fired=False) as rsps:
            rsps.add(responses.POST,
                     "https://example.com/bc_logout",
                     body=exception)
        res = self.provider.do_verified_logout(_sid, CLIENT_ID, alla=False)

        assert set(res.keys()) == {"iframe", "cookie"}

    def test_do_verified_logout_the_other(self):
        self._code_auth()
        self._code_auth2()

        # client0
        self.provider.cdb["client0"][
            "backchannel_logout_uri"] = "https://example.com/bc_logout"
        self.provider.cdb["client0"]["client_id"] = "client0"
        self.provider.cdb["number5"][
            "frontchannel_logout_uri"] = "https://example.com/fc_logout"
        self.provider.cdb["number5"]["client_id"] = CLIENT_ID

        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]

        # This only does back channel logout
        with responses.RequestsMock() as rsps:
            rsps.add(rsps.POST, "https://example.com/bc_logout", status=200)
            res = self.provider.do_verified_logout(_sid, "client0", alla=False)

        assert set(res.keys()) == {"cookie"}

    def test_do_verified_logout_the_other_back_channel_failed(self):
        self._code_auth()
        self._code_auth2()

        # client0
        self.provider.cdb["client0"][
            "backchannel_logout_uri"] = "https://example.com/bc_logout"
        self.provider.cdb["client0"]["client_id"] = "client0"
        self.provider.cdb["number5"][
            "frontchannel_logout_uri"] = "https://example.com/fc_logout"
        self.provider.cdb["number5"]["client_id"] = CLIENT_ID

        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]

        # Does back channel logout and it will fail
        with responses.RequestsMock() as rsps:
            rsps.add(rsps.POST, "https://example.com/bc_logout", status=400)
            res = self.provider.do_verified_logout(_sid, "client0", alla=False)

        assert list(res.keys()) == []

    def test_end_session_endpoint_no_post_logout_redirect_uri(self):
        self._code_auth()
        cookie = self._create_cookie("username", "number5")

        self.provider.cdb["number5"]["post_logout_redirect_uris"] = [
            ("https://example.com/plru", ""),
            ("https://example.com/plru2", ""),
        ]

        res = self.provider.end_session_endpoint(urlencode({"state": "abcde"}),
                                                 cookie=cookie)
        assert isinstance(res, Response)
        assert res.status_code == 400

    def test_logout_info_for_all_clients_no_params(self):
        with pytest.raises(ParameterError):
            self.provider.logout_info_for_all_clients()

    def test_do_back_channel_logout_no_backchannel(self):
        self._code_auth()

        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]
        _sub = self.provider.sdb[_sid]["sub"]
        #
        if "backchannel_logout_uri" in self.provider.cdb["number5"]:
            del self.provider.cdb["number5"]["backchannel_logout_uri"]

        res = self.provider.do_back_channel_logout(
            self.provider.cdb["number5"], _sub, _sid)
        assert res is None

    def test_id_token_hint_multiple_aud(self):
        id_token = self._auth_with_id_token()
        assert session_get(self.provider.sdb, "sub",
                           id_token["sub"])  # verify we got valid session

        self.provider.cdb["number5"]["post_logout_redirect_uris"] = [
            ("https://example.com/plru", "")
        ]

        # add another aud and an azp.
        id_token["azp"] = id_token["aud"][0]
        id_token["aud"].append("foobar")
        id_token_hint = id_token.to_jwt(algorithm="none")

        resp = self.provider.end_session_endpoint(
            urlencode({"id_token_hint": id_token_hint}))

        assert isinstance(resp, SeeOther)

    def test_id_token_hint_aud_does_not_match_client_id(self):
        id_token = self._auth_with_id_token()
        assert session_get(self.provider.sdb, "sub",
                           id_token["sub"])  # verify we got valid session

        # add another aud and an azp.
        id_token_hint = id_token.to_jwt(algorithm="none")

        # Mess with the session DB
        _sid = list(self.provider.sdb._db.storage.keys())[0]
        self.provider.sdb[_sid]["client_id"] = "something else"
        resp = self.provider.end_session_endpoint(
            urlencode({"id_token_hint": id_token_hint}))

        assert isinstance(resp, Response)
        assert resp.status_code == 400

    def test_no_back_or_front_channel_logout(self):
        self._code_auth()

        # Mess with client DB
        for c in ["backchannel_logout_uri", "frontchannel_logout_uri"]:
            if c in self.provider.cdb["number5"]:
                del self.provider.cdb["number5"][c]

        resp = self.provider.do_verified_logout(sid=list(
            self.provider.sdb._db.storage.keys())[0],
                                                client_id="number5")

        assert resp == {}

    def test_back_channel_logout_fails(self):
        self._code_auth()

        # client0
        self.provider.cdb["client0"][
            "backchannel_logout_uri"] = "https://example.com/bc_logout"
        self.provider.cdb["client0"]["client_id"] = "client0"

        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]

        # There is no back channel logout, hence there should be no HTTP POST
        with responses.RequestsMock():
            res = self.provider.do_verified_logout(_sid, "client0", alla=False)

        assert res == {}

    def test_logout_info_for_one_client_no_logout_info(self):
        self._code_auth()

        # Mess with client DB
        for c in ["backchannel_logout_uri", "frontchannel_logout_uri"]:
            if c in self.provider.cdb["number5"]:
                del self.provider.cdb["number5"][c]

        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]
        resp = self.provider.logout_info_for_one_client(_sid, "number5")

        assert resp == {"back_channel": {}, "front_channel": {}}

    def test_unknown_client(self):
        self._code_auth()
        cookie = self._create_cookie("username", "unknown")

        resp = self.provider.end_session_endpoint(urlencode({"state":
                                                             "abcde"}),
                                                  cookie=cookie)

        assert isinstance(resp, Response)
        assert resp.status_code == 400

    def test_no_cookie_no_id_token_hint(self):
        self._code_auth()

        resp = self.provider.end_session_endpoint(urlencode({"state":
                                                             "abcde"}))

        assert isinstance(resp, Response)
        assert resp.status_code == 400

    def test_back_channel_logout_failed_front_channel_logout_exists(self):
        self._code_auth()

        # client0
        self.provider.cdb["number5"][
            "backchannel_logout_uri"] = "https://example.com/bc_logout"
        self.provider.cdb["number5"][
            "frontchannel_logout_uri"] = "https://example.com/fc_logout"
        self.provider.cdb["number5"]["client_id"] = "number5"

        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]

        # Does back channel logout and it will fail
        with responses.RequestsMock() as rsps:
            rsps.add(rsps.POST, "https://example.com/bc_logout", status=400)
            res = self.provider.do_verified_logout(_sid, "client0", alla=True)

        assert set(res.keys()) == {"cookie", "iframe"}

    def test_logout_from_clients_one_without_logout_info(self):
        self._code_auth()
        self._code_auth2()

        # Mess with client DB
        # neither back channel nor front channel
        for c in ["backchannel_logout_uri", "frontchannel_logout_uri"]:
            if c in self.provider.cdb["client0"]:
                del self.provider.cdb["client0"][c]

        self.provider.cdb["client0"]["client_id"] = "client0"

        # both back channel and front channel
        self.provider.cdb["number5"][
            "frontchannel_logout_uri"] = "https://example.com/fc_logout"
        self.provider.cdb["number5"]["client_id"] = "number5"

        # Get a session ID, anyone will do.
        # I know the session backend DB is a DictSessionBackend so I can use that
        _sid = list(self.provider.sdb._db.storage.keys())[0]
        res = self.provider.logout_info_for_all_clients(sid=_sid)
        assert set(res.keys()) == {"back_channel", "front_channel"}
        assert set(res["back_channel"].keys()) == {"number5"}
        assert set(res["front_channel"].keys()) == {"number5"}
示例#25
0
class TestOICConsumer:
    @pytest.fixture(autouse=True)
    def setup_consumer(self, session_db_factory):
        client_id = "client_1"
        client_config = {
            "client_id": client_id,
            "client_authn_method": CLIENT_AUTHN_METHOD,
        }

        self.consumer = Consumer(DictSessionBackend(), CONFIG, client_config,
                                 SERVER_INFO)
        self.consumer.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        self.consumer.keyjar = CLIKEYS
        self.consumer.redirect_uris = ["https://example.com/cb"]
        self.consumer.authorization_endpoint = "https://example.com/authorization"
        self.consumer.token_endpoint = "https://example.com/token"
        self.consumer.userinfo_endpoint = "https://example.com/userinfo"  # type: ignore
        self.consumer.client_secret = "hemlig"
        self.consumer.secret_type = "basic"

    def test_backup_keys(self):
        keys = self.consumer.__dict__.keys()
        _dict = self.consumer.dictionary()
        dkeys = [key for key in keys if key not in _dict.keys()]
        assert _eq(dkeys, IGNORE)

    def test_backup_restore(self):
        authz_org_url = "http://example.org/authorization"

        _dict = sorted(list(self.consumer.__dict__.items()))

        self.consumer._backup("sid")
        self.consumer.restore("sid")
        assert sorted(_dict) == sorted(list(self.consumer.__dict__.items()))

        self.consumer.authorization_endpoint = authz_org_url
        assert _dict != sorted(list(self.consumer.__dict__.items()))

        self.consumer.restore("sid")
        assert _dict == sorted(list(self.consumer.__dict__.items()))

    def test_backup_restore_update(self):
        authz_org_url = "http://example.org/authorization"

        self.consumer._backup("sid")

        self.consumer.authorization_endpoint = authz_org_url
        self.consumer.token_endpoint = "https://example.org/token"
        self.consumer.userinfo_endpoint = ""  # type: ignore

        assert self.consumer.authorization_endpoint == authz_org_url
        assert self.consumer.token_endpoint == "https://example.org/token"
        assert self.consumer.userinfo_endpoint == ""  # type: ignore

        self.consumer.update("sid")

        assert self.consumer.authorization_endpoint == authz_org_url
        assert self.consumer.token_endpoint == "https://example.org/token"
        assert (self.consumer.userinfo_endpoint  # type: ignore
                == "https://example.com/userinfo")

    def test_begin(self):
        srv = Server()
        srv.keyjar = SRVKEYS
        sid, location = self.consumer.begin("openid", "code")
        authreq = srv.parse_authorization_request(url=location)
        assert _eq(
            list(authreq.keys()),
            [
                "state",
                "max_age",
                "claims",
                "response_type",
                "client_id",
                "scope",
                "redirect_uri",
            ],
        )

        assert authreq["state"] == sid
        assert authreq["scope"] == self.consumer.consumer_config["scope"]
        assert authreq["client_id"] == self.consumer.client_id

    def test_begin_file(self, tmpdir):
        path = tmpdir.strpath
        external_path = "/exported"
        self.consumer.consumer_config["request_method"] = "file"
        self.consumer.consumer_config["temp_dir"] = path
        self.consumer.consumer_config["temp_path"] = external_path
        self.consumer.consumer_config["authz_page"] = "/authz"
        srv = Server()
        srv.keyjar = SRVKEYS

        sid, location = self.consumer.begin("openid",
                                            "code",
                                            path="http://*****:*****@example.com",
                    "nickname": "Ilja",
                    "verified": True,
                },
            )

            result = self.consumer.do_authorization_request(state=_state,
                                                            request_args=args)
            parsed = urlparse(result.headers["location"])

            self.consumer.parse_response(AuthorizationResponse,
                                         info=parsed.query,
                                         sformat="urlencoded")

            self.consumer.complete(_state)

            result = self.consumer.get_user_info(_state)
        assert isinstance(result, OpenIDSchema)
        assert _eq(result.keys(),
                   ["name", "email", "verified", "nickname", "sub"])

    def test_sign_userinfo(self):
        _state = "state0"
        self.consumer.client_prefs = {"userinfo_signed_response_alg": "RS256"}
        del self.consumer.consumer_config["request_method"]

        args = {
            "client_id": self.consumer.client_id,
            "response_type": "code",
            "scope": ["openid"],
        }

        location = "https://example.com/cb?code=code&state=state0"
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                "https://example.com/authorization",
                status=302,
                headers={"location": location},
            )
            rsps.add(
                responses.POST,
                "https://example.com/token",
                content_type="application/json",
                json={
                    "access_token": "some_token",
                    "token_type": "bearer",
                    "state": "state0",
                    "scope": "openid",
                },
            )
            rsps.add(
                responses.POST,
                "https://example.com/userinfo",
                content_type="application/json",
                json={
                    "name": "Ilja",
                    "sub": "some_sub",
                    "email": "*****@*****.**",
                    "nickname": "Ilja",
                    "verified": True,
                },
            )
            self.consumer.begin("openid", "code")
            result = self.consumer.do_authorization_request(state=_state,
                                                            request_args=args)
            parsed = urlparse(result.headers["location"])
            self.consumer.parse_response(AuthorizationResponse,
                                         info=parsed.query,
                                         sformat="urlencoded")

            self.consumer.complete(_state)

            result = self.consumer.get_user_info(_state)
        assert isinstance(result, OpenIDSchema)
        assert _eq(result.keys(),
                   ["name", "email", "verified", "nickname", "sub"])

    def test_get_userinfo_claims(self):
        _state = "state0"

        args = {
            "client_id": self.consumer.client_id,
            "response_type": "code",
            "scope": ["openid"],
        }

        location = "https://example.com/cb?code=code&state=state0"
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                "https://example.com/authorization",
                status=302,
                headers={"location": location},
            )
            rsps.add(
                responses.POST,
                "https://example.com/token",
                content_type="application/json",
                json={
                    "access_token": "some_token",
                    "token_type": "bearer",
                    "state": "state0",
                    "scope": "openid",
                },
            )
            rsps.add(
                responses.POST,
                "https://example.com/userinfo",
                content_type="application/json",
                json={
                    "name": "Ilja",
                    "sub": "some_sub",
                    "email": "*****@*****.**",
                    "nickname": "Ilja",
                    "verified": True,
                },
            )

            result = self.consumer.do_authorization_request(state=_state,
                                                            request_args=args)
            parsed = urlparse(result.headers["location"])
            self.consumer.parse_response(AuthorizationResponse,
                                         info=parsed.query,
                                         sformat="urlencoded")
            response = self.consumer.complete(_state)
            result = self.consumer.get_userinfo_claims(
                response["access_token"],
                self.consumer.userinfo_endpoint,  # type: ignore
            )
        assert isinstance(result, OpenIDSchema)
        assert _eq(result.keys(),
                   ["name", "email", "verified", "nickname", "sub"])

    def real_test_discover(self):
        c = Consumer(None, None)
        principal = "*****@*****.**"
        res = c.discover(principal)
        assert isinstance(res, ProviderConfigurationResponse)
        assert _eq(
            res.keys(),
            [
                "registration_endpoint",
                "scopes_supported",
                "identifiers_supported",
                "token_endpoint",
                "flows_supported",
                "version",
                "userinfo_endpoint",
                "authorization_endpoint",
                "x509_url",
                "issuer",
            ],
        )
        assert res.version == "3.0"  # type: ignore
        assert _eq(
            res.flows_supported,  # type: ignore
            [
                "code",
                "token",
                "id_token",
                "code token",
                "code id_token",
                "id_token token",
            ],
        )

    def test_discover(self):
        c = Consumer(None, None)
        webfinger = {
            "subject":
            "acct:[email protected]",
            "links": [{
                "rel": "http://openid.net/specs/connect/1.0/issuer",
                "href": "https://*****:*****@example.com"
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                "https://example.com/.well-known/webfinger"
                "?resource=acct%3Afoo%40example.com&rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer",
                json=webfinger,
            )
            res = c.discover(principal)
        assert res == "https://localhost:8088/"

    def test_client_register(self):
        c = Consumer(None, None)
        c.redirect_uris = ["https://example.com/authz"]
        reg_resp = {
            "client_id": "some_client",
            "client_secret": "super_secret",
            "client_secret_expires_at": 123456789,
            "redirect_uris": ["https://example.com/authz"],
        }
        with responses.RequestsMock() as rsps:
            rsps.add(responses.POST,
                     "https://example.com/register/",
                     json=reg_resp)
            c.register("https://example.com/register/")
            assert json.loads(rsps.calls[0].request.body) == {
                "application_type": "web",
                "response_types": ["code"],
                "redirect_uris": ["https://example.com/authz"],
                "grant_types": ["authorization_code"],
            }
        assert c.client_id == "some_client"
        assert c.client_secret == "super_secret"
        assert c.registration_expires == 123456789

    def test_client_register_token(self):
        c = Consumer(None, None)

        c.redirect_uris = ["https://example.com/authz"]

        client_info = {
            "client_id": "clientid",
            "redirect_uris": ["https://example.com/authz"],
        }

        with responses.RequestsMock() as rsps:
            rsps.add(
                rsps.POST,
                "https://provider.example.com/registration/",
                json=client_info,
            )
            c.register(
                "https://provider.example.com/registration/",
                registration_token="initial_registration_token",
            )
            header = rsps.calls[0].request.headers["Authorization"]
            assert header == "Bearer aW5pdGlhbF9yZWdpc3RyYXRpb25fdG9rZW4="

    def test_client_register_token_b64(self):
        c = Consumer(None, None)

        c.redirect_uris = ["https://example.com/authz"]

        client_info = {
            "client_id": "clientid",
            "redirect_uris": ["https://example.com/authz"],
        }
        registration_token = (
            "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6IC"
            "JlYjc1N2M3Yy00MWRlLTRmZDYtOTkwNy1hNGFiMDY1ZjEzMmEifQ.eyJqdGkiOiI2ZWY0MDZi"
            "MC02YzA3LTQ0NzctOWU1YS1hY2FiZjNiMWNiMjgiLCJleHAiOjAsIm5iZiI6MCwiaWF0Ijox"
            "NTczNzMxNjg5LCJpc3MiOiJodHRwczovL29wZW5pZC1wcm92aWRlci5leGFtcGxlLmNvbS9h"
            "dXRoL3JlYWxtcy9tYXN0ZXIiLCJhdWQiOiJodHRwczovL29wZW5pZC1wcm92aWRlci5leGFt"
            "cGxlLmNvbS9hdXRoL3JlYWxtcy9tYXN0ZXIiLCJ0eXAiOiJJbml0aWFsQWNjZXNzVG9rZW4i"
            "fQ.0XTlit_JcxPZeIy8A4BzrHn1NvegVP7ws8KI0ySFex8")
        with responses.RequestsMock() as rsps:
            rsps.add(
                rsps.POST,
                "https://provider.example.com/registration/",
                json=client_info,
            )
            c.register(
                "https://provider.example.com/registration/",
                registration_token=registration_token,
            )
            header = rsps.calls[0].request.headers["Authorization"]
            assert header == "Bearer " + registration_token

    def _faulty_id_token(self):
        idval = {
            "nonce": "KUEYfRM2VzKDaaKD",
            "sub": "EndUserSubject",
            "iss": "https://alpha.cloud.nds.rub.de",
            "exp": 1420823073,
            "iat": 1420822473,
            "aud": "TestClient",
        }
        idts = IdToken(**idval)

        _signed_jwt = idts.to_jwt(key=[SYMKey(key="TestPassword")],
                                  algorithm="HS256")

        # Mess with the signed id_token
        p = _signed_jwt.split(".")
        p[2] = "aaa"

        return ".".join(p)

    def test_faulty_id_token(self):
        _faulty_signed_jwt = self._faulty_id_token()

        with pytest.raises(BadSignature):
            IdToken().from_jwt(_faulty_signed_jwt,
                               key=[SYMKey(key="TestPassword")])

        # What if no verification key is given ?
        # Should also result in an exception
        with pytest.raises(MissingSigningKey):
            IdToken().from_jwt(_faulty_signed_jwt)

    def test_faulty_id_token_in_access_token_response(self):
        c = Consumer(None, None)
        c.keyjar.add_symmetric("", "TestPassword", ["sig"])

        _info = {
            "access_token": "accessTok",
            "id_token": self._faulty_id_token(),
            "token_type": "Bearer",
        }

        _json = json.dumps(_info)
        with pytest.raises(ValueError):
            c.parse_response(AccessTokenResponse, _json, sformat="json")

    def test_faulty_idtoken_from_accesstoken_endpoint(self):
        _state = "state0"
        self.consumer.consumer_config["response_type"] = ["id_token"]

        args = {
            "client_id": self.consumer.client_id,
            "response_type": self.consumer.consumer_config["response_type"],
            "scope": ["openid"],
        }

        location = (
            "https://example.com/cb?state=state0&id_token=eyJhbGciOiJSUzI1NiJ9"
            ".eyJpc3MiOiAiaHR0cDovL2xvY2FsaG9zdDo4MDg4IiwgInN1YiI6ICJhNWRkMjRiMmYwOGE2ODZmZDM4NmMyMmM"
            "zZmY4ZWUyODFlZjJmYmZmMWZkZTcwMDg2NjhjZGEzZGVjZmE0NjY5IiwgImF1ZCI6IFsiY2xpZW50XzEiXSwgImV"
            "4cCI6IDE1NzIwOTk5NjAsICJhY3IiOiAiMiIsICJpYXQiOiAxNTcyMDEzNTYwLCAibm9uY2UiOiAibmdFTGZVdmN"
            "PMWoyaXNWcXkwQWNwM0NOYlZnMGdFRDEifQ.aaa")
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                "https://example.com/authorization",
                status=302,
                headers={"location": location},
            )
            result = self.consumer.do_authorization_request(state=_state,
                                                            request_args=args)
        self.consumer._backup("state0")

        assert result.status_code == 302
        query = urlparse(result.headers["location"]).query
        with pytest.raises(BadSignature):
            self.consumer.parse_authz(query=query)

    def test_get_session_management_id(self):
        now = utc_time_sans_frac()
        smid = "session_management_id"
        idval = {
            "nonce": "KUEYfRM2VzKDaaKD",
            "sub": "EndUserSubject",
            "iss": "https://example.com",
            "exp": now + 3600,
            "iat": now,
            "aud": self.consumer.client_id,
            "sid": smid,
        }
        idts = IdToken(**idval)

        _signed_jwt = idts.to_jwt(key=KC_RSA.keys(), algorithm="RS256")

        _state = "state"
        self.consumer.sdb[_state] = {
            "redirect_uris": ["https://example.org/cb"]
        }
        resp = AuthorizationResponse(id_token=_signed_jwt, state=_state)
        self.consumer.consumer_config["response_type"] = ["id_token"]
        self.consumer.parse_authz(resp.to_urlencoded())
        assert self.consumer.sso_db["state"]["smid"] == smid
        assert session_get(self.consumer.sso_db, "smid", smid) == [_state]
示例#26
0
class TestOICConsumer():
    @pytest.fixture(autouse=True)
    def setup_consumer(self):
        client_id = "client_1"
        client_config = {
            "client_id": client_id,
            "client_authn_method": CLIENT_AUTHN_METHOD,
            #'config': {}
        }

        self.consumer = Consumer(SessionDB(SERVER_INFO["issuer"]),
                                 CONFIG, client_config, SERVER_INFO)
        self.consumer.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]}
        self.consumer.client_secret = "abcdefghijklmnop"
        self.consumer.keyjar = CLIKEYS
        self.consumer.redirect_uris = ["https://example.com/cb"]
        self.consumer.authorization_endpoint = "http://example.com/authorization"
        self.consumer.token_endpoint = "http://example.com/token"
        self.consumer.userinfo_endpoint = "http://example.com/userinfo"
        self.consumer.client_secret = "hemlig"
        self.consumer.secret_type = "basic"

        mfos = MyFakeOICServer("http://*****:*****@connect-op.heroku.com"
        res = c.discover(principal)
        assert isinstance(res, ProviderConfigurationResponse)
        assert _eq(res.keys(), ['registration_endpoint', 'scopes_supported',
                                'identifiers_supported', 'token_endpoint',
                                'flows_supported', 'version',
                                'userinfo_endpoint',
                                'authorization_endpoint', 'x509_url', 'issuer'])
        assert res.version == "3.0"
        assert _eq(res.flows_supported, ['code', 'token', 'id_token',
                                         'code token', 'code id_token',
                                         'id_token token'])

    def test_discover(self):
        c = Consumer(None, None)
        mfos = MyFakeOICServer("http://*****:*****@example.com"
        res = c.discover(principal)
        assert res == "http://*****:*****@example.com"

        res = c.discover(principal)
        info = c.provider_config(res)
        assert isinstance(info, ProviderConfigurationResponse)
        assert _eq(info.keys(), ['registration_endpoint', 'jwks_uri',
                                 'check_session_endpoint',
                                 'refresh_session_endpoint',
                                 'register_endpoint',
                                 'subject_types_supported',
                                 'token_endpoint_auth_methods_supported',
                                 'id_token_signing_alg_values_supported',
                                 'grant_types_supported', 'user_info_endpoint',
                                 'claims_parameter_supported',
                                 'request_parameter_supported',
                                 'discovery_endpoint', 'issuer',
                                 'authorization_endpoint', 'scopes_supported',
                                 'require_request_uri_registration',
                                 'identifiers_supported', 'token_endpoint',
                                 'request_uri_parameter_supported', 'version',
                                 'response_types_supported',
                                 'end_session_endpoint', 'flows_supported'])

        assert info["end_session_endpoint"] == "http://example.com/end_session"

    def test_client_register(self):
        c = Consumer(None, None)

        c.application_type = "web"
        c.application_name = "My super service"
        c.redirect_uris = ["http://example.com/authz"]
        c.contact = ["*****@*****.**"]

        mfos = MyFakeOICServer("http://example.com")
        mfos.keyjar = SRVKEYS
        c.http_request = mfos.http_request
        location = c.discover("*****@*****.**")
        info = c.provider_config(location)

        c.register(info["registration_endpoint"])
        assert c.client_id is not None
        assert c.client_secret is not None
        assert c.registration_expires > utc_time_sans_frac()

    def _faulty_id_token(self):
        idval = {'nonce': 'KUEYfRM2VzKDaaKD', 'sub': 'EndUserSubject',
                 'iss': 'https://alpha.cloud.nds.rub.de', 'exp': 1420823073,
                 'iat': 1420822473, 'aud': 'TestClient'}
        idts = IdToken(**idval)

        _signed_jwt = idts.to_jwt(key=[SYMKey(key="TestPassword")],
                                  algorithm="HS256")

        # Mess with the signed id_token
        p = _signed_jwt.split(".")
        p[2] = "aaa"

        return ".".join(p)

    def test_faulty_id_token(self):
        _faulty_signed_jwt = self._faulty_id_token()

        with pytest.raises(BadSignature):
            IdToken().from_jwt(_faulty_signed_jwt,
                               key=[SYMKey(key="TestPassword")])

        # What if no verification key is given ?
        # Should also result in an exception
        with pytest.raises(MissingSigningKey):
            _ = IdToken().from_jwt(_faulty_signed_jwt)

    def test_faulty_id_token_in_access_token_response(self):
        c = Consumer(None, None)
        c.keyjar.add_symmetric("", "TestPassword", ["sig"])

        _info = {"access_token": "accessTok",
                 "id_token": self._faulty_id_token(),
                 "token_type": "Bearer"}

        _json = json.dumps(_info)
        with pytest.raises(BadSignature):
            c.parse_response(AccessTokenResponse, _json, sformat="json")

    def test_faulty_idtoken_from_accesstoken_endpoint(self):
        mfos = MITMServer("http://localhost:8088")
        mfos.keyjar = SRVKEYS
        self.consumer.http_request = mfos.http_request
        _state = "state0"
        self.consumer.consumer_config["response_type"] = ["id_token"]

        args = {
            "client_id": self.consumer.client_id,
            "response_type": self.consumer.consumer_config["response_type"],
            "scope": ["openid"],
        }

        result = self.consumer.do_authorization_request(state=_state,
                                                        request_args=args)
        self.consumer._backup("state0")

        assert result.status_code == 302
        query = urlparse(result.headers["location"]).query
        with pytest.raises(BadSignature):
            self.consumer.parse_authz(query=query)
示例#27
0
class TestOICConsumer():
    @pytest.fixture(autouse=True)
    def setup_consumer(self, fake_oic_server, session_db_factory):
        client_id = "client_1"
        client_config = {
            "client_id": client_id,
            "client_authn_method": CLIENT_AUTHN_METHOD,
            # 'config': {}
        }

        self.consumer = Consumer(session_db_factory(SERVER_INFO["issuer"]),
                                 CONFIG, client_config, SERVER_INFO)
        self.consumer.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        self.consumer.client_secret = "abcdefghijklmnop"
        self.consumer.keyjar = CLIKEYS
        self.consumer.redirect_uris = ["https://example.com/cb"]
        self.consumer.authorization_endpoint = \
            "http://example.com/authorization"
        self.consumer.token_endpoint = "http://example.com/token"
        self.consumer.userinfo_endpoint = "http://example.com/userinfo"
        self.consumer.client_secret = "hemlig"
        self.consumer.secret_type = "basic"

        mfos = fake_oic_server("http://*****:*****@connect-op.heroku.com"
        res = c.discover(principal)
        assert isinstance(res, ProviderConfigurationResponse)
        assert _eq(res.keys(), [
            'registration_endpoint', 'scopes_supported',
            'identifiers_supported', 'token_endpoint', 'flows_supported',
            'version', 'userinfo_endpoint', 'authorization_endpoint',
            'x509_url', 'issuer'
        ])
        assert res.version == "3.0"
        assert _eq(res.flows_supported, [
            'code', 'token', 'id_token', 'code token', 'code id_token',
            'id_token token'
        ])

    def test_discover(self, fake_oic_server):
        c = Consumer(None, None)
        mfos = fake_oic_server("https://*****:*****@example.com"
        res = c.discover(principal)
        assert res == "https://*****:*****@example.com"

        res = c.discover(principal)
        info = c.provider_config(res)
        assert isinstance(info, ProviderConfigurationResponse)
        assert _eq(info.keys(), [
            'registration_endpoint', 'jwks_uri', 'check_session_endpoint',
            'refresh_session_endpoint', 'register_endpoint',
            'subject_types_supported', 'token_endpoint_auth_methods_supported',
            'id_token_signing_alg_values_supported', 'grant_types_supported',
            'user_info_endpoint', 'claims_parameter_supported',
            'request_parameter_supported', 'discovery_endpoint', 'issuer',
            'authorization_endpoint', 'scopes_supported',
            'require_request_uri_registration', 'identifiers_supported',
            'token_endpoint', 'request_uri_parameter_supported', 'version',
            'response_types_supported', 'end_session_endpoint',
            'flows_supported'
        ])

        assert info[
            "end_session_endpoint"] == "https://example.com/end_session"

    def test_client_register(self, fake_oic_server):
        c = Consumer(None, None)

        c.application_type = "web"
        c.application_name = "My super service"
        c.redirect_uris = ["https://example.com/authz"]
        c.contact = ["*****@*****.**"]
        mfos = fake_oic_server("https://example.com")
        mfos.keyjar = SRVKEYS
        c.http_request = mfos.http_request
        location = c.discover("*****@*****.**")
        info = c.provider_config(location)

        c.register(info["registration_endpoint"])
        assert c.client_id is not None
        assert c.client_secret is not None
        assert c.registration_expires > utc_time_sans_frac()

    def _faulty_id_token(self):
        idval = {
            'nonce': 'KUEYfRM2VzKDaaKD',
            'sub': 'EndUserSubject',
            'iss': 'https://alpha.cloud.nds.rub.de',
            'exp': 1420823073,
            'iat': 1420822473,
            'aud': 'TestClient'
        }
        idts = IdToken(**idval)

        _signed_jwt = idts.to_jwt(key=[SYMKey(key="TestPassword")],
                                  algorithm="HS256")

        # Mess with the signed id_token
        p = _signed_jwt.split(".")
        p[2] = "aaa"

        return ".".join(p)

    def test_faulty_id_token(self):
        _faulty_signed_jwt = self._faulty_id_token()

        with pytest.raises(BadSignature):
            IdToken().from_jwt(_faulty_signed_jwt,
                               key=[SYMKey(key="TestPassword")])

        # What if no verification key is given ?
        # Should also result in an exception
        with pytest.raises(MissingSigningKey):
            IdToken().from_jwt(_faulty_signed_jwt)

    def test_faulty_id_token_in_access_token_response(self):
        c = Consumer(None, None)
        c.keyjar.add_symmetric("", "TestPassword", ["sig"])

        _info = {
            "access_token": "accessTok",
            "id_token": self._faulty_id_token(),
            "token_type": "Bearer"
        }

        _json = json.dumps(_info)
        with pytest.raises(BadSignature):
            c.parse_response(AccessTokenResponse, _json, sformat="json")

    def test_faulty_idtoken_from_accesstoken_endpoint(self, mitm_server):
        mfos = mitm_server("http://localhost:8088")
        mfos.keyjar = SRVKEYS
        self.consumer.http_request = mfos.http_request
        _state = "state0"
        self.consumer.consumer_config["response_type"] = ["id_token"]

        args = {
            "client_id": self.consumer.client_id,
            "response_type": self.consumer.consumer_config["response_type"],
            "scope": ["openid"],
        }

        result = self.consumer.do_authorization_request(state=_state,
                                                        request_args=args)
        self.consumer._backup("state0")

        assert result.status_code == 302
        query = urlparse(result.headers["location"]).query
        with pytest.raises(BadSignature):
            self.consumer.parse_authz(query=query)
示例#28
0
class TestOICProvider(object):
    def setup_class(self):
        self.server = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), CDB,
                               AUTHN_BROKER, USERINFO,
                               AUTHZ, verify_client, SYMKEY, urlmap=URLMAP,
                               keyjar=KEYJAR)

        self.cons = Consumer({}, CONSUMER_CONFIG, CLIENT_CONFIG,
                               server_info=SERVER_INFO, )
        self.cons.behaviour = {"request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]}
        self.cons.debug = True
        self.cons.keyjar[""] = KC_RSA

    def test_server_init(self):
        assert self.server
        assert self.server.authn_broker == AUTHN_BROKER
        print self.server.urlmap
        assert self.server.urlmap["client_1"] == ["https://example.com/authz"]

    def test_server_authorization_endpoint(self):
        bib = {"scope": ["openid"],
               "state": "id-6da9ca0cc23959f5f33e8becd9b08cae",
               "redirect_uri": "http://*****:*****@example.com"]
        req["response_types"] = ["code"]

        print req.to_dict()

        resp = self.server.registration_endpoint(request=req.to_json())

        print resp.message
        regresp = RegistrationResponse().deserialize(resp.message, "json")
        print regresp.keys()
        assert _eq(regresp.keys(), ['redirect_uris', 'contacts', 'application_type',
                                    'client_name', 'registration_client_uri',
                                    'client_secret_expires_at',
                                    'registration_access_token',
                                    'client_id', 'client_secret',
                                    'client_id_issued_at', 'response_types'])

    def test_provider_key_setup(self):
        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"})

        keys = provider.keyjar.get_signing_key("RSA")
        assert len(keys) == 1
        assert provider.jwks_uri == "http://www.example.com/static/jwks"

    def _client_id(self, cdb):
        cid = None
        for k, item in cdb.items():
            if item in cdb.keys():
                cid = item
                break

        return cid

    def test_registered_redirect_uri_without_query_component(self):
        provider = Provider("FOO", {}, {}, None, None, None, None, "")
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])

        registration_req = rr.to_json()

        provider.registration_endpoint(request=registration_req)

        correct = [
            "http://example.org/cb",
            "http://example.org/cb/foo",
        ]
        faulty = [
            "http://example.org/foo",
            "http://example.com/cb",
            "http://example.org/cb?got=you",
            "http://example.org/cb/foo?got=you"
        ]

        cid = self._client_id(provider.cdb)

        for ruri in faulty:
            areq = AuthorizationRequest(redirect_uri=ruri,
                                        client_id=cid,
                                        response_type="code",
                                        scope="openid")

            print areq
            try:
                provider._verify_redirect_uri(areq)
                assert False
            except RedirectURIError:
                pass

        for ruri in correct:
            areq = AuthorizationRequest(redirect_uri=ruri,
                                        client_id=cid,
                                        response_type="code", scope="openid")

            print areq
            try:
                provider._verify_redirect_uri(areq)
            except RedirectURIError, err:
                print err
                assert False
示例#29
0
class TestOICConsumer:
    @pytest.fixture(autouse=True)
    def setup_consumer(self, session_db_factory):
        client_id = "client_1"
        client_config = {
            "client_id": client_id,
            "client_authn_method": CLIENT_AUTHN_METHOD,
        }

        self.consumer = Consumer(
            session_db_factory(SERVER_INFO["issuer"]),
            CONFIG,
            client_config,
            SERVER_INFO,
        )
        self.consumer.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        self.consumer.keyjar = CLIKEYS
        self.consumer.redirect_uris = ["https://example.com/cb"]
        self.consumer.authorization_endpoint = "https://example.com/authorization"
        self.consumer.token_endpoint = "https://example.com/token"
        self.consumer.userinfo_endpoint = "https://example.com/userinfo"
        self.consumer.client_secret = "hemlig"
        self.consumer.secret_type = "basic"

    def test_backup_keys(self):
        keys = self.consumer.__dict__.keys()
        _dict = self.consumer.dictionary()
        dkeys = [key for key in keys if key not in _dict.keys()]
        assert _eq(dkeys, IGNORE)

    def test_backup_restore(self):
        authz_org_url = "http://example.org/authorization"

        _dict = sorted(list(self.consumer.__dict__.items()))

        self.consumer._backup("sid")
        self.consumer.restore("sid")
        assert sorted(_dict) == sorted(list(self.consumer.__dict__.items()))

        self.consumer.authorization_endpoint = authz_org_url
        assert _dict != sorted(list(self.consumer.__dict__.items()))

        self.consumer.restore("sid")
        assert _dict == sorted(list(self.consumer.__dict__.items()))

    def test_backup_restore_update(self):
        authz_org_url = "http://example.org/authorization"

        self.consumer._backup("sid")

        self.consumer.authorization_endpoint = authz_org_url
        self.consumer.token_endpoint = "https://example.org/token"
        self.consumer.userinfo_endpoint = ""

        assert self.consumer.authorization_endpoint == authz_org_url
        assert self.consumer.token_endpoint == "https://example.org/token"
        assert self.consumer.userinfo_endpoint == ""

        self.consumer.update("sid")

        assert self.consumer.authorization_endpoint == authz_org_url
        assert self.consumer.token_endpoint == "https://example.org/token"
        assert self.consumer.userinfo_endpoint == "https://example.com/userinfo"

    def test_begin(self):
        srv = Server()
        srv.keyjar = SRVKEYS
        sid, location = self.consumer.begin("openid", "code")
        authreq = srv.parse_authorization_request(url=location)
        assert _eq(
            list(authreq.keys()),
            [
                "state",
                "max_age",
                "claims",
                "response_type",
                "client_id",
                "scope",
                "redirect_uri",
            ],
        )

        assert authreq["state"] == sid
        assert authreq["scope"] == self.consumer.consumer_config["scope"]
        assert authreq["client_id"] == self.consumer.client_id

    def test_begin_file(self, tmpdir):
        path = tmpdir.strpath
        external_path = "/exported"
        self.consumer.consumer_config["request_method"] = "file"
        self.consumer.consumer_config["temp_dir"] = path
        self.consumer.consumer_config["temp_path"] = external_path
        self.consumer.consumer_config["authz_page"] = "/authz"
        srv = Server()
        srv.keyjar = SRVKEYS

        sid, location = self.consumer.begin(
            "openid", "code", path="http://*****:*****@example.com",
                    "nickname": "Ilja",
                    "verified": True,
                },
            )

            result = self.consumer.do_authorization_request(
                state=_state, request_args=args
            )
            parsed = urlparse(result.headers["location"])

            self.consumer.parse_response(
                AuthorizationResponse, info=parsed.query, sformat="urlencoded"
            )

            self.consumer.complete(_state)

            result = self.consumer.get_user_info(_state)
        assert isinstance(result, OpenIDSchema)
        assert _eq(result.keys(), ["name", "email", "verified", "nickname", "sub"])

    def test_sign_userinfo(self):
        _state = "state0"
        self.consumer.client_prefs = {"userinfo_signed_response_alg": "RS256"}
        del self.consumer.consumer_config["request_method"]

        args = {
            "client_id": self.consumer.client_id,
            "response_type": "code",
            "scope": ["openid"],
        }

        location = "https://example.com/cb?code=code&state=state0"
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                "https://example.com/authorization",
                status=302,
                headers={"location": location},
            )
            rsps.add(
                responses.POST,
                "https://example.com/token",
                content_type="application/json",
                json={
                    "access_token": "some_token",
                    "token_type": "bearer",
                    "state": "state0",
                    "scope": "openid",
                },
            )
            rsps.add(
                responses.POST,
                "https://example.com/userinfo",
                content_type="application/json",
                json={
                    "name": "Ilja",
                    "sub": "some_sub",
                    "email": "*****@*****.**",
                    "nickname": "Ilja",
                    "verified": True,
                },
            )
            self.consumer.begin("openid", "code")
            result = self.consumer.do_authorization_request(
                state=_state, request_args=args
            )
            parsed = urlparse(result.headers["location"])
            self.consumer.parse_response(
                AuthorizationResponse, info=parsed.query, sformat="urlencoded"
            )

            self.consumer.complete(_state)

            result = self.consumer.get_user_info(_state)
        assert isinstance(result, OpenIDSchema)
        assert _eq(result.keys(), ["name", "email", "verified", "nickname", "sub"])

    def test_get_userinfo_claims(self):
        _state = "state0"

        args = {
            "client_id": self.consumer.client_id,
            "response_type": "code",
            "scope": ["openid"],
        }

        location = "https://example.com/cb?code=code&state=state0"
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                "https://example.com/authorization",
                status=302,
                headers={"location": location},
            )
            rsps.add(
                responses.POST,
                "https://example.com/token",
                content_type="application/json",
                json={
                    "access_token": "some_token",
                    "token_type": "bearer",
                    "state": "state0",
                    "scope": "openid",
                },
            )
            rsps.add(
                responses.POST,
                "https://example.com/userinfo",
                content_type="application/json",
                json={
                    "name": "Ilja",
                    "sub": "some_sub",
                    "email": "*****@*****.**",
                    "nickname": "Ilja",
                    "verified": True,
                },
            )

            result = self.consumer.do_authorization_request(
                state=_state, request_args=args
            )
            parsed = urlparse(result.headers["location"])
            self.consumer.parse_response(
                AuthorizationResponse, info=parsed.query, sformat="urlencoded"
            )
            response = self.consumer.complete(_state)
            result = self.consumer.get_userinfo_claims(
                response["access_token"], self.consumer.userinfo_endpoint
            )
        assert isinstance(result, OpenIDSchema)
        assert _eq(result.keys(), ["name", "email", "verified", "nickname", "sub"])

    def real_test_discover(self):
        c = Consumer(None, None)
        principal = "*****@*****.**"
        res = c.discover(principal)
        assert isinstance(res, ProviderConfigurationResponse)
        assert _eq(
            res.keys(),
            [
                "registration_endpoint",
                "scopes_supported",
                "identifiers_supported",
                "token_endpoint",
                "flows_supported",
                "version",
                "userinfo_endpoint",
                "authorization_endpoint",
                "x509_url",
                "issuer",
            ],
        )
        assert res.version == "3.0"  # type: ignore
        assert _eq(
            res.flows_supported,  # type: ignore
            [
                "code",
                "token",
                "id_token",
                "code token",
                "code id_token",
                "id_token token",
            ],
        )

    def test_discover(self):
        c = Consumer(None, None)
        webfinger = {
            "subject": "acct:[email protected]",
            "links": [
                {
                    "rel": "http://openid.net/specs/connect/1.0/issuer",
                    "href": "https://*****:*****@example.com"
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                "https://example.com/.well-known/webfinger"
                "?resource=acct%3Afoo%40example.com&rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer",
                json=webfinger,
            )
            res = c.discover(principal)
        assert res == "https://localhost:8088/"

    def test_client_register(self):
        c = Consumer(None, None)
        c.redirect_uris = ["https://example.com/authz"]
        reg_resp = {
            "client_id": "some_client",
            "client_secret": "super_secret",
            "client_secret_expires_at": 123456789,
            "redirect_uris": ["https://example.com/authz"],
        }
        with responses.RequestsMock() as rsps:
            rsps.add(responses.POST, "https://example.com/register/", json=reg_resp)
            c.register("https://example.com/register/")
            assert json.loads(rsps.calls[0].request.body) == {
                "application_type": "web",
                "response_types": ["code"],
                "redirect_uris": ["https://example.com/authz"],
                "grant_types": ["authorization_code"],
            }
        assert c.client_id == "some_client"
        assert c.client_secret == "super_secret"
        assert c.registration_expires == 123456789

    def test_client_register_token(self):
        c = Consumer(None, None)

        c.redirect_uris = ["https://example.com/authz"]

        client_info = {
            "client_id": "clientid",
            "redirect_uris": ["https://example.com/authz"],
        }

        with responses.RequestsMock() as rsps:
            rsps.add(
                rsps.POST,
                "https://provider.example.com/registration/",
                json=client_info,
            )
            c.register(
                "https://provider.example.com/registration/",
                registration_token="initial_registration_token",
            )
            header = rsps.calls[0].request.headers["Authorization"]
            assert header == "Bearer aW5pdGlhbF9yZWdpc3RyYXRpb25fdG9rZW4="

    def _faulty_id_token(self):
        idval = {
            "nonce": "KUEYfRM2VzKDaaKD",
            "sub": "EndUserSubject",
            "iss": "https://alpha.cloud.nds.rub.de",
            "exp": 1420823073,
            "iat": 1420822473,
            "aud": "TestClient",
        }
        idts = IdToken(**idval)

        _signed_jwt = idts.to_jwt(key=[SYMKey(key="TestPassword")], algorithm="HS256")

        # Mess with the signed id_token
        p = _signed_jwt.split(".")
        p[2] = "aaa"

        return ".".join(p)

    def test_faulty_id_token(self):
        _faulty_signed_jwt = self._faulty_id_token()

        with pytest.raises(BadSignature):
            IdToken().from_jwt(_faulty_signed_jwt, key=[SYMKey(key="TestPassword")])

        # What if no verification key is given ?
        # Should also result in an exception
        with pytest.raises(MissingSigningKey):
            IdToken().from_jwt(_faulty_signed_jwt)

    def test_faulty_id_token_in_access_token_response(self):
        c = Consumer(None, None)
        c.keyjar.add_symmetric("", "TestPassword", ["sig"])

        _info = {
            "access_token": "accessTok",
            "id_token": self._faulty_id_token(),
            "token_type": "Bearer",
        }

        _json = json.dumps(_info)
        with pytest.raises(ValueError):
            c.parse_response(AccessTokenResponse, _json, sformat="json")

    def test_faulty_idtoken_from_accesstoken_endpoint(self, mitm_server):
        mfos = mitm_server("http://localhost:8088")
        mfos.keyjar = SRVKEYS
        self.consumer.http_request = mfos.http_request
        _state = "state0"
        self.consumer.consumer_config["response_type"] = ["id_token"]

        args = {
            "client_id": self.consumer.client_id,
            "response_type": self.consumer.consumer_config["response_type"],
            "scope": ["openid"],
        }

        result = self.consumer.do_authorization_request(state=_state, request_args=args)
        self.consumer._backup("state0")

        assert result.status_code == 302
        query = urlparse(result.headers["location"]).query
        with pytest.raises(BadSignature):
            self.consumer.parse_authz(query=query)
示例#30
0
class TestOICConsumer():
    def setup_class(self):
        self.consumer = Consumer(SessionDB(SERVER_INFO["issuer"]), CONFIG,
                                 CLIENT_CONFIG, SERVER_INFO)
        self.consumer.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        self.consumer.client_secret = CLIENT_SECRET

    def test_init(self):
        assert self.consumer

    def test_backup_keys(self):
        keys = self.consumer.__dict__.keys()
        print keys
        _dict = self.consumer.dictionary()
        print _dict.keys()
        dkeys = [key for key in keys if key not in _dict.keys()]
        print dkeys
        assert _eq(dkeys, IGNORE)

    def test_backup_restore(self):
        _dict = self.consumer.__dict__.items()

        self.consumer._backup("sid")
        self.consumer.restore("sid")

        assert _dict == self.consumer.__dict__.items()

        self.consumer.authorization_endpoint = AUTHZ_URL

        assert _dict != self.consumer.__dict__.items()

        self.consumer.restore("sid")

        assert _dict == self.consumer.__dict__.items()

    def test_backup_restore_update(self):
        self.consumer.authorization_endpoint = AUTHZ_URL
        self.consumer.token_endpoint = "http://example.com/token"
        self.consumer.userinfo_endpoint = "http://example.com/userinfo"

        self.consumer._backup("sid")

        self.consumer.authorization_endpoint = AUTHZ_ORG_URL
        self.consumer.token_endpoint = "http://example.org/token"
        self.consumer.userinfo_endpoint = ""

        assert self.consumer.authorization_endpoint == AUTHZ_ORG_URL
        assert self.consumer.token_endpoint == "http://example.org/token"
        assert self.consumer.userinfo_endpoint == ""

        self.consumer.update("sid")

        assert self.consumer.authorization_endpoint == AUTHZ_ORG_URL
        assert self.consumer.token_endpoint == "http://example.org/token"
        assert self.consumer.userinfo_endpoint == "http://example.com/userinfo"

    def test_begin(self):
        self.consumer.authorization_endpoint = AUTHZ_URL
        self.consumer.keyjar[""].append(KC_RSA)
        # self.consumer.keyjar.set_sign_key(rsapub, "rsa")
        #self.consumer.keyjar.set_verify_key(rsapub, "rsa")

        srv = Server()
        srv.keyjar = SRVKEYS
        print "redirect_uris", self.consumer.redirect_uris
        print "config", self.consumer.config
        sid, location = self.consumer.begin("openid", "code")
        print location
        authreq = srv.parse_authorization_request(url=location)
        print authreq.keys()
        assert _eq(authreq.keys(), [
            'request', 'state', 'max_age', 'claims', 'response_type',
            'client_id', 'scope', 'redirect_uri'
        ])

        assert authreq["state"] == sid
        assert authreq["scope"] == self.consumer.config["scope"]
        assert authreq["client_id"] == self.consumer.client_id

    def test_begin_file(self):
        tempdir = tempfile.mkdtemp()
        self.consumer.config["request_method"] = "file"
        self.consumer.config["temp_dir"] = tempdir
        self.consumer.config["temp_path"] = tempdir
        self.consumer.config["authz_page"] = "/authz"
        srv = Server()
        srv.keyjar = SRVKEYS

        sid, location = self.consumer.begin("openid",
                                            "code",
                                            path="http://localhost:8087")
        print location
        # vkeys = {".":srv.keyjar.get_verify_key()}
        authreq = srv.parse_authorization_request(url=location)
        print authreq.keys()
        assert _eq(authreq.keys(), [
            'max_age', 'state', 'redirect_uri', 'response_type', 'client_id',
            'scope', 'claims', 'request_uri'
        ])

        assert authreq["state"] == sid
        assert authreq["scope"] == self.consumer.config["scope"]
        assert authreq["client_id"] == self.consumer.client_id
        assert authreq["redirect_uri"].startswith(
            "http://localhost:8087/authz")
        # Cleanup the file we have created
        shutil.rmtree(tempdir)

    def test_complete(self):
        mfos = MyFakeOICServer("http://localhost:8088")
        mfos.keyjar = SRVKEYS

        self.consumer.http_request = mfos.http_request
        _state = "state0"
        self.consumer.nonce = rndstr()
        self.consumer.redirect_uris = ["https://example.com/cb"]
        args = {
            "client_id": self.consumer.client_id,
            "response_type": "code",
            "scope": ["openid"],
        }

        result = self.consumer.do_authorization_request(state=_state,
                                                        request_args=args)
        assert result.status_code == 302
        print "redirect_uris", self.consumer.redirect_uris
        print result.headers["location"]

        assert result.headers["location"].startswith(
            self.consumer.redirect_uris[0])
        _, query = result.headers["location"].split("?")

        # vkeys = {".": self.consumer.keyjar.get_verify_key()}

        self.consumer.parse_response(AuthorizationResponse,
                                     info=query,
                                     sformat="urlencoded")

        resp = self.consumer.complete(_state)
        print resp
        assert resp.type() == "AccessTokenResponse"
        print resp.keys()
        assert _eq(resp.keys(), [
            'token_type', 'state', 'access_token', 'scope', 'expires_in',
            'refresh_token'
        ])

        assert resp["state"] == _state

    def test_parse_authz(self):
        mfos = MyFakeOICServer("http://localhost:8088")
        mfos.keyjar = SRVKEYS

        self.consumer.http_request = mfos.http_request
        _state = "state0"
        self.consumer.nonce = rndstr()
        args = {
            "client_id": self.consumer.client_id,
            "response_type": "code",
            "scope": ["openid"],
        }

        result = self.consumer.do_authorization_request(state=_state,
                                                        request_args=args)

        print self.consumer.sdb["state0"].keys()
        part = self.consumer.parse_authz(query=result.headers["location"])
        print part
        atr = part[0]
        assert part[1] is None
        assert part[2] is None

        assert atr.type() == "AuthorizationResponse"
        assert atr["state"] == _state
        assert "code" in atr

    def test_parse_authz_implicit(self):
        mfos = MyFakeOICServer("http://localhost:8088")
        mfos.keyjar = SRVKEYS

        self.consumer.http_request = mfos.http_request
        self.consumer.config["response_type"] = ["token"]
        _state = "statxxx"
        args = {
            "client_id": self.consumer.client_id,
            "response_type": "implicit",
            "scope": ["openid"],
            "redirect_uri": "http://localhost:8088/cb"
        }

        result = self.consumer.do_authorization_request(state=_state,
                                                        request_args=args)

        part = self.consumer.parse_authz(query=result.headers["location"])
        print part
        assert part[0] is None
        atr = part[1]
        assert part[2] is None

        assert atr.type() == "AccessTokenResponse"
        assert atr["state"] == _state
        assert "access_token" in atr
示例#31
0
class TestProvider(object):
    @pytest.fixture(autouse=True)
    def create_provider(self, session_db_factory):
        self.provider = Provider(SERVER_INFO["issuer"],
                                 session_db_factory(SERVER_INFO["issuer"]),
                                 CDB,
                                 AUTHN_BROKER,
                                 USERINFO,
                                 AUTHZ,
                                 verify_client,
                                 SYMKEY,
                                 urlmap=URLMAP,
                                 keyjar=KEYJAR)
        self.provider.baseurl = self.provider.name

        self.cons = Consumer(
            {},
            CONSUMER_CONFIG,
            CLIENT_CONFIG,
            server_info=SERVER_INFO,
        )
        self.cons.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        self.cons.keyjar[""] = KC_RSA

    def test_providerinfo(self):
        self.provider.baseurl = 'http://example.com/path1/path2'
        resp = self.provider.create_providerinfo()
        assert resp.to_dict(
        )['authorization_endpoint'] == 'http://example.com/path1/path2/authorization'

    def test_providerinfo_trailing(self):
        self.provider.baseurl = 'http://example.com/path1/path2/'
        resp = self.provider.create_providerinfo()
        assert resp.to_dict(
        )['authorization_endpoint'] == 'http://example.com/path1/path2/authorization'

    def test_authorization_endpoint(self):
        bib = {
            "scope": ["openid"],
            "state": "id-6da9ca0cc23959f5f33e8becd9b08cae",
            "redirect_uri": "http://*****:*****@patch('oic.oic.provider.utc_time_sans_frac', Mock(return_value=123456))
    def test_client_secret_expiration_time(self):
        exp_time = self.provider.client_secret_expiration_time()
        assert exp_time == 209856

    def test_registration_endpoint(self):
        req = RegistrationRequest()

        req["application_type"] = "web"
        req["client_name"] = "My super service"
        req["redirect_uris"] = ["http://example.com/authz"]
        req["contacts"] = ["*****@*****.**"]
        req["response_types"] = ["code"]

        resp = self.provider.registration_endpoint(request=req.to_json())

        regresp = RegistrationResponse().deserialize(resp.message, "json")
        assert _eq(regresp.keys(), [
            'redirect_uris', 'contacts', 'application_type', 'client_name',
            'registration_client_uri', 'client_secret_expires_at',
            'registration_access_token', 'client_id', 'client_secret',
            'client_id_issued_at', 'response_types'
        ])

    def test_registration_endpoint_unicode(self):
        data = 'application_type=web&client_name=M%C3%A1+supe%C5%99+service&' \
               'redirect_uris=http%3A%2F%2Fexample.com%2Fauthz&response_types=code'
        resp = self.provider.registration_endpoint(request=data)

        regresp = RegistrationResponse().deserialize(resp.message, "json")
        assert _eq(regresp.keys(), [
            'redirect_uris', 'application_type', 'client_name',
            'registration_client_uri', 'client_secret_expires_at',
            'registration_access_token', 'client_id', 'client_secret',
            'client_id_issued_at', 'response_types'
        ])

    def test_registration_endpoint_with_non_https_redirect_uri_implicit_flow(
            self):
        params = {
            "application_type": "web",
            "redirect_uris": ["http://example.com/authz"],
            "response_types": ["id_token", "token"]
        }
        req = RegistrationRequest(**params)
        resp = self.provider.registration_endpoint(request=req.to_json())

        assert resp.status == "400 Bad Request"
        error = json.loads(resp.message)
        assert error["error"] == "invalid_redirect_uri"

    def test_verify_redirect_uris_with_https_code_flow(self):
        params = {
            "application_type": "web",
            "redirect_uris": ["http://example.com/authz"],
            "response_types": ["code"]
        }
        request = RegistrationRequest(**params)
        verified_uris = self.provider.verify_redirect_uris(request)
        assert verified_uris == [("http://example.com/authz", None)]

    def test_verify_redirect_uris_with_non_https_redirect_uri_implicit_flow(
            self):
        params = {
            "application_type": "web",
            "redirect_uris": ["http://example.com/authz"],
            "response_types": ["id_token", "token"]
        }
        request = RegistrationRequest(**params)

        with pytest.raises(InvalidRedirectURIError) as exc_info:
            self.provider.verify_redirect_uris(request)

        assert str(exc_info.value) == "None https redirect_uri not allowed"

    def test_provider_key_setup(self, tmpdir, session_db_factory):
        path = tmpdir.strpath
        provider = Provider("pyoicserv",
                            session_db_factory(SERVER_INFO["issuer"]), None,
                            None, None, None, None, None)
        provider.baseurl = "http://www.example.com"
        provider.key_setup(path, path, sig={"format": "jwk", "alg": "RSA"})

        keys = provider.keyjar.get_signing_key("RSA")
        assert len(keys) == 1
        assert provider.jwks_uri == "http://www.example.com/{}/jwks".format(
            path)

    @pytest.mark.parametrize("uri", [
        "http://example.org/foo", "http://example.com/cb",
        "http://example.org/cb?got=you", "http://example.org/cb/foo?got=you"
    ])
    def test_verify_redirect_uri_faulty_without_query(self, uri):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])
        registration_req = rr.to_json()

        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    response_type="code",
                                    scope="openid")

        with pytest.raises(RedirectURIError):
            self.provider._verify_redirect_uri(areq)

    @pytest.mark.parametrize("uri", [
        "http://example.org/cb",
    ])
    def test_verify_redirect_uri_correct_without_query(self, uri):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])
        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    response_type="code",
                                    scope="openid")

        self.provider._verify_redirect_uri(areq)

    def test_verify_sector_identifier_nonreachable(self):
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com")
        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET, "https://example.com", status=404)
            message = "Couldn't open sector_identifier_uri"
            with pytest.raises(InvalidSectorIdentifier, message=message):
                self.provider._verify_sector_identifier(rr)

        assert len(logcap.records) == 0

    def test_verify_sector_identifier_error(self):
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com")
        error = ConnectionError('broken connection')
        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET, "https://example.com", body=error)
            with pytest.raises(InvalidSectorIdentifier,
                               message="Couldn't open sector_identifier_uri"):
                self.provider._verify_sector_identifier(rr)

        assert len(logcap.records) == 2
        # First log record is from server...
        assert logcap.records[1].msg == error

    def test_verify_sector_identifier_malformed(self):
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com")
        body = "This is not the JSON you are looking for"
        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET, "https://example.com", body=body)
            with pytest.raises(
                    InvalidSectorIdentifier,
                    message="Error deserializing sector_identifier_uri content"
            ):
                self.provider._verify_sector_identifier(rr)

        assert len(logcap.records) == 1
        assert logcap.records[0].msg == "sector_identifier_uri => %s"
        assert logcap.records[0].args == (body, )

    def test_verify_sector_identifier_ru_missing_in_si(self):
        """Redirect_uris is not present in the sector_identifier_uri content."""
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com",
                                 redirect_uris=["http://example.com/missing"])
        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET,
                     "https://example.com",
                     body=json.dumps(["http://example.com/present"]))
            with pytest.raises(
                    InvalidSectorIdentifier,
                    message="redirect uri missing from sector_identifiers"):
                self.provider._verify_sector_identifier(rr)

        assert len(logcap.records) == 2
        assert logcap.records[0].msg == "sector_identifier_uri => %s"
        assert logcap.records[0].args == ('["http://example.com/present"]', )
        assert logcap.records[1].msg == "redirect_uris: %s"
        assert logcap.records[1].args == (["http://example.com/missing"], )

    def test_verify_sector_identifier_ru_missing(self):
        """Redirect_uris is not present in the request."""
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com")
        redirects = ["http://example.com/present"]

        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET,
                     "https://example.com",
                     body=json.dumps(redirects))
            si_redirects, si_url = self.provider._verify_sector_identifier(rr)

        assert si_url == "https://example.com"
        assert si_redirects == redirects
        assert len(logcap.records) == 1
        assert logcap.records[0].msg == "sector_identifier_uri => %s"
        assert logcap.records[0].args == ('["http://example.com/present"]', )

    def test_verify_sector_identifier_ru_ok(self):
        """Redirect_uris is present in the sector_identifier_uri content."""
        rr = RegistrationRequest(operation="register",
                                 sector_identifier_uri="https://example.com",
                                 redirect_uris=["http://example.com/present"])
        redirects = ["http://example.com/present"]

        with responses.RequestsMock() as rsps, LogCapture(
                level=logging.DEBUG) as logcap:
            rsps.add(rsps.GET,
                     "https://example.com",
                     body=json.dumps(redirects))
            si_redirects, si_url = self.provider._verify_sector_identifier(rr)

        assert si_url == "https://example.com"
        assert si_redirects == redirects
        assert len(logcap.records) == 2
        assert logcap.records[0].msg == "sector_identifier_uri => %s"
        assert logcap.records[0].args == ('["http://example.com/present"]', )
        assert logcap.records[1].msg == "redirect_uris: %s"
        assert logcap.records[1].args == (["http://example.com/present"], )

    @pytest.mark.parametrize("uri", [
        "http://example.org/cb", "http://example.org/cb?got=you",
        "http://example.org/cb?foo=you"
        "http://example.org/cb?foo=bar&got=you",
        "http://example.org/cb?foo=you&foo=bar"
    ])
    def test_registered_redirect_uri_faulty_with_query_component(self, uri):
        rr = RegistrationRequest(
            operation="register",
            redirect_uris=["http://example.org/cb?foo=bar"],
            response_types=["code"])

        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    scope="openid",
                                    response_type="code")

        with pytest.raises(RedirectURIError):
            self.provider._verify_redirect_uri(areq)

    def test_registered_redirect_uri_correct_with_query_component(self):
        rr = RegistrationRequest(
            operation="register",
            redirect_uris=["http://example.org/cb?foo=bar"],
            response_types=["code"])

        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(
            redirect_uri="http://example.org/cb?foo=bar",
            client_id=cid,
            scope="openid",
            response_type="code")

        self.provider._verify_redirect_uri(areq)

    def test_verify_redirect_uri_native_http_localhost(self):
        areq = RegistrationRequest(redirect_uris=["http://localhost/cb"],
                                   application_type='native')

        self.provider.verify_redirect_uris(areq)

    def test_verify_redirect_uri_native_loopback(self):
        areq = RegistrationRequest(redirect_uris=["http://127.0.0.1/cb"],
                                   application_type='native')

        self.provider.verify_redirect_uris(areq)

    def test_verify_redirect_uri_native_http_non_localhost(self):
        areq = RegistrationRequest(redirect_uris=["http://example.org/cb"],
                                   application_type='native')

        try:
            self.provider.verify_redirect_uris(areq)
        except InvalidRedirectURIError:
            assert True

    def test_verify_redirect_uri_native_custom(self):
        areq = RegistrationRequest(
            redirect_uris=["com.example.app:/oauth2redirect"],
            application_type='native')

        self.provider.verify_redirect_uris(areq)

    def test_verify_redirect_uri_native_https(self):
        areq = RegistrationRequest(redirect_uris=["https://example.org/cb"],
                                   application_type='native')

        try:
            self.provider.verify_redirect_uris(areq)
        except InvalidRedirectURIError:
            assert True

    def test_read_registration(self):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/new"],
                                 response_types=["code"])
        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)

        authn = ' '.join(['Bearer', regresp['registration_access_token']])
        query = '='.join(['client_id', regresp['client_id']])
        resp = self.provider.read_registration(authn, query)

        assert json.loads(resp.message) == regresp.to_dict()

    def test_read_registration_wrong_authn(self):
        resp = self.provider.read_registration('wrong string', 'request')
        assert resp.status == '400 Bad Request'
        assert json.loads(resp.message) == {
            'error': 'invalid_request',
            'error_description': None
        }

    def test_key_rollover(self):
        provider2 = Provider("FOOP", {}, {}, None, None, None, None, None)
        provider2.keyjar = KEYJAR
        # Number of KeyBundles
        assert len(provider2.keyjar.issuer_keys[""]) == 1
        kb = ec_init({"type": "EC", "crv": "P-256", "use": ["sig"]})
        provider2.do_key_rollover(json.loads(kb.jwks()), "b%d")
        assert len(provider2.keyjar.issuer_keys[""]) == 2
        kb = ec_init({"type": "EC", "crv": "P-256", "use": ["sig"]})
        provider2.do_key_rollover(json.loads(kb.jwks()), "b%d")
        assert len(provider2.keyjar.issuer_keys[""]) == 3
        provider2.remove_inactive_keys(-1)
        assert len(provider2.keyjar.issuer_keys[""]) == 2

    def test_endsession_endpoint(self):
        resp = self.provider.endsession_endpoint("")
        self._assert_cookies_expired(resp.headers)

        # End session not allowed if no cookie is sent (can't determine session)
        resp = self.provider.endsession_endpoint("", cookie="FAIL")
        assert resp.status == "400 Bad Request"

    def test_endsession_endpoint_with_id_token_hint(self):
        id_token = self._auth_with_id_token()
        assert self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify we got valid session

        id_token_hint = id_token.to_jwt(algorithm="none")
        resp = self.provider.endsession_endpoint(
            urlencode({"id_token_hint": id_token_hint}))
        assert not self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify session has been removed
        self._assert_cookies_expired(resp.headers)

    def test_endsession_endpoint_with_post_logout_redirect_uri(self):
        id_token = self._auth_with_id_token()
        assert self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify we got valid session

        post_logout_redirect_uri = \
            CDB[CLIENT_CONFIG["client_id"]]["post_logout_redirect_uris"][0][0]
        resp = self.provider.endsession_endpoint(
            urlencode({"post_logout_redirect_uri": post_logout_redirect_uri}))
        assert isinstance(resp, SeeOther)
        assert not self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify session has been removed
        self._assert_cookies_expired(resp.headers)

    def test_session_state_in_auth_req_for_session_support(
            self, session_db_factory):
        provider = Provider(SERVER_INFO["issuer"],
                            session_db_factory(SERVER_INFO["issuer"]),
                            CDB,
                            AUTHN_BROKER,
                            USERINFO,
                            AUTHZ,
                            verify_client,
                            SYMKEY,
                            urlmap=URLMAP,
                            keyjar=KEYJAR)

        provider.capabilities.update(
            {"check_session_iframe": "https://op.example.com/check_session"})

        req_args = {
            "scope": ["openid"],
            "redirect_uri": "http://localhost:8087/authz",
            "response_type": ["code"],
            "client_id": "number5"
        }
        areq = AuthorizationRequest(**req_args)
        resp = provider.authorization_endpoint(request=areq.to_urlencoded())
        aresp = self.cons.parse_response(AuthorizationResponse,
                                         resp.message,
                                         sformat="urlencoded")
        assert "session_state" in aresp

    def _assert_cookies_expired(self, http_headers):
        cookies_string = ";".join(
            [c[1] for c in http_headers if c[0] == "Set-Cookie"])
        all_cookies = SimpleCookie()

        try:
            cookies_string = cookies_string.decode()
        except (AttributeError, UnicodeDecodeError):
            pass

        all_cookies.load(cookies_string)

        now = datetime.datetime.utcnow()  #
        for c in [
                self.provider.cookie_name, self.provider.session_cookie_name
        ]:
            dt = datetime.datetime.strptime(all_cookies[c]["expires"],
                                            "%a, %d-%b-%Y %H:%M:%S GMT")
            assert dt < now  # make sure the cookies have expired to be cleared

    def _auth_with_id_token(self):
        state, location = self.cons.begin("openid",
                                          "id_token",
                                          path="http://localhost:8087")
        resp = self.provider.authorization_endpoint(
            request=location.split("?")[1])
        aresp = self.cons.parse_response(AuthorizationResponse,
                                         resp.message,
                                         sformat="urlencoded")
        return aresp["id_token"]

    def test_id_token_RS512_sign(self):
        self.provider.capabilities['id_token_signing_alg_values_supported'] = [
            'RS512'
        ]
        self.provider.build_jwx_def()
        id_token = self._auth_with_id_token()
        assert id_token.jws_header['alg'] == "RS512"

    def test_refresh_access_token_request(self):
        authreq = AuthorizationRequest(state="state",
                                       redirect_uri="http://example.com/authz",
                                       client_id=CLIENT_ID,
                                       response_type="code",
                                       scope=["openid", 'offline_access'],
                                       prompt='consent')

        _sdb = self.provider.sdb
        sid = _sdb.access_token.key(user="******", areq=authreq)
        access_grant = _sdb.access_token(sid=sid)
        ae = AuthnEvent("user", "salt")
        _sdb[sid] = {
            "oauth_state": "authz",
            "authn_event": ae.to_json(),
            "authzreq": authreq.to_json(),
            "client_id": CLIENT_ID,
            "code": access_grant,
            "code_used": False,
            "scope": ["openid", 'offline_access'],
            "redirect_uri": "http://example.com/authz",
        }
        _sdb.do_sub(sid, "client_salt")

        # Construct Access token request
        areq = AccessTokenRequest(code=access_grant,
                                  client_id=CLIENT_ID,
                                  redirect_uri="http://example.com/authz",
                                  client_secret=CLIENT_SECRET,
                                  grant_type='authorization_code')

        txt = areq.to_urlencoded()

        resp = self.provider.token_endpoint(request=txt)
        atr = AccessTokenResponse().deserialize(resp.message, "json")

        rareq = RefreshAccessTokenRequest(grant_type="refresh_token",
                                          refresh_token=atr['refresh_token'],
                                          client_id=CLIENT_ID,
                                          client_secret=CLIENT_SECRET,
                                          scope=['openid'])

        resp = self.provider.token_endpoint(request=rareq.to_urlencoded())
        atr2 = AccessTokenResponse().deserialize(resp.message, "json")
        assert atr2['access_token'] != atr['access_token']
        assert atr2['refresh_token'] == atr['refresh_token']
        assert atr2['token_type'] == 'Bearer'
示例#32
0
class TestOICConsumerLogout:
    @pytest.fixture(autouse=True)
    def setup_consumer(self, session_db_factory):
        client_config = {
            "client_id": CLIENT_ID,
            "client_authn_method": CLIENT_AUTHN_METHOD,
        }

        self.consumer = Consumer(DictSessionBackend(), CONFIG, client_config,
                                 SERVER_INFO)
        self.consumer.keyjar = CLIKEYS
        self.consumer.redirect_uris = ["https://example.com/authz"]
        self.consumer.client_secret = "hemlig"
        self.consumer.secret_type = "basic"
        self.consumer.issuer = ISSUER_ID

        self.provider = Provider(
            ISSUER_ID,
            session_db_factory(ISSUER_ID),
            CDB,
            AUTHN_BROKER,
            USERINFO,
            AUTHZ,
            verify_client,
            SYMKEY,
            urlmap=URLMAP,
            keyjar=SRVKEYS,
        )
        self.provider.baseurl = self.provider.name

    def test_logout_with_sub(self):
        # Simulate an authorization
        sid, request_location = self.consumer.begin("openid",
                                                    "code",
                                                    path="https://example.com")
        resp = self.provider.authorization_endpoint(request=request_location)
        part = self.consumer.parse_authz(resp.message)
        assert isinstance(part, tuple)
        aresp = part[0]
        assert aresp

        assert self.consumer.sdb[sid]["issuer"] == self.provider.baseurl

        # Simulate an accesstoken request
        areq = AccessTokenRequest(
            code=aresp["code"],
            client_id=CLIENT_ID,
            redirect_uri="http://example.com/authz",
            client_secret=self.consumer.client_secret,
            grant_type="authorization_code",
        )
        token_resp = self.provider.code_grant_type(areq)
        tresp = self.consumer.parse_response(AccessTokenResponse,
                                             token_resp.message,
                                             sformat="json")

        # Now, for the backchannel logout. This happens on the OP
        logout_info = {
            "sub": tresp["id_token"]["sub"],
            "events": {
                BACK_CHANNEL_LOGOUT_EVENT: {}
            },
        }
        alg = "RS256"
        _jws = JWT(
            self.provider.keyjar,
            iss=self.provider.baseurl,
            lifetime=86400,
            sign_alg=alg,
        )
        logout_token = _jws.pack(aud=CLIENT_ID, **logout_info)

        # The logout request that gets sent to the RP
        request = BackChannelLogoutRequest(logout_token=logout_token)

        # The RP evaluates the request. If everything is OK a session ID (== original state
        # value) is returned.
        _sid = self.consumer.backchannel_logout(request_args=request.to_dict())

        assert _sid == sid

        # Test other coding
        _sid = self.consumer.backchannel_logout(
            request=request.to_urlencoded())
        assert _sid == sid

    def test_not_for_me(self):
        _sub = "sub"

        logout_info = {"sub": _sub, "events": {BACK_CHANNEL_LOGOUT_EVENT: {}}}
        alg = "RS256"
        _jws = JWT(
            self.provider.keyjar,
            iss=self.provider.baseurl,
            lifetime=86400,
            sign_alg=alg,
        )
        logout_token = _jws.pack(aud="someone", **logout_info)

        # The logout request that gets sent to the RP
        request = BackChannelLogoutRequest(logout_token=logout_token)

        with pytest.raises(MessageException):
            self.consumer.backchannel_logout(request_args=request.to_dict())

    def test_logout_without_sub(self):
        # Simulate an authorization
        sid, request_location = self.consumer.begin("openid",
                                                    "code",
                                                    path="https://example.com")
        resp = self.provider.authorization_endpoint(request=request_location)
        part = self.consumer.parse_authz(resp.message)
        assert isinstance(part, tuple)
        aresp = part[0]
        assert aresp

        assert self.consumer.sdb[sid]["issuer"] == self.provider.baseurl

        # Simulate an accesstoken request
        areq = AccessTokenRequest(
            code=aresp["code"],
            client_id=CLIENT_ID,
            redirect_uri="http://example.com/authz",
            client_secret=self.consumer.client_secret,
            grant_type="authorization_code",
        )
        token_resp = self.provider.code_grant_type(areq)
        self.consumer.parse_response(AccessTokenResponse,
                                     token_resp.message,
                                     sformat="json")
        # Have to fake this until the provider changes are in place
        _smid = "session_management_id"
        self.consumer.sso_db.update(sid, "smid", _smid)

        # Now, for the backchannel logout. This happens on the OP
        logout_info = {"sid": _smid, "events": {BACK_CHANNEL_LOGOUT_EVENT: {}}}
        alg = "RS256"
        _jws = JWT(
            self.provider.keyjar,
            iss=self.provider.baseurl,
            lifetime=86400,
            sign_alg=alg,
        )
        logout_token = _jws.pack(aud=CLIENT_ID, **logout_info)

        # The logout request that gets sent to the RP
        request = BackChannelLogoutRequest(logout_token=logout_token)

        # The RP evaluates the request. If everything is OK a session ID (== original state
        # value) is returned.
        _sid = self.consumer.backchannel_logout(request_args=request.to_dict())

        assert _sid == [sid]

    def test_logout_with_none(self):
        # Now for the backchannel logout. This happens on the OP

        logout_info = LogoutToken(events={BACK_CHANNEL_LOGOUT_EVENT: {}})

        alg = "RS256"
        _jws = JWT(
            self.provider.keyjar,
            iss=self.provider.baseurl,
            lifetime=86400,
            sign_alg=alg,
        )
        logout_token = _jws.pack(aud=CLIENT_ID, **logout_info)

        # The logout request that gets sent to the RP
        request = BackChannelLogoutRequest(logout_token=logout_token)

        # The RP evaluates the request. If everything is OK a session ID (== original state
        # value) is returned.
        with pytest.raises(MessageException):
            self.consumer.backchannel_logout(request_args=request.to_dict())

    def test_sso_db_dict(self):
        client_config = {
            "client_id": CLIENT_ID,
            "client_authn_method": CLIENT_AUTHN_METHOD,
        }

        _consumer = Consumer({}, CONFIG, client_config, SERVER_INFO, sso_db={})
        _consumer.keyjar = CLIKEYS
        _consumer.redirect_uris = ["https://example.com/authz"]
        _consumer.client_secret = "hemlig"
        _consumer.secret_type = "basic"
        _consumer.issuer = ISSUER_ID

        # Simulate an authorization
        sid, request_location = _consumer.begin("openid",
                                                "code",
                                                path="https://example.com")
        resp = self.provider.authorization_endpoint(request=request_location)
        part = _consumer.parse_authz(resp.message)
        assert isinstance(part, tuple)
        aresp = part[0]
        assert aresp

        assert _consumer.sdb[sid]["issuer"] == self.provider.baseurl

        # Simulate an accesstoken request
        areq = AccessTokenRequest(
            code=aresp["code"],
            client_id=CLIENT_ID,
            redirect_uri="http://example.com/authz",
            client_secret=_consumer.client_secret,
            grant_type="authorization_code",
        )
        token_resp = self.provider.code_grant_type(areq)
        tresp = _consumer.parse_response(AccessTokenResponse,
                                         token_resp.message,
                                         sformat="json")

        # Now, for the backchannel logout. This happens on the OP
        logout_info = {
            "sub": tresp["id_token"]["sub"],
            "events": {
                BACK_CHANNEL_LOGOUT_EVENT: {}
            },
        }
        alg = "RS256"
        _jws = JWT(
            self.provider.keyjar,
            iss=self.provider.baseurl,
            lifetime=86400,
            sign_alg=alg,
        )
        logout_token = _jws.pack(aud=CLIENT_ID, **logout_info)

        # The logout request that gets sent to the RP
        request = BackChannelLogoutRequest(logout_token=logout_token)

        # The RP evaluates the request. If everything is OK a session ID (== original state
        # value) is returned.
        _sid = _consumer.backchannel_logout(request_args=request.to_dict())
        assert _sid == sid

    def test_attribute_error(self):
        self.consumer.sdb.update("sid", "foo", "bar")
        self.consumer.update("sid")

        with pytest.raises(AttributeError):
            getattr(self.consumer, "foo")
示例#33
0
class TestOICConsumer():
    def setup_class(self):
        self.consumer = Consumer(SessionDB(), CONFIG, CLIENT_CONFIG,
                                 SERVER_INFO)
        self.consumer.client_secret = CLIENT_SECRET

    def test_init(self):
        assert self.consumer

    def test_backup_keys(self):
        keys = self.consumer.__dict__.keys()
        print keys
        _dict = self.consumer.dictionary()
        print _dict.keys()
        dkeys = [key for key in keys if key not in _dict.keys()]
        print dkeys
        assert _eq(dkeys, IGNORE)

    def test_backup_restore(self):
        _dict = self.consumer.__dict__.items()

        self.consumer._backup("sid")
        self.consumer.restore("sid")

        assert _dict == self.consumer.__dict__.items()

        self.consumer.authorization_endpoint = AUTHZ_URL

        assert _dict != self.consumer.__dict__.items()

        self.consumer.restore("sid")

        assert _dict == self.consumer.__dict__.items()

    def test_backup_restore_update(self):
        self.consumer.authorization_endpoint = AUTHZ_URL
        self.consumer.token_endpoint = "http://example.com/token"
        self.consumer.userinfo_endpoint = "http://example.com/userinfo"

        self.consumer._backup("sid")

        self.consumer.authorization_endpoint = AUTHZ_ORG_URL
        self.consumer.token_endpoint = "http://example.org/token"
        self.consumer.userinfo_endpoint = ""

        assert self.consumer.authorization_endpoint == AUTHZ_ORG_URL
        assert self.consumer.token_endpoint == "http://example.org/token"
        assert self.consumer.userinfo_endpoint == ""

        self.consumer.update("sid")

        assert self.consumer.authorization_endpoint == AUTHZ_ORG_URL
        assert self.consumer.token_endpoint == "http://example.org/token"
        assert self.consumer.userinfo_endpoint == "http://example.com/userinfo"

    def test_begin(self):
        self.consumer.authorization_endpoint = AUTHZ_URL
        self.consumer.keyjar[""].append(KC_RSA)
        #self.consumer.keyjar.set_sign_key(rsapub, "rsa")
        #self.consumer.keyjar.set_verify_key(rsapub, "rsa")

        srv = Server()
        srv.keyjar = SRVKEYS
        print "redirect_uris", self.consumer.redirect_uris
        print "config", self.consumer.config
        location = self.consumer.begin("openid", "code")
        print location
        authreq = srv.parse_authorization_request(url=location)
        print authreq.keys()
        assert _eq(authreq.keys(), ['request', 'state', 'max_age', 'claims',
                                    'response_type', 'client_id', 'scope',
                                    'redirect_uri'])

        assert authreq["state"] == self.consumer.state
        assert authreq["scope"] == self.consumer.config["scope"]
        assert authreq["client_id"] == self.consumer.client_id

    def test_begin_file(self):
        self.consumer.config["request_method"] = "file"
        self.consumer.config["temp_dir"] = "./file"
        self.consumer.config["temp_path"] = "/tmp/"
        self.consumer.config["authz_page"] = "/authz"
        srv = Server()
        srv.keyjar = SRVKEYS

        location = self.consumer.begin("openid", "code",
                                       path="http://localhost:8087")
        print location
        #vkeys = {".":srv.keyjar.get_verify_key()}
        authreq = srv.parse_authorization_request(url=location)
        print authreq.keys()
        assert _eq(authreq.keys(), ['max_age', 'state', 'redirect_uri',
                                    'response_type', 'client_id', 'scope',
                                    'claims', 'request_uri'])

        assert authreq["state"] == self.consumer.state
        assert authreq["scope"] == self.consumer.config["scope"]
        assert authreq["client_id"] == self.consumer.client_id
        assert authreq["redirect_uri"].startswith("http://localhost:8087/authz")

    def test_complete(self):
        mfos = MyFakeOICServer("http://localhost:8088")
        mfos.keyjar = SRVKEYS

        self.consumer.http_request = mfos.http_request
        self.consumer.state = "state0"
        self.consumer.nonce = rndstr()
        self.consumer.redirect_uris = ["https://example.com/cb"]
        args = {
            "client_id": self.consumer.client_id,
            "response_type": "code",
            "scope": ["openid"],
        }

        result = self.consumer.do_authorization_request(
            state=self.consumer.state, request_args=args)
        assert result.status_code == 302
        print "redirect_uris", self.consumer.redirect_uris
        print result.headers["location"]

        assert result.headers["location"].startswith(
            self.consumer.redirect_uris[0])
        _, query = result.headers["location"].split("?")

        #vkeys = {".": self.consumer.keyjar.get_verify_key()}

        self.consumer.parse_response(AuthorizationResponse, info=query,
                                     sformat="urlencoded")

        resp = self.consumer.complete()
        print resp
        assert resp.type() == "AccessTokenResponse"
        print resp.keys()
        assert _eq(resp.keys(), ['token_type', 'state', 'access_token',
                                 'scope', 'expires_in', 'refresh_token'])

        assert resp["state"] == self.consumer.state

    def test_parse_authz(self):
        mfos = MyFakeOICServer("http://localhost:8088")
        mfos.keyjar = SRVKEYS

        self.consumer.http_request = mfos.http_request
        self.consumer.state = "state0"
        self.consumer.nonce = rndstr()
        args = {
            "client_id": self.consumer.client_id,
            "response_type": "code",
            "scope": ["openid"],
        }

        result = self.consumer.do_authorization_request(
            state=self.consumer.state, request_args=args)

        print self.consumer.sdb.keys()
        print self.consumer.sdb["state0"].keys()
        part = self.consumer.parse_authz(query=result.headers["location"])
        print part
        atr = part[0]
        assert part[1] is None
        assert part[2] is None

        assert atr.type() == "AuthorizationResponse"
        assert atr["state"] == "state0"
        assert "code" in atr

    def test_parse_authz_implicit(self):
        self.consumer.config["response_type"] = "implicit"

        args = {
            "client_id": self.consumer.client_id,
            "response_type": "implicit",
            "scope": ["openid"],
        }

        result = self.consumer.do_authorization_request(
            state=self.consumer.state, request_args=args)

        part = self.consumer.parse_authz(query=result.headers["location"])
        print part
        assert part[0] is None
        atr = part[1]
        assert part[2] is None

        assert atr.type() == "AccessTokenResponse"
        assert atr["state"] == "state0"
        assert "access_token" in atr
示例#34
0
    def test_sso_db_dict(self):
        client_config = {
            "client_id": CLIENT_ID,
            "client_authn_method": CLIENT_AUTHN_METHOD,
        }

        _consumer = Consumer({}, CONFIG, client_config, SERVER_INFO, sso_db={})
        _consumer.keyjar = CLIKEYS
        _consumer.redirect_uris = ["https://example.com/authz"]
        _consumer.client_secret = "hemlig"
        _consumer.secret_type = "basic"
        _consumer.issuer = ISSUER_ID

        # Simulate an authorization
        sid, request_location = _consumer.begin("openid",
                                                "code",
                                                path="https://example.com")
        resp = self.provider.authorization_endpoint(request=request_location)
        part = _consumer.parse_authz(resp.message)
        assert isinstance(part, tuple)
        aresp = part[0]
        assert aresp

        assert _consumer.sdb[sid]["issuer"] == self.provider.baseurl

        # Simulate an accesstoken request
        areq = AccessTokenRequest(
            code=aresp["code"],
            client_id=CLIENT_ID,
            redirect_uri="http://example.com/authz",
            client_secret=_consumer.client_secret,
            grant_type="authorization_code",
        )
        token_resp = self.provider.code_grant_type(areq)
        tresp = _consumer.parse_response(AccessTokenResponse,
                                         token_resp.message,
                                         sformat="json")

        # Now, for the backchannel logout. This happens on the OP
        logout_info = {
            "sub": tresp["id_token"]["sub"],
            "events": {
                BACK_CHANNEL_LOGOUT_EVENT: {}
            },
        }
        alg = "RS256"
        _jws = JWT(
            self.provider.keyjar,
            iss=self.provider.baseurl,
            lifetime=86400,
            sign_alg=alg,
        )
        logout_token = _jws.pack(aud=CLIENT_ID, **logout_info)

        # The logout request that gets sent to the RP
        request = BackChannelLogoutRequest(logout_token=logout_token)

        # The RP evaluates the request. If everything is OK a session ID (== original state
        # value) is returned.
        _sid = _consumer.backchannel_logout(request_args=request.to_dict())
        assert _sid == sid
示例#35
0
class TestProvider(object):
    @pytest.fixture(autouse=True)
    def create_provider(self):
        self.provider = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]),
                                 CDB,
                                 AUTHN_BROKER, USERINFO,
                                 AUTHZ, verify_client, SYMKEY, urlmap=URLMAP,
                                 keyjar=KEYJAR)
        self.provider.baseurl = self.provider.name

        self.cons = Consumer({}, CONSUMER_CONFIG, CLIENT_CONFIG,
                             server_info=SERVER_INFO, )
        self.cons.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]}
        self.cons.keyjar[""] = KC_RSA

    def test_authorization_endpoint(self):
        bib = {"scope": ["openid"],
               "state": "id-6da9ca0cc23959f5f33e8becd9b08cae",
               "redirect_uri": "http://*****:*****@example.com"]
        req["response_types"] = ["code"]

        resp = self.provider.registration_endpoint(request=req.to_json())

        regresp = RegistrationResponse().deserialize(resp.message, "json")
        assert _eq(regresp.keys(),
                   ['redirect_uris', 'contacts', 'application_type',
                    'client_name', 'registration_client_uri',
                    'client_secret_expires_at',
                    'registration_access_token',
                    'client_id', 'client_secret',
                    'client_id_issued_at', 'response_types'])

    def test_registration_endpoint_with_non_https_redirect_uri_implicit_flow(
            self):
        params = {"application_type": "web",
                  "redirect_uris": ["http://example.com/authz"],
                  "response_types": ["id_token", "token"]}
        req = RegistrationRequest(**params)
        resp = self.provider.registration_endpoint(request=req.to_json())

        assert resp.status == "400 Bad Request"
        error = json.loads(resp.message)
        assert error["error"] == "invalid_redirect_uri"

    def test_verify_redirect_uris_with_https_code_flow(self):
        params = {"application_type": "web",
                  "redirect_uris": ["http://example.com/authz"],
                  "response_types": ["code"]}
        request = RegistrationRequest(**params)
        verified_uris = self.provider._verify_redirect_uris(request)
        assert verified_uris == [("http://example.com/authz", None)]

    def test_verify_redirect_uris_with_non_https_redirect_uri_implicit_flow(self):
        params = {"application_type": "web",
                  "redirect_uris": ["http://example.com/authz"],
                  "response_types": ["id_token", "token"]}
        request = RegistrationRequest(**params)

        with pytest.raises(InvalidRedirectURIError) as exc_info:
            self.provider._verify_redirect_uris(request)

        assert str(exc_info.value) == "None https redirect_uri not allowed"

    @pytest.mark.network
    def test_registration_endpoint_openid4us(self):
        req = RegistrationRequest(
            **{'token_endpoint_auth_method': u'client_secret_post',
               'redirect_uris': [
                   u'https://connect.openid4.us:5443/phpRp/index.php/callback',
                   u'https://connect.openid4.us:5443/phpRp/authcheck.php/authcheckcb'],
               'jwks_uri': u'https://connect.openid4.us:5443/phpRp/rp/rp.jwk',
               'userinfo_encrypted_response_alg': u'RSA1_5',
               'contacts': [u'*****@*****.**'],
               'userinfo_encrypted_response_enc': u'A128CBC-HS256',
               'application_type': u'web',
               'client_name': u'ABRP-17',
               'grant_types': [u'authorization_code', u'implicit'],
               'post_logout_redirect_uris': [
                   u'https://connect.openid4.us:5443/phpRp/index.php/logoutcb'],
               'subject_type': u'public',
               'response_types': [u'code', u'token', u'id_token', u'code token',
                                  u'code id_token', u'id_token token',
                                  u'code id_token token'],
               'policy_uri': u'https://connect.openid4.us:5443/phpRp/index.php/policy',
               'logo_uri': u'https://connect.openid4.us:5443/phpRp/media/logo.png'})

        resp = self.provider.registration_endpoint(request=req.to_json())

        regresp = RegistrationResponse().deserialize(resp.message, "json")
        assert _eq(regresp.keys(), list(req.keys()) +
                   ['registration_client_uri',
                    'client_secret_expires_at',
                    'registration_access_token',
                    'client_id', 'client_secret',
                    'client_id_issued_at'])

    def test_provider_key_setup(self, tmpdir):
        path = tmpdir.strpath
        provider = Provider("pyoicserv", SessionDB(SERVER_INFO["issuer"]), None,
                            None, None, None, None, "")
        provider.baseurl = "http://www.example.com"
        provider.key_setup(path, path, sig={"format": "jwk", "alg": "RSA"})

        keys = provider.keyjar.get_signing_key("RSA")
        assert len(keys) == 1
        assert provider.jwks_uri == "http://www.example.com/{}/jwks".format(
            path)

    @pytest.mark.parametrize("uri", [
        "http://example.org/foo",
        "http://example.com/cb",
        "http://example.org/cb?got=you",
        "http://example.org/cb/foo?got=you"
    ])
    def test_verify_redirect_uri_faulty_without_query(self, uri):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])
        registration_req = rr.to_json()

        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    response_type="code",
                                    scope="openid")

        with pytest.raises(RedirectURIError):
            self.provider._verify_redirect_uri(areq)

    @pytest.mark.parametrize("uri", [
        "http://example.org/cb",
        "http://example.org/cb/foo"
    ])
    def test_verify_redirect_uri_correct_without_query(self, uri):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])
        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    response_type="code",
                                    scope="openid")

        self.provider._verify_redirect_uri(areq)

    @pytest.mark.parametrize("uri", [
        "http://example.org/cb",
        "http://example.org/cb/foo",
        "http://example.org/cb?got=you",
        "http://example.org/cb?foo=you"
        "http://example.org/cb?foo=bar&got=you",
        "http://example.org/cb?foo=you&foo=bar"
    ])
    def test_registered_redirect_uri_faulty_with_query_component(self, uri):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=[
                                     "http://example.org/cb?foo=bar"],
                                 response_types=["code"])

        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(redirect_uri=uri,
                                    client_id=cid,
                                    scope="openid",
                                    response_type="code")

        with pytest.raises(RedirectURIError):
            self.provider._verify_redirect_uri(areq)

    def test_registered_redirect_uri_correct_with_query_component(self):
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=[
                                     "http://example.org/cb?foo=bar"],
                                 response_types=["code"])

        registration_req = rr.to_json()
        resp = self.provider.registration_endpoint(request=registration_req)
        regresp = RegistrationResponse().from_json(resp.message)
        cid = regresp["client_id"]

        areq = AuthorizationRequest(
            redirect_uri="http://example.org/cb?foo=bar",
            client_id=cid, scope="openid",
            response_type="code")

        self.provider._verify_redirect_uri(areq)

    def test_key_rollover(self):
        provider2 = Provider("FOOP", {}, {}, None, None, None, None, "")
        provider2.keyjar = KEYJAR
        # Number of KeyBundles
        assert len(provider2.keyjar.issuer_keys[""]) == 1
        kb = ec_init({"type": "EC", "crv": "P-256", "use": ["sig"]})
        provider2.do_key_rollover(json.loads(kb.jwks()), "b%d")
        assert len(provider2.keyjar.issuer_keys[""]) == 2
        kb = ec_init({"type": "EC", "crv": "P-256", "use": ["sig"]})
        provider2.do_key_rollover(json.loads(kb.jwks()), "b%d")
        assert len(provider2.keyjar.issuer_keys[""]) == 3
        provider2.remove_inactive_keys(-1)
        assert len(provider2.keyjar.issuer_keys[""]) == 2

    def test_endsession_endpoint(self):
        resp = self.provider.endsession_endpoint("")
        self._assert_cookies_expired(resp.headers)

        # End session not allowed if no cookie is sent (can't determine session)
        resp = self.provider.endsession_endpoint("", cookie="FAIL")
        assert resp.status == "400 Bad Request"

    def test_endsession_endpoint_with_id_token_hint(self):
        id_token = self._auth_with_id_token()
        assert self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify we got valid session

        id_token_hint = id_token.to_jwt(algorithm="none")
        resp = self.provider.endsession_endpoint(
            urlencode({"id_token_hint": id_token_hint}))
        assert not self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify session has been removed
        self._assert_cookies_expired(resp.headers)

    def test_endsession_endpoint_with_post_logout_redirect_uri(self):
        id_token = self._auth_with_id_token()
        assert self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify we got valid session

        post_logout_redirect_uri = \
            CDB[CLIENT_CONFIG["client_id"]]["post_logout_redirect_uris"][0][0]
        resp = self.provider.endsession_endpoint(urlencode(
            {"post_logout_redirect_uri": post_logout_redirect_uri}))
        assert isinstance(resp, Redirect)
        assert not self.provider.sdb.get_sids_by_sub(
            id_token["sub"])  # verify session has been removed
        self._assert_cookies_expired(resp.headers)

    def test_session_state_in_auth_req_for_session_support(self):
        provider = Provider("foo", SessionDB(SERVER_INFO["issuer"]), CDB,
                            AUTHN_BROKER, USERINFO,
                            AUTHZ, verify_client, SYMKEY, urlmap=URLMAP,
                            keyjar=KEYJAR, capabilities={
                "check_session_iframe": "https://op.example.com/check_session"})

        req_args = {"scope": ["openid"],
                    "redirect_uri": "http://localhost:8087/authz",
                    "response_type": ["code"],
                    "client_id": "a1b2c3"
                    }
        areq = AuthorizationRequest(**req_args)
        resp = provider.authorization_endpoint(
            request=areq.to_urlencoded())
        aresp = self.cons.parse_response(AuthorizationResponse, resp.message,
                                         sformat="urlencoded")
        assert "session_state" in aresp

    def _assert_cookies_expired(self, http_headers):
        cookies_string = ";".join(
            [c[1] for c in http_headers if c[0] == "Set-Cookie"])
        all_cookies = SimpleCookie()
        all_cookies.load(cookies_string)

        now = datetime.datetime.now()
        for c in [self.provider.cookie_name, self.provider.session_cookie_name]:
            dt = datetime.datetime.strptime(all_cookies[c]["expires"],
                                            "%a, %d-%b-%Y %H:%M:%S GMT")
            assert dt < now  # make sure the cookies have expired to be cleared

    def _auth_with_id_token(self):
        state, location = self.cons.begin("openid", "id_token",
                                          path="http://localhost:8087")
        resp = self.provider.authorization_endpoint(
            request=location.split("?")[1])
        aresp = self.cons.parse_response(AuthorizationResponse, resp.message,
                                         sformat="urlencoded")
        return aresp["id_token"]
示例#36
0
class TestOICProvider(object):
    def setup_class(self):
        self.server = Provider("pyoicserv",
                               SessionDB(SERVER_INFO["issuer"]),
                               CDB,
                               AUTHN_BROKER,
                               USERINFO,
                               AUTHZ,
                               verify_client,
                               SYMKEY,
                               urlmap=URLMAP,
                               keyjar=KEYJAR)

        self.cons = Consumer(
            {},
            CONSUMER_CONFIG,
            CLIENT_CONFIG,
            server_info=SERVER_INFO,
        )
        self.cons.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }
        self.cons.debug = True
        self.cons.keyjar[""] = KC_RSA

    def test_server_init(self):
        assert self.server
        assert self.server.authn_broker == AUTHN_BROKER
        print self.server.urlmap
        assert self.server.urlmap["client_1"] == ["https://example.com/authz"]

    def test_server_authorization_endpoint(self):
        bib = {
            "scope": ["openid"],
            "state": "id-6da9ca0cc23959f5f33e8becd9b08cae",
            "redirect_uri": "http://*****:*****@example.com"]
        req["response_types"] = ["code"]

        print req.to_dict()

        resp = self.server.registration_endpoint(request=req.to_json())

        print resp.message
        regresp = RegistrationResponse().deserialize(resp.message, "json")
        print regresp.keys()
        assert _eq(regresp.keys(), [
            'redirect_uris', 'contacts', 'application_type', 'client_name',
            'registration_client_uri', 'client_secret_expires_at',
            'registration_access_token', 'client_id', 'client_secret',
            'client_id_issued_at', 'response_types'
        ])

    def test_provider_key_setup(self):
        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"})

        keys = provider.keyjar.get_signing_key("RSA")
        assert len(keys) == 1
        assert provider.jwks_uri == "http://www.example.com/static/jwks"

    def _client_id(self, cdb):
        cid = None
        for k, item in cdb.items():
            if item in cdb.keys():
                cid = item
                break

        return cid

    def test_registered_redirect_uri_without_query_component(self):
        provider = Provider("FOO", {}, {}, None, None, None, None, "")
        rr = RegistrationRequest(operation="register",
                                 redirect_uris=["http://example.org/cb"],
                                 response_types=["code"])

        registration_req = rr.to_json()

        provider.registration_endpoint(request=registration_req)

        correct = [
            "http://example.org/cb",
            "http://example.org/cb/foo",
        ]
        faulty = [
            "http://example.org/foo", "http://example.com/cb",
            "http://example.org/cb?got=you",
            "http://example.org/cb/foo?got=you"
        ]

        cid = self._client_id(provider.cdb)

        for ruri in faulty:
            areq = AuthorizationRequest(redirect_uri=ruri,
                                        client_id=cid,
                                        response_type="code",
                                        scope="openid")

            print areq
            try:
                provider._verify_redirect_uri(areq)
                assert False
            except RedirectURIError:
                pass

        for ruri in correct:
            areq = AuthorizationRequest(redirect_uri=ruri,
                                        client_id=cid,
                                        response_type="code",
                                        scope="openid")

            print areq
            try:
                provider._verify_redirect_uri(areq)
            except RedirectURIError, err:
                print err
                assert False