예제 #1
0
def test_provider_authenticated_token():
    provider = Provider("pyoicserv", sdb.SessionDB(), CDB, FUNCTIONS)
    _session_db = {}
    cons = Consumer(_session_db, client_config = CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True
    cons.response_type = "token"
    environ = BASE_ENVIRON

    location = cons.begin(environ, start_response)

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

    resp = provider.authorization_endpoint(environ, start_response)

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

    resp2 = provider.authenticated(environ2, start_response)

    assert len(resp2) == 1
    txt = resp2[0]
    assert "access_token=" in txt
    assert "token_type=Bearer" in txt
예제 #2
0
def test_consumer_client_get_access_token_reques():
    _session_db = {}
    cons = Consumer(_session_db,
                    client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO,
                    **CONSUMER_CONFIG)
    cons.client_secret = "secret0"
    cons.state = "state"
    cons.redirect_uris = ["https://www.example.com/oic/cb"]

    resp1 = AuthorizationResponse(code="auth_grant", state="state")
    cons.parse_response(AuthorizationResponse, resp1.to_urlencoded(),
                        "urlencoded")
    resp2 = AccessTokenResponse(access_token="token1",
                                token_type="Bearer",
                                expires_in=0,
                                state="state")
    cons.parse_response(AccessTokenResponse, resp2.to_urlencoded(),
                        "urlencoded")

    url, body, http_args = cons.get_access_token_request()
    assert url == "http://localhost:8088/token"
    print body
    assert body == ("code=auth_grant&client_secret=secret0&"
                    "grant_type=authorization_code&client_id=number5&"
                    "redirect_uri=https%3A%2F%2Fwww.example.com%2Foic%2Fcb")
    assert http_args == {
        'headers': {
            'content-type': 'application/x-www-form-urlencoded'
        }
    }
예제 #3
0
def test_factory():
    _session_db = {}
    cons = Consumer(_session_db,
                    client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO,
                    **CONSUMER_CONFIG)

    sid = stateID("https://example.org/", cons.seed)
    _state = sid
    cons._backup(sid)
    cons.sdb["seed:%s" % cons.seed] = sid

    kaka = make_cookie(CLIENT_CONFIG["client_id"],
                       _state,
                       cons.seed,
                       expire=360,
                       path="/")

    _oac = factory(kaka[1],
                   _session_db,
                   CLIENT_CONFIG["client_id"],
                   client_config=CLIENT_CONFIG,
                   server_info=SERVER_INFO,
                   **CONSUMER_CONFIG)

    assert _oac
    assert _oac.client_id == cons.client_id
    assert _oac.seed == cons.seed
예제 #4
0
    def __init__(self, outgoing, internal_attributes, config, base_url, name,
                 external_type, user_id_attr):
        """
        :param outgoing: Callback should be called by the module after the authorization in the
        backend is done.
        :param internal_attributes: Mapping dictionary between SATOSA internal attribute names and
        the names returned by underlying IdP's/OP's as well as what attributes the calling SP's and
        RP's expects namevice.
        :param config: Configuration parameters for the module.
        :param base_url: base url of the service
        :param name: name of the plugin
        :param external_type: The name for this module in the internal attributes.

        :type outgoing:
        (satosa.context.Context, satosa.internal_data.InternalResponse) -> satosa.response.Response
        :type internal_attributes: dict[string, dict[str, str | list[str]]]
        :type config: dict[str, dict[str, str] | list[str]]
        :type base_url: str
        :type name: str
        :type external_type: str
        """
        super().__init__(outgoing, internal_attributes, base_url, name)
        self.config = config
        self.redirect_url = "%s/%s" % (self.config["base_url"],
                                       self.config["authz_page"])
        self.external_type = external_type
        self.user_id_attr = user_id_attr
        self.consumer = Consumer(session_db=None,
                                 client_config=self.config["client_config"],
                                 server_info=self.config["server_info"],
                                 authz_page=self.config["authz_page"],
                                 response_type=self.config["response_type"])
        self.consumer.client_secret = self.config["client_secret"]
예제 #5
0
def test_provider_authenticated_none():
    provider = Provider("pyoicserv", sdb.SessionDB(), CDB, FUNCTIONS)
    _session_db = {}
    cons = Consumer(_session_db, client_config = CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True
    cons.response_type = "none"
    environ = BASE_ENVIRON

    location = cons.begin(environ, start_response)

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

    resp = provider.authorization_endpoint(environ, start_response)

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

    resp2 = provider.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]
    assert query.startswith("state=")
    assert "&" not in query
예제 #6
0
def test_factory():
    sdb = DictSessionBackend()
    consumer = Consumer(
        sdb,
        client_config=CLIENT_CONFIG,
        server_info=SERVER_INFO,
        settings=CLIENT_SETTINGS,
        **CONSUMER_CONFIG,
    )
    sid = stateID("https://example.org/", consumer.seed)
    _state = sid
    consumer._backup(sid)
    consumer.sdb["seed:%s" % consumer.seed] = sid

    kaka = make_cookie(CLIENT_CONFIG["client_id"],
                       _state,
                       consumer.seed,
                       expire=360,
                       path="/")

    _oac = factory(
        kaka[1],
        sdb,
        CLIENT_CONFIG["client_id"],
        client_config=CLIENT_CONFIG,
        server_info=SERVER_INFO,
        **CONSUMER_CONFIG,
    )

    assert _oac.client_id == consumer.client_id
    assert _oac.seed == consumer.seed
예제 #7
0
def test_consumer_parse_access_token():
    # implicit flow test
    _session_db = {}
    cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True
    environ = BASE_ENVIRON

    cons.response_type = ["token"]
    sid, loc = cons.begin("http://localhost:8087",
                          "http://localhost:8088/authorization")

    atr = AccessTokenResponse(access_token="2YotnFZFEjr1zCsicMWpAA",
                              token_type="example",
                              refresh_token="tGzv3JOkF0XG5Qx2TlKWIA",
                              example_parameter="example_value",
                              state=sid)

    res = cons.handle_authorization_response(query=atr.to_urlencoded())

    assert res.type() == "AccessTokenResponse"
    print cons.grant[sid]
    grant = cons.grant[sid]
    assert len(grant.tokens) == 1
    token = grant.tokens[0]
    assert token.access_token == "2YotnFZFEjr1zCsicMWpAA"
예제 #8
0
def test_provider_authenticated_token():
    provider = Provider("pyoicserv",
                        sdb.SessionDB(SERVER_INFO["issuer"]),
                        CDB,
                        AUTHN_BROKER,
                        AUTHZ,
                        verify_client,
                        symkey=rndstr(16))
    _session_db = {}
    cons = Consumer(_session_db,
                    client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO,
                    **CONSUMER_CONFIG)
    cons.debug = True

    sid, location = cons.begin("http://localhost:8087",
                               "http://localhost:8088/authorization", "token")

    QUERY_STRING = location.split("?")[1]
    resp = provider.authorization_endpoint(QUERY_STRING)
    print resp.headers
    print resp.message
    txt = resp.message
    assert "access_token=" in txt
    assert "token_type=Bearer" in txt
예제 #9
0
    def test_authenticated(self):
        _session_db = {}
        cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                        server_info=SERVER_INFO, **CONSUMER_CONFIG)

        sid, location = cons.begin("http://localhost:8087",
                                   "http://localhost:8088/authorization")

        resp = self.provider.authorization_endpoint(urlparse(location).query)
        assert resp.status == "303 See Other"
        resp = urlparse(resp.message).query
        with LogCapture(level=logging.DEBUG) as logcap:
            aresp = cons.handle_authorization_response(query=resp)

        assert isinstance(aresp, AuthorizationResponse)
        assert _eq(aresp.keys(), ['state', 'code', 'client_id', 'iss'])
        assert _eq(cons.grant[sid].keys(), ['tokens', 'code', 'exp_in',
                                            'seed', 'id_token',
                                            'grant_expiration_time'])

        state = aresp['state']
        assert _eq(logcap.records[0].msg, '- authorization - code flow -')
        assert logcap.records[1].msg in expected_outcome(
            'QUERY: ', ['state={}'.format(state), 'code=<REDACTED>',
                        'client_id=client1',
                        'iss=https%3A%2F%2Fexample.com%2Fas'])
        expected = {'iss': 'https://example.com/as',
                    'state': state, 'code': '<REDACTED>',
                    'client_id': 'client1'}
        # Eval here to avoid intermittent failures due to dict ordering
        assert _eq(eval(logcap.records[2].msg[29:-1]), expected)
        expected = ["'client_id': 'client1'", "'iss': 'https://example.com/as'",
                    "'keyjar': <KeyJar(issuers=[])>"]
        assert _eq(sorted(logcap.records[3].msg[22:-1].split(', ')), expected)
예제 #10
0
def test_consumer_parse_access_token():
    # implicit flow test
    _session_db = {}
    cons = Consumer(_session_db, client_config = CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True
    environ = BASE_ENVIRON

    cons.response_type = ["token"]
    _ = cons.begin(environ, start_response)

    atr = AccessTokenResponse(access_token="2YotnFZFEjr1zCsicMWpAA",
                              token_type="example",
                              refresh_token="tGzv3JOkF0XG5Qx2TlKWIA",
                              example_parameter="example_value",
                              state=cons.state)

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

    res = cons.handle_authorization_response(environ, start_response)

    assert res.type() ==  "AccessTokenResponse"
    print cons.grant[cons.state]
    grant = cons.grant[cons.state]
    assert len(grant.tokens) == 1
    token = grant.tokens[0]
    assert token.access_token == "2YotnFZFEjr1zCsicMWpAA"
예제 #11
0
def test_provider_authenticated():
    provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ,
                        verify_client, symkey=rndstr(16))
    _session_db = {}
    cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True

    location = cons.begin("http://localhost:8087",
                          "http://localhost:8088/authorization")

    query_string = location.split("?")[1]

    resp = provider.authorization_endpoint(query_string)
    assert resp.status == "302 Found"
    print resp.headers
    print resp.message
    if content_type(resp.headers) == "json":
        resp = resp.message
    else:
        resp = resp.message.split("?")[1]
    aresp = cons.handle_authorization_response(query=resp)

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

    print cons.grant[cons.state].keys()
    assert _eq(cons.grant[cons.state].keys(), ['tokens', 'code', 'exp_in',
                                               'seed', 'id_token',
                                               'grant_expiration_time'])
예제 #12
0
 def create_consumer(self):
     self.consumer = Consumer(
         DictSessionBackend(),
         client_config=CLIENT_CONFIG,
         server_info=SERVER_INFO,
         settings=CLIENT_SETTINGS,
         **CONSUMER_CONFIG,
     )
예제 #13
0
def test_consumer_client_auth_info():
    _session_db = {}
    cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.client_secret = "secret0"
    ra, ha, extra = cons.client_auth_info()
    assert ra == {'client_secret': 'secret0', 'client_id': 'number5'}
    assert ha == {}
    assert extra == {'auth_method': 'bearer_body'}
예제 #14
0
def handle_authz_response(environ, start_response):
    _cli = Consumer(SESSION_DB, CLIENT_CONFIG, SERVER_INFO, **CONSUMER_CONFIG)
    aresp = _cli.parse_authz(environ, start_response, DEVNULL())
    print "ARESP: %s" % aresp

    kaka = http_util.cookie(CLIENT_CONFIG["client_id"], aresp.state, _cli.seed,
                            expire=360, path="/")

    resp = http_util.Response("Your will is registered", headers=[kaka])
    return resp(environ, start_response)
예제 #15
0
 def test_provider_config(self):
     c = Consumer(None, None)
     response = ASConfigurationResponse(**{'issuer': 'https://example.com',
                                           'end_session_endpoint': 'https://example.com/end_session'})
     with responses.RequestsMock() as rsps:
         rsps.add(responses.GET, 'https://example.com/.well-known/openid-configuration', json=response.to_dict())
         info = c.provider_config('https://example.com')
     assert isinstance(info, ASConfigurationResponse)
     assert _eq(info.keys(), ['issuer', 'version', 'end_session_endpoint'])
     assert info["end_session_endpoint"] == "https://example.com/end_session"
예제 #16
0
def test_consumer_client_get_access_token_reques():
    _session_db = {}
    cons = Consumer(_session_db,
                    client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO,
                    **CONSUMER_CONFIG)
    cons.client_secret = "secret0"
    _state = "state"
    cons.redirect_uris = ["https://www.example.com/oic/cb"]

    resp1 = AuthorizationResponse(code="auth_grant", state=_state)
    cons.parse_response(AuthorizationResponse, resp1.to_urlencoded(),
                        "urlencoded")
    resp2 = AccessTokenResponse(access_token="token1",
                                token_type="Bearer",
                                expires_in=0,
                                state=_state)
    cons.parse_response(AccessTokenResponse, resp2.to_urlencoded(),
                        "urlencoded")

    url, body, http_args = cons.get_access_token_request(_state)
    url_obj = URLObject.create(url)
    expected_url_obj = URLObject.create("http://localhost:8088/token")
    assert url_obj == expected_url_obj
    body_splits = body.split('&')
    expected_body_splits = "code=auth_grant&client_secret=secret0&" \
                    "grant_type=authorization_code&client_id=number5&" \
                    "redirect_uri=https%3A%2F%2Fwww.example.com%2Foic%2Fcb".split('&')
    assert set(body_splits) == set(expected_body_splits)
    assert http_args == {
        'headers': {
            'Content-type': 'application/x-www-form-urlencoded'
        }
    }
예제 #17
0
def test_consumer_client_get_access_token_reques():
    _session_db = {}
    cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.client_secret = "secret0"
    cons.state = "state"
    cons.redirect_uris = ["https://www.example.com/oic/cb"]

    resp1 = AuthorizationResponse(code="auth_grant", state="state")
    cons.parse_response(AuthorizationResponse, resp1.to_urlencoded(),
                        "urlencoded")
    resp2 = AccessTokenResponse(access_token="token1",
                                token_type="Bearer", expires_in=0,
                                state="state")
    cons.parse_response(AccessTokenResponse, resp2.to_urlencoded(),
                        "urlencoded")

    url, body, http_args = cons.get_access_token_request()
    assert url == "http://localhost:8088/token"
    print body
    assert body == ("code=auth_grant&client_secret=secret0&"
                    "grant_type=authorization_code&client_id=number5&"
                    "redirect_uri=https%3A%2F%2Fwww.example.com%2Foic%2Fcb")
    assert http_args == {'headers': {
        'content-type': 'application/x-www-form-urlencoded'}}
예제 #18
0
    def test_authenticated(self):
        _session_db = DictSessionBackend()
        cons = Consumer(
            _session_db,
            client_config=CLIENT_CONFIG,
            server_info=SERVER_INFO,
            **CONSUMER_CONFIG,
        )

        sid, location = cons.begin("http://localhost:8087",
                                   "http://localhost:8088/authorization")

        resp = self.provider.authorization_endpoint(urlparse(location).query)
        assert resp.status_code == 303
        resp = urlparse(resp.message).query
        with LogCapture(level=logging.DEBUG) as logcap:
            aresp = cons.handle_authorization_response(query=resp)

        assert isinstance(aresp, AuthorizationResponse)
        assert _eq(aresp.keys(), ["state", "code", "client_id", "iss"])
        assert _eq(
            cons.grant[sid].keys(),
            [
                "tokens", "code", "exp_in", "seed", "id_token",
                "grant_expiration_time"
            ],
        )

        state = aresp["state"]
        assert _eq(logcap.records[0].msg, "- authorization - code flow -")
        assert verify_outcome(
            logcap.records[1].msg,
            "QUERY: ",
            [
                "state={}".format(state),
                "code=<REDACTED>",
                "client_id=client1",
                "iss=https://example.com/as",
            ],
        )

        expected = {
            "iss": "https://example.com/as",
            "state": state,
            "code": "<REDACTED>",
            "client_id": "client1",
        }
        # Eval here to avoid intermittent failures due to dict ordering
        assert _eq(eval(logcap.records[2].msg[29:-1]), expected)
        expected2 = [
            "'client_id': 'client1'",
            "'iss': 'https://example.com/as'",
            "'keyjar': <KeyJar(issuers=[])>",
        ]
        assert _eq(sorted(logcap.records[3].msg[22:-1].split(", ")), expected2)
예제 #19
0
def test_consumer_client_auth_info():
    _session_db = {}
    cons = Consumer(_session_db,
                    client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO,
                    **CONSUMER_CONFIG)
    cons.client_secret = "secret0"
    ra, ha, extra = cons.client_auth_info()
    assert ra == {'client_secret': 'secret0', 'client_id': 'number5'}
    assert ha == {}
    assert extra == {'auth_method': 'bearer_body'}
예제 #20
0
    def test_init(self):
        cons = Consumer({}, client_config=CLIENT_CONFIG,
                        server_info=SERVER_INFO,
                        **CONSUMER_CONFIG)
        cons._backup("123456")
        assert "123456" in cons.sdb

        cons = Consumer({}, client_config=CLIENT_CONFIG, **CONSUMER_CONFIG)
        assert cons.authorization_endpoint is None

        cons = Consumer({}, **CONSUMER_CONFIG)
        assert cons.authorization_endpoint is None
예제 #21
0
    def test_authenticated_token(self):
        _session_db = {}
        cons = Consumer(_session_db, client_config=CLIENT_CONFIG, server_info=SERVER_INFO, **CONSUMER_CONFIG)

        sid, location = cons.begin("http://localhost:8087", "http://localhost:8088/authorization", "token")

        QUERY_STRING = location.split("?")[1]
        resp = self.provider.authorization_endpoint(QUERY_STRING)
        auth_resp = parse_qs(urlparse(resp.message).fragment)

        assert "access_token" in auth_resp
        assert auth_resp["token_type"][0] == "Bearer"
예제 #22
0
def test_consumer_parse_authz_error_2():
    _session_db = {}
    cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True

    _ = cons.begin("http://localhost:8087",
                   "http://localhost:8088/authorization")

    atr = TokenErrorResponse(error="invalid_client")
    QUERY_STRING = atr.to_urlencoded()

    raises(AuthzError,
           "cons.handle_authorization_response(query=QUERY_STRING)")
예제 #23
0
def test_consumer_client_get_access_token_reques():
    _session_db = {}
    cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.client_secret = "secret0"
    _state = "state"
    cons.redirect_uris = ["https://www.example.com/oic/cb"]

    resp1 = AuthorizationResponse(code="auth_grant", state=_state)
    cons.parse_response(AuthorizationResponse, resp1.to_urlencoded(),
                        "urlencoded")
    resp2 = AccessTokenResponse(access_token="token1",
                                token_type="Bearer", expires_in=0,
                                state=_state)
    cons.parse_response(AccessTokenResponse, resp2.to_urlencoded(),
                        "urlencoded")

    url, body, http_args = cons.get_access_token_request(_state)
    url_obj = URLObject.create(url)
    expected_url_obj = URLObject.create("http://localhost:8088/token")
    assert url_obj == expected_url_obj
    body_splits = body.split('&')
    expected_body_splits = "code=auth_grant&client_secret=secret0&" \
                    "grant_type=authorization_code&client_id=number5&" \
                    "redirect_uri=https%3A%2F%2Fwww.example.com%2Foic%2Fcb".split('&')
    assert set(body_splits) == set(expected_body_splits)
    assert http_args == {'headers': {
        'Content-type': 'application/x-www-form-urlencoded'}}
예제 #24
0
    def test_authenticated(self):
        _session_db = {}
        cons = Consumer(_session_db, client_config=CLIENT_CONFIG, server_info=SERVER_INFO, **CONSUMER_CONFIG)

        sid, location = cons.begin("http://localhost:8087", "http://localhost:8088/authorization")

        resp = self.provider.authorization_endpoint(urlparse(location).query)
        assert resp.status == "302 Found"
        resp = urlparse(resp.message).query
        aresp = cons.handle_authorization_response(query=resp)

        assert isinstance(aresp, AuthorizationResponse)
        assert _eq(aresp.keys(), ["state", "code"])
        assert _eq(cons.grant[sid].keys(), ["tokens", "code", "exp_in", "seed", "id_token", "grant_expiration_time"])
예제 #25
0
def test_provider_authenticated_token():
    provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN_BROKER, AUTHZ, verify_client)
    _session_db = {}
    cons = Consumer(_session_db, client_config=CLIENT_CONFIG, server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True

    location = cons.begin("http://localhost:8087", "http://localhost:8088/authorization", "token")

    QUERY_STRING = location.split("?")[1]
    resp = provider.authorization_endpoint(QUERY_STRING)
    print resp.headers
    print resp.message
    txt = resp.message
    assert "access_token=" in txt
    assert "token_type=Bearer" in txt
예제 #26
0
def register(environ, start_response, logger, kaka=None):
    """
    Initialize the OAuth2 flow
    """
    _session_db = environ["oic.sessiondb"]
    _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)

    resp = http_util.Redirect(location)
    return resp(environ, start_response)
예제 #27
0
def test_consumer_parse_authz_error_2():
    _session_db = {}
    cons = Consumer(_session_db, client_config = CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True
    environ = BASE_ENVIRON

    _ = cons.begin(environ, start_response)

    atr = TokenErrorResponse(error="invalid_client")
    environ = BASE_ENVIRON.copy()
    environ["QUERY_STRING"] = atr.to_urlencoded()

    raises(AuthzError,
           "cons.handle_authorization_response(environ, start_response)")
예제 #28
0
    def test_authenticated_token(self):
        _session_db = {}
        cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                        server_info=SERVER_INFO, **CONSUMER_CONFIG)

        sid, location = cons.begin("http://localhost:8087",
                                   "http://localhost:8088/authorization",
                                   "token")

        QUERY_STRING = location.split("?")[1]
        resp = self.provider.authorization_endpoint(QUERY_STRING)
        auth_resp = parse_qs(urlparse(resp.message).fragment)

        assert "access_token" in auth_resp
        assert auth_resp["token_type"][0] == "Bearer"
예제 #29
0
def test_consumer_parse_authz_error_2():
    _session_db = {}
    cons = Consumer(_session_db,
                    client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO,
                    **CONSUMER_CONFIG)
    cons.debug = True

    _ = cons.begin("http://localhost:8087",
                   "http://localhost:8088/authorization")

    atr = TokenErrorResponse(error="invalid_client")
    QUERY_STRING = atr.to_urlencoded()

    raises(AuthzError,
           "cons.handle_authorization_response(query=QUERY_STRING)")
예제 #30
0
파일: oauth.py 프로젝트: its-dirg/SATOSA
    def __init__(self, outgoing, internal_attributes, config, base_url, name, external_type, user_id_attr):
        """
        :param outgoing: Callback should be called by the module after the authorization in the
        backend is done.
        :param internal_attributes: Mapping dictionary between SATOSA internal attribute names and
        the names returned by underlying IdP's/OP's as well as what attributes the calling SP's and
        RP's expects namevice.
        :param config: Configuration parameters for the module.
        :param base_url: base url of the service
        :param name: name of the plugin
        :param external_type: The name for this module in the internal attributes.

        :type outgoing:
        (satosa.context.Context, satosa.internal_data.InternalResponse) -> satosa.response.Response
        :type internal_attributes: dict[string, dict[str, str | list[str]]]
        :type config: dict[str, dict[str, str] | list[str]]
        :type base_url: str
        :type name: str
        :type external_type: str
        """
        super().__init__(outgoing, internal_attributes, base_url, name)
        self.config = config
        self.redirect_url = "%s/%s" % (self.config["base_url"], self.config["authz_page"])
        self.external_type = external_type
        self.user_id_attr = user_id_attr
        self.consumer = Consumer(
            session_db=None,
            client_config=self.config["client_config"],
            server_info=self.config["server_info"],
            authz_page=self.config["authz_page"],
            response_type=self.config["response_type"])
        self.consumer.client_secret = self.config["client_secret"]
예제 #31
0
def test_provider_authenticated():
    provider = Provider("pyoicserv", sdb.SessionDB(), CDB, FUNCTIONS)
    _session_db = {}
    cons = Consumer(_session_db, client_config = CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True
    environ = BASE_ENVIRON

    location = cons.begin(environ, start_response)

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

    resp = provider.authorization_endpoint(environ, start_response)

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

    resp2 = provider.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.split("?")[1]

    aresp = cons.handle_authorization_response(environ, start_response)

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

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

    print cons.grant[cons.state].keys()
    assert _eq(cons.grant[cons.state].keys(), ['tokens', 'code', 'exp_in',
                                               'seed', 'id_token',
                                               'grant_expiration_time'])
예제 #32
0
def authz(environ, start_response, logger, kaka=None):
    """
    This is where I get back to after authentication at the Authorization
    service
    """
    _session_db = environ["oic.sessiondb"]
    _cc = environ["oic.client_config"]
    _conc = environ["oic.consumer.config"]
    _server_info = environ["oic.server.info"]

    _log_info = logger.info

    try:
        _cli = Consumer(_session_db, _conc, _cc, _server_info)
        response = _cli.parse_authz(environ, start_response, logger)
    except (AuthzError, TokenError), err:
        resp = http_util.Unauthorized("%s" % err)
        return resp(environ, start_response)
예제 #33
0
def test_consumer_parse_authz_exception():
    _session_db = {}
    cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True

    sid, loc = cons.begin("http://localhost:8087",
                          "http://localhost:8088/authorization")

    atr = AuthorizationResponse(code="SplxlOBeZQQYbYS6WxSbIA",
                                state=sid)

    adict = atr.to_dict()
    del adict["code"]
    QUERY_STRING = urllib.urlencode(adict)

    raises(MissingRequiredAttribute,
           "cons.handle_authorization_response(query=QUERY_STRING)")
예제 #34
0
파일: oauth.py 프로젝트: borgand/SATOSA
    def get_consumer(self):
        """
        Creates a OAuth 2.0 consumer from a given configuration.

        :param user_id_hash_type: Tells the OAuth consumer how to ask for user id. In oidc can
        pairwise and public be used.

        :type user_id_hash_type: UserIdHashType
        :rtype: Consumer
        :return: An OAuth 2.0 consumer.
        """
        consumer = Consumer(session_db=None,
                            client_config=self.config["client_config"],
                            server_info=self.config["server_info"],
                            authz_page=self.config["authz_page"],
                            response_type=self.config["response_type"])
        consumer.client_secret = self.config["client_secret"]
        return consumer
예제 #35
0
def test_consumer_handle_authorization_response():
    _session_db = {}
    cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True

    sid, loc = cons.begin("http://localhost:8087",
                          "http://localhost:8088/authorization")

    atr = AuthorizationResponse(code="SplxlOBeZQQYbYS6WxSbIA",
                                state=sid)

    res = cons.handle_authorization_response(query=atr.to_urlencoded())

    assert res.type() == "AuthorizationResponse"
    print cons.grant[sid]
    grant = cons.grant[sid]
    assert grant.code == "SplxlOBeZQQYbYS6WxSbIA"
예제 #36
0
def test_consumer_begin():
    _session_db = {}
    cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)

    sid, loc = cons.begin("http://localhost:8087",
                          "http://localhost:8088/authorization")

    # state is dynamic
    params = {"scope": "openid",
              "state": sid,
              "redirect_uri": "http://localhost:8087/authz",
              "response_type": "code",
              "client_id": "number5"}

    url = "http://localhost:8088/authorization?%s" % urllib.urlencode(params)

    assert loc == url
예제 #37
0
def test_factory():
    sdb = {}
    consumer = Consumer(sdb, client_config=CLIENT_CONFIG,
                        server_info=SERVER_INFO, **CONSUMER_CONFIG)
    sid = stateID("https://example.org/", consumer.seed)
    _state = sid
    consumer._backup(sid)
    consumer.sdb["seed:%s" % consumer.seed] = sid

    kaka = make_cookie(CLIENT_CONFIG["client_id"], _state, consumer.seed,
                       expire=360, path="/")

    _oac = factory(kaka[1], sdb, CLIENT_CONFIG["client_id"],
                   client_config=CLIENT_CONFIG, server_info=SERVER_INFO,
                   **CONSUMER_CONFIG)

    assert _oac.client_id == consumer.client_id
    assert _oac.seed == consumer.seed
예제 #38
0
 def test_provider_config(self):
     c = Consumer(None, None)
     response = ASConfigurationResponse(
         **{
             "issuer": "https://example.com",
             "end_session_endpoint": "https://example.com/end_session",
         })
     with responses.RequestsMock() as rsps:
         rsps.add(
             responses.GET,
             "https://example.com/.well-known/openid-configuration",
             json=response.to_dict(),
         )
         info = c.provider_config("https://example.com")
     assert isinstance(info, ASConfigurationResponse)
     assert _eq(info.keys(), ["issuer", "version", "end_session_endpoint"])
     assert info[
         "end_session_endpoint"] == "https://example.com/end_session"
예제 #39
0
    def test_authenticated(self):
        _session_db = {}
        cons = Consumer(_session_db,
                        client_config=CLIENT_CONFIG,
                        server_info=SERVER_INFO,
                        **CONSUMER_CONFIG)

        sid, location = cons.begin("http://localhost:8087",
                                   "http://localhost:8088/authorization")

        resp = self.provider.authorization_endpoint(urlparse(location).query)
        assert resp.status_code == 303
        resp = urlparse(resp.message).query
        with LogCapture(level=logging.DEBUG) as logcap:
            aresp = cons.handle_authorization_response(query=resp)

        assert isinstance(aresp, AuthorizationResponse)
        assert _eq(aresp.keys(), ['state', 'code', 'client_id', 'iss'])
        assert _eq(cons.grant[sid].keys(), [
            'tokens', 'code', 'exp_in', 'seed', 'id_token',
            'grant_expiration_time'
        ])

        state = aresp['state']
        assert _eq(logcap.records[0].msg, '- authorization - code flow -')
        assert verify_outcome(logcap.records[1].msg, 'QUERY: ', [
            'state={}'.format(state), 'code=<REDACTED>', 'client_id=client1',
            'iss=https://example.com/as'
        ])

        expected = {
            'iss': 'https://example.com/as',
            'state': state,
            'code': '<REDACTED>',
            'client_id': 'client1'
        }
        # Eval here to avoid intermittent failures due to dict ordering
        assert _eq(eval(logcap.records[2].msg[29:-1]), expected)
        expected = [
            "'client_id': 'client1'", "'iss': 'https://example.com/as'",
            "'keyjar': <KeyJar(issuers=[])>"
        ]
        assert _eq(sorted(logcap.records[3].msg[22:-1].split(', ')), expected)
예제 #40
0
파일: oauth.py 프로젝트: borgand/SATOSA
    def get_consumer(self):
        """
        Creates a OAuth 2.0 consumer from a given configuration.

        :param user_id_hash_type: Tells the OAuth consumer how to ask for user id. In oidc can
        pairwise and public be used.

        :type user_id_hash_type: UserIdHashType
        :rtype: Consumer
        :return: An OAuth 2.0 consumer.
        """
        consumer = Consumer(
            session_db=None,
            client_config=self.config["client_config"],
            server_info=self.config["server_info"],
            authz_page=self.config["authz_page"],
            response_type=self.config["response_type"])
        consumer.client_secret = self.config["client_secret"]
        return consumer
예제 #41
0
    def test_init(self):
        cons = Consumer({}, client_config=CLIENT_CONFIG,
                        server_info=SERVER_INFO,
                        **CONSUMER_CONFIG)
        cons._backup("123456")
        assert "123456" in cons.sdb

        cons = Consumer({}, client_config=CLIENT_CONFIG, **CONSUMER_CONFIG)
        assert cons.authorization_endpoint is None

        cons = Consumer({}, **CONSUMER_CONFIG)
        assert cons.authorization_endpoint is None
예제 #42
0
def test_consumer_handle_authorization_response():
    _session_db = {}
    cons = Consumer(_session_db,
                    client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO,
                    **CONSUMER_CONFIG)
    cons.debug = True

    sid, loc = cons.begin("http://localhost:8087",
                          "http://localhost:8088/authorization")

    atr = AuthorizationResponse(code="SplxlOBeZQQYbYS6WxSbIA", state=sid)

    res = cons.handle_authorization_response(query=atr.to_urlencoded())

    assert res.type() == "AuthorizationResponse"
    print cons.grant[sid]
    grant = cons.grant[sid]
    assert grant.code == "SplxlOBeZQQYbYS6WxSbIA"
예제 #43
0
def test_consumer_parse_authz_exception():
    _session_db = {}
    cons = Consumer(_session_db,
                    client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO,
                    **CONSUMER_CONFIG)
    cons.debug = True

    sid, loc = cons.begin("http://localhost:8087",
                          "http://localhost:8088/authorization")

    atr = AuthorizationResponse(code="SplxlOBeZQQYbYS6WxSbIA", state=sid)

    adict = atr.to_dict()
    del adict["code"]
    QUERY_STRING = urllib.urlencode(adict)

    raises(MissingRequiredAttribute,
           "cons.handle_authorization_response(query=QUERY_STRING)")
예제 #44
0
def test_consumer_parse_authz_exception():
    _session_db = {}
    cons = Consumer(_session_db, client_config = CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True
    environ = BASE_ENVIRON

    _ = cons.begin(environ, start_response)

    atr = AuthorizationResponse(code="SplxlOBeZQQYbYS6WxSbIA",
                                state=cons.state)
    
    adict = atr.to_dict()
    del adict["code"]
    environ = BASE_ENVIRON.copy()
    environ["QUERY_STRING"] = urllib.urlencode(adict)

    raises(MissingRequiredAttribute,
           "cons.handle_authorization_response(environ, start_response)")
예제 #45
0
def test_provider_authenticated_1():
    provider = Provider("pyoicserv", sdb.SessionDB(), CDB, FUNCTIONS)
    _session_db = {}
    cons = Consumer(_session_db, client_config = CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True
    environ = BASE_ENVIRON

    location = cons.begin(environ, start_response)

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

    _ = provider.authorization_endpoint(environ, start_response)

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

    resp2 = provider.authenticated(environ2, start_response)
    print resp2
    assert resp2 == ['<html>Unknown session identifier</html>']
예제 #46
0
def test_consumer_handle_authorization_response():
    _session_db = {}
    cons = Consumer(_session_db, client_config = CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True
    environ = BASE_ENVIRON

    _ = cons.begin(environ, start_response)

    atr = AuthorizationResponse(code="SplxlOBeZQQYbYS6WxSbIA",
                                state=cons.state)

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

    res = cons.handle_authorization_response(environ, start_response)

    assert res.type() == "AuthorizationResponse"
    print cons.grant[cons.state]
    grant = cons.grant[cons.state]
    assert grant.code == "SplxlOBeZQQYbYS6WxSbIA"
예제 #47
0
    def test_authenticated(self):
        _session_db = {}
        cons = Consumer(_session_db,
                        client_config=CLIENT_CONFIG,
                        server_info=SERVER_INFO,
                        **CONSUMER_CONFIG)

        sid, location = cons.begin("http://localhost:8087",
                                   "http://localhost:8088/authorization")

        resp = self.provider.authorization_endpoint(urlparse(location).query)
        assert resp.status == "302 Found"
        resp = urlparse(resp.message).query
        aresp = cons.handle_authorization_response(query=resp)

        assert isinstance(aresp, AuthorizationResponse)
        assert _eq(aresp.keys(), ['state', 'code'])
        assert _eq(cons.grant[sid].keys(), [
            'tokens', 'code', 'exp_in', 'seed', 'id_token',
            'grant_expiration_time'
        ])
예제 #48
0
def test_consumer_parse_access_token():
    # implicit flow test
    _session_db = {}
    cons = Consumer(_session_db,
                    client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO,
                    **CONSUMER_CONFIG)
    cons.debug = True
    environ = BASE_ENVIRON

    cons.response_type = ["token"]
    _ = cons.begin("http://localhost:8087",
                   "http://localhost:8088/authorization")

    atr = AccessTokenResponse(access_token="2YotnFZFEjr1zCsicMWpAA",
                              token_type="example",
                              refresh_token="tGzv3JOkF0XG5Qx2TlKWIA",
                              example_parameter="example_value",
                              state=cons.state)

    res = cons.handle_authorization_response(query=atr.to_urlencoded())

    assert res.type() == "AccessTokenResponse"
    print cons.grant[cons.state]
    grant = cons.grant[cons.state]
    assert len(grant.tokens) == 1
    token = grant.tokens[0]
    assert token.access_token == "2YotnFZFEjr1zCsicMWpAA"
예제 #49
0
def test_consumer_begin():
    _session_db = {}
    cons = Consumer(_session_db,
                    client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO,
                    **CONSUMER_CONFIG)

    loc = cons.begin("http://localhost:8087",
                     "http://localhost:8088/authorization")

    # state is dynamic
    params = {
        "scope": "openid",
        "state": cons.state,
        "redirect_uri": "http://localhost:8087/authz",
        "response_type": "code",
        "client_id": "number5"
    }

    url = "http://localhost:8088/authorization?%s" % urllib.urlencode(params)

    assert loc == url
예제 #50
0
def test_provider_authenticated():
    provider = Provider("pyoicserv",
                        sdb.SessionDB(),
                        CDB,
                        AUTHN_BROKER,
                        AUTHZ,
                        verify_client,
                        symkey=rndstr(16))
    _session_db = {}
    cons = Consumer(_session_db,
                    client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO,
                    **CONSUMER_CONFIG)
    cons.debug = True

    location = cons.begin("http://localhost:8087",
                          "http://localhost:8088/authorization")

    query_string = location.split("?")[1]

    resp = provider.authorization_endpoint(query_string)
    assert resp.status == "302 Found"
    print resp.headers
    print resp.message
    if content_type(resp.headers) == "json":
        resp = resp.message
    else:
        resp = resp.message.split("?")[1]
    aresp = cons.handle_authorization_response(query=resp)

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

    print cons.grant[cons.state].keys()
    assert _eq(cons.grant[cons.state].keys(), [
        'tokens', 'code', 'exp_in', 'seed', 'id_token', 'grant_expiration_time'
    ])
예제 #51
0
def test_provider_authenticated_none():
    provider = Provider("pyoicserv", sdb.SessionDB(), CDB, AUTHN, AUTHZ,
                        verify_client)
    _session_db = {}
    cons = Consumer(_session_db, client_config=CLIENT_CONFIG,
                    server_info=SERVER_INFO, **CONSUMER_CONFIG)
    cons.debug = True

    location = cons.begin("http://localhost:8087",
                          "http://localhost:8088/authorization",
                          "none")

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

    resp2 = provider.authorization_endpoint(request=QUERY_STRING)

    location = resp2.message
    print location

    assert location.startswith("http://localhost:8087/authz")
    query = location.split("?")[1]
    assert query.startswith("state=")
    assert "&" not in query
예제 #52
0
    def test_init(self):
        cons = Consumer(
            DictSessionBackend(),
            client_config=CLIENT_CONFIG,
            server_info=SERVER_INFO,
            settings=CLIENT_SETTINGS,
            **CONSUMER_CONFIG,
        )
        cons._backup("123456")
        assert "123456" in cons.sdb

        cons = Consumer(
            DictSessionBackend(),
            client_config=CLIENT_CONFIG,
            settings=CLIENT_SETTINGS,
            **CONSUMER_CONFIG,
        )
        assert cons.authorization_endpoint is None

        cons = Consumer(DictSessionBackend, **CONSUMER_CONFIG)
        assert cons.authorization_endpoint is None
예제 #53
0
def register(environ, start_response):
    _oac = Consumer(SESSION_DB, CLIENT_CONFIG, SERVER_INFO, **CONSUMER_CONFIG)
    location = _oac.begin(environ, start_response, DEVNULL())
    resp = http_util.Redirect(location)
    return resp(environ, start_response)
예제 #54
0
class TestConsumer(object):
    @pytest.fixture(autouse=True)
    def create_consumer(self):
        self.consumer = Consumer({},
                                 client_config=CLIENT_CONFIG,
                                 server_info=SERVER_INFO,
                                 **CONSUMER_CONFIG)

    def test_init(self):
        cons = Consumer({},
                        client_config=CLIENT_CONFIG,
                        server_info=SERVER_INFO,
                        **CONSUMER_CONFIG)
        cons._backup("123456")
        assert "123456" in cons.sdb

        cons = Consumer({}, client_config=CLIENT_CONFIG, **CONSUMER_CONFIG)
        assert cons.authorization_endpoint is None

        cons = Consumer({}, **CONSUMER_CONFIG)
        assert cons.authorization_endpoint is None

    def test_begin(self):
        sid, loc = self.consumer.begin("http://localhost:8087",
                                       "http://localhost:8088/authorization")

        # state is dynamic
        params = {
            "scope": "openid",
            "state": sid,
            "redirect_uri": "http://localhost:8087/authz",
            "response_type": "code",
            "client_id": "number5"
        }

        url = "http://localhost:8088/authorization?{}".format(
            urlencode(params))
        assert url_compare(loc, url)

    def test_handle_authorization_response(self):
        sid, loc = self.consumer.begin("http://localhost:8087",
                                       "http://localhost:8088/authorization")

        atr = AuthorizationResponse(code="SplxlOBeZQQYbYS6WxSbIA", state=sid)

        res = self.consumer.handle_authorization_response(
            query=atr.to_urlencoded())

        assert isinstance(res, AuthorizationResponse)
        assert self.consumer.grant[sid].code == "SplxlOBeZQQYbYS6WxSbIA"

    def test_parse_authz_without_code(self):
        sid, loc = self.consumer.begin("http://localhost:8087",
                                       "http://localhost:8088/authorization")

        atr = AuthorizationResponse(code="SplxlOBeZQQYbYS6WxSbIA", state=sid)

        adict = atr.to_dict()
        del adict["code"]

        with pytest.raises(MissingRequiredAttribute):
            self.consumer.handle_authorization_response(query=urlencode(adict))

    def test_parse_authz_access_denied(self):
        sid, loc = self.consumer.begin("http://localhost:8087",
                                       "http://localhost:8088/authorization")

        atr = AuthorizationErrorResponse(error="access_denied", state=sid)

        with pytest.raises(AuthzError):
            self.consumer.handle_authorization_response(
                query=atr.to_urlencoded())

    def test_parse_access_token(self):
        # implicit flow test
        self.consumer.response_type = ["token"]
        sid, loc = self.consumer.begin("http://localhost:8087",
                                       "http://localhost:8088/authorization")

        atr = AccessTokenResponse(access_token="2YotnFZFEjr1zCsicMWpAA",
                                  token_type="example",
                                  refresh_token="tGzv3JOkF0XG5Qx2TlKWIA",
                                  example_parameter="example_value",
                                  state=sid)

        res = self.consumer.handle_authorization_response(
            query=atr.to_urlencoded())

        assert isinstance(res, AccessTokenResponse)
        grant = self.consumer.grant[sid]
        assert len(grant.tokens) == 1
        token = grant.tokens[0]
        assert token.access_token == "2YotnFZFEjr1zCsicMWpAA"

    def test_parse_authz_invalid_client(self):
        self.consumer.begin("http://localhost:8087",
                            "http://localhost:8088/authorization")

        atr = TokenErrorResponse(error="invalid_client")

        with pytest.raises(AuthzError):
            self.consumer.handle_authorization_response(
                query=atr.to_urlencoded())

    def test_consumer_client_auth_info(self):
        self.consumer.client_secret = "secret0"
        ra, ha, extra = self.consumer.client_auth_info()
        assert ra == {'client_secret': 'secret0', 'client_id': 'number5'}
        assert ha == {}
        assert extra == {'auth_method': 'bearer_body'}

    def test_client_get_access_token_request(self):
        self.consumer.client_secret = "secret0"
        _state = "state"
        self.consumer.redirect_uris = ["https://www.example.com/oic/cb"]

        resp1 = AuthorizationResponse(code="auth_grant", state=_state)
        self.consumer.parse_response(AuthorizationResponse,
                                     resp1.to_urlencoded(), "urlencoded")
        resp2 = AccessTokenResponse(access_token="token1",
                                    token_type="Bearer",
                                    expires_in=0,
                                    state=_state)
        self.consumer.parse_response(AccessTokenResponse,
                                     resp2.to_urlencoded(), "urlencoded")

        url, body, http_args = self.consumer.get_access_token_request(_state)
        assert url_compare(url, "http://localhost:8088/token")
        expected_params = 'redirect_uri=https%3A%2F%2Fwww.example.com%2Foic%2Fcb&client_id=number5&state=state&' \
                          'code=auth_grant&grant_type=authorization_code&client_secret=secret0'

        assert query_string_compare(body, expected_params)
        assert http_args == {
            'headers': {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        }
예제 #55
0
 def create_consumer(self):
     self.consumer = Consumer({},
                              client_config=CLIENT_CONFIG,
                              server_info=SERVER_INFO,
                              **CONSUMER_CONFIG)
예제 #56
0
파일: rp.py 프로젝트: zack53/pyoidc
    # is run.
    sys.path.insert(0, ".")
    # If a specific configuration directory is specified look there first
    if args.conf_path:
        sys.path.insert(0, args.conf_path)
    RP_CONF = importlib.import_module(args.config)

    # per AS instantiate a consumer
    for name, info in RP_CONF.AS_CONF.items():
        c_conf = {"client_id": info["client_id"]}

        CONSUMER[name] = Consumer(session_db={},
                                  client_config=c_conf,
                                  server_info={
                                      "authorization_endpoint":
                                      info["authorization_endpoint"],
                                      "token_endpoint":
                                      info["token_endpoint"]
                                  },
                                  authz_page="authz_cb",
                                  response_type="code")

        CONSUMER[name].client_secret = info["client_secret"]

    SRV = wsgiserver.CherryPyWSGIServer(
        ('0.0.0.0', RP_CONF.PORT), SessionMiddleware(application,
                                                     session_opts))

    if RP_CONF.BASE.startswith("https"):
        from cherrypy.wsgiserver import ssl_pyopenssl

        SRV.ssl_adapter = ssl_pyopenssl.pyOpenSSLAdapter(
예제 #57
0
class _OAuthBackend(BackendModule):
    """
    Backend module for OAuth 2.0, should not be directly used.
    See satosa.backends.oauth.FacebookBackend.
    """
    def __init__(self, outgoing, internal_attributes, config, base_url, name,
                 external_type, user_id_attr):
        """
        :param outgoing: Callback should be called by the module after the authorization in the
        backend is done.
        :param internal_attributes: Mapping dictionary between SATOSA internal attribute names and
        the names returned by underlying IdP's/OP's as well as what attributes the calling SP's and
        RP's expects namevice.
        :param config: Configuration parameters for the module.
        :param base_url: base url of the service
        :param name: name of the plugin
        :param external_type: The name for this module in the internal attributes.

        :type outgoing:
        (satosa.context.Context, satosa.internal.InternalData) -> satosa.response.Response
        :type internal_attributes: dict[string, dict[str, str | list[str]]]
        :type config: dict[str, dict[str, str] | list[str]]
        :type base_url: str
        :type name: str
        :type external_type: str
        """
        super().__init__(outgoing, internal_attributes, base_url, name)
        self.config = config
        self.redirect_url = "%s/%s" % (self.config["base_url"],
                                       self.config["authz_page"])
        self.external_type = external_type
        self.user_id_attr = user_id_attr
        self.consumer = Consumer(session_db=None,
                                 client_config=self.config["client_config"],
                                 server_info=self.config["server_info"],
                                 authz_page=self.config["authz_page"],
                                 response_type=self.config["response_type"])
        self.consumer.client_secret = self.config["client_secret"]

    def start_auth(self, context, internal_request, get_state=stateID):
        """
        See super class method satosa.backends.base#start_auth
        :param get_state: Generates a state to be used in the authentication call.

        :type get_state: Callable[[str, bytes], str]
        :type context: satosa.context.Context
        :type internal_request: satosa.internal.InternalData
        :rtype satosa.response.Redirect
        """
        request_args = self.get_request_args(get_state=get_state)
        context.state[self.name] = {"state": request_args["state"]}
        cis = self.consumer.construct_AuthorizationRequest(
            request_args=request_args)
        return Redirect(cis.request(self.consumer.authorization_endpoint))

    def get_request_args(self, get_state=stateID):
        oauth_state = get_state(self.config["base_url"], rndstr().encode())
        request_args = {
            "redirect_uri": self.redirect_url,
            "state": oauth_state,
        }
        return request_args

    def register_endpoints(self):
        """
        Creates a list of all the endpoints this backend module needs to listen to. In this case
        it's the authentication response from the underlying OP that is redirected from the OP to
        the proxy.
        :rtype: Sequence[(str, Callable[[satosa.context.Context], satosa.response.Response]]
        :return: A list that can be used to map the request to SATOSA to this endpoint.
        """
        return [("^%s$" % self.config["authz_page"], self._authn_response)]

    def _verify_state(self, resp, state_data, state):
        """
        Will verify the state and throw and error if the state is invalid.
        :type resp: AuthorizationResponse
        :type state_data: dict[str, str]
        :type state: satosa.state.State

        :param resp: The authorization response from the AS, created by pyoidc.
        :param state_data: The state data for this backend.
        :param state: The current state for the proxy and this backend.
        Only used for raising errors.
        """
        is_known_state = "state" in resp and "state" in state_data and resp[
            "state"] == state_data["state"]
        if not is_known_state:
            received_state = resp.get("state", "")
            msg = "Missing or invalid state [{}] in response!".format(
                received_state)
            logline = lu.LOG_FMT.format(id=lu.get_session_id(state),
                                        message=msg)
            logger.debug(logline)
            raise SATOSAAuthenticationError(
                state,
                "Missing or invalid state [%s] in response!" % received_state)

    def _authn_response(self, context):
        """
        Handles the authentication response from the AS.

        :type context: satosa.context.Context
        :rtype: satosa.response.Response
        :param context: The context in SATOSA
        :return: A SATOSA response. This method is only responsible to call the callback function
        which generates the Response object.
        """
        state_data = context.state[self.name]
        aresp = self.consumer.parse_response(AuthorizationResponse,
                                             info=json.dumps(context.request))
        self._verify_state(aresp, state_data, context.state)

        rargs = {
            "code": aresp["code"],
            "redirect_uri": self.redirect_url,
            "state": state_data["state"]
        }

        atresp = self.consumer.do_access_token_request(request_args=rargs,
                                                       state=aresp["state"])
        if "verify_accesstoken_state" not in self.config or self.config[
                "verify_accesstoken_state"]:
            self._verify_state(atresp, state_data, context.state)

        user_info = self.user_information(atresp["access_token"])
        internal_response = InternalData(
            auth_info=self.auth_info(context.request))
        internal_response.attributes = self.converter.to_internal(
            self.external_type, user_info)
        internal_response.subject_id = user_info[self.user_id_attr]
        del context.state[self.name]
        return self.auth_callback_func(context, internal_response)

    def auth_info(self, request):
        """
        Creates the SATOSA authentication information object.
        :type request: dict[str, str]
        :rtype: AuthenticationInformation

        :param request: The request parameters in the authentication response sent by the AS.
        :return: How, who and when the autentication took place.
        """
        raise NotImplementedError(
            "Method 'auth_info' must be implemented in the subclass!")

    def user_information(self, access_token):
        """
        Will retrieve the user information data for the authenticated user.
        :type access_token: str
        :rtype: dict[str, str]

        :param access_token: The access token to be used to retrieve the data.
        :return: Dictionary with attribute name as key and attribute value as value.
        """
        raise NotImplementedError(
            "Method 'user_information' must be implemented in the subclass!")

    def get_metadata_desc(self):
        """
        See satosa.backends.oauth.get_metadata_desc
        :rtype: satosa.metadata_creation.description.MetadataDescription
        """
        return get_metadata_desc_for_oauth_backend(
            self.config["server_info"]["authorization_endpoint"], self.config)
예제 #58
0
class TestConsumer(object):
    @pytest.fixture(autouse=True)
    def create_consumer(self):
        self.consumer = Consumer(
            DictSessionBackend(),
            client_config=CLIENT_CONFIG,
            server_info=SERVER_INFO,
            settings=CLIENT_SETTINGS,
            **CONSUMER_CONFIG,
        )

    def test_init(self):
        cons = Consumer(
            DictSessionBackend(),
            client_config=CLIENT_CONFIG,
            server_info=SERVER_INFO,
            settings=CLIENT_SETTINGS,
            **CONSUMER_CONFIG,
        )
        cons._backup("123456")
        assert "123456" in cons.sdb

        cons = Consumer(
            DictSessionBackend(),
            client_config=CLIENT_CONFIG,
            settings=CLIENT_SETTINGS,
            **CONSUMER_CONFIG,
        )
        assert cons.authorization_endpoint is None

        cons = Consumer(DictSessionBackend, **CONSUMER_CONFIG)
        assert cons.authorization_endpoint is None

    def test_begin(self):
        sid, loc = self.consumer.begin("http://localhost:8087",
                                       "http://localhost:8088/authorization")

        # state is dynamic
        params = {
            "scope": "openid",
            "state": sid,
            "redirect_uri": "http://localhost:8087/authz",
            "response_type": "code",
            "client_id": "number5",
        }

        url = "http://localhost:8088/authorization?{}".format(
            urlencode(params))
        assert url_compare(loc, url)

    def test_handle_authorization_response(self):
        sid, loc = self.consumer.begin("http://localhost:8087",
                                       "http://localhost:8088/authorization")

        atr = AuthorizationResponse(code="SplxlOBeZQQYbYS6WxSbIA", state=sid)

        res = self.consumer.handle_authorization_response(
            query=atr.to_urlencoded())

        assert isinstance(res, AuthorizationResponse)
        assert self.consumer.grant[sid].code == "SplxlOBeZQQYbYS6WxSbIA"

    def test_parse_authz_without_code(self):
        sid, loc = self.consumer.begin("http://localhost:8087",
                                       "http://localhost:8088/authorization")

        atr = AuthorizationResponse(code="SplxlOBeZQQYbYS6WxSbIA", state=sid)

        adict = atr.to_dict()
        del adict["code"]

        with pytest.raises(MissingRequiredAttribute):
            self.consumer.handle_authorization_response(query=urlencode(adict))

    def test_parse_authz_access_denied(self):
        sid, loc = self.consumer.begin("http://localhost:8087",
                                       "http://localhost:8088/authorization")

        atr = AuthorizationErrorResponse(error="access_denied", state=sid)

        with pytest.raises(AuthzError):
            self.consumer.handle_authorization_response(
                query=atr.to_urlencoded())

    def test_parse_access_token(self):
        # implicit flow test
        self.consumer.response_type = ["token"]
        sid, loc = self.consumer.begin("http://localhost:8087",
                                       "http://localhost:8088/authorization")

        atr = AccessTokenResponse(
            access_token="2YotnFZFEjr1zCsicMWpAA",
            token_type="example",
            refresh_token="tGzv3JOkF0XG5Qx2TlKWIA",
            example_parameter="example_value",
            state=sid,
        )

        res = self.consumer.handle_authorization_response(
            query=atr.to_urlencoded())

        assert isinstance(res, AccessTokenResponse)
        grant = self.consumer.grant[sid]
        assert len(grant.tokens) == 1
        token = grant.tokens[0]
        assert token.access_token == "2YotnFZFEjr1zCsicMWpAA"

    def test_parse_authz_invalid_client(self):
        self.consumer.begin("http://localhost:8087",
                            "http://localhost:8088/authorization")

        atr = TokenErrorResponse(error="invalid_client")

        with pytest.raises(AuthzError):
            self.consumer.handle_authorization_response(
                query=atr.to_urlencoded())

    def test_consumer_client_auth_info(self):
        self.consumer.client_secret = "secret0"
        ra, ha, extra = self.consumer.client_auth_info()
        assert ra == {"client_secret": "secret0", "client_id": "number5"}
        assert ha == {}
        assert extra == {"auth_method": "bearer_body"}

    def test_provider_config(self):
        c = Consumer(None, None)
        response = ASConfigurationResponse(
            **{
                "issuer": "https://example.com",
                "end_session_endpoint": "https://example.com/end_session",
            })
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                "https://example.com/.well-known/openid-configuration",
                json=response.to_dict(),
            )
            info = c.provider_config("https://example.com")
        assert isinstance(info, ASConfigurationResponse)
        assert _eq(info.keys(), ["issuer", "version", "end_session_endpoint"])
        assert info[
            "end_session_endpoint"] == "https://example.com/end_session"

    def test_client_get_access_token_request(self):
        self.consumer.client_secret = "secret0"
        _state = "state"
        self.consumer.redirect_uris = ["https://www.example.com/oic/cb"]

        resp1 = AuthorizationResponse(code="auth_grant", state=_state)
        self.consumer.parse_response(AuthorizationResponse,
                                     resp1.to_urlencoded(), "urlencoded")
        resp2 = AccessTokenResponse(access_token="token1",
                                    token_type="Bearer",
                                    expires_in=0,
                                    state=_state)
        self.consumer.parse_response(AccessTokenResponse,
                                     resp2.to_urlencoded(), "urlencoded")

        url, body, http_args = self.consumer.get_access_token_request(_state)
        assert url_compare(url, "http://localhost:8088/token")
        expected_params = (
            "redirect_uri=https%3A%2F%2Fwww.example.com%2Foic%2Fcb&client_id=number5&state=state&"
            "code=auth_grant&grant_type=authorization_code&client_secret=secret0"
        )

        assert query_string_compare(body, expected_params)
        assert http_args == {
            "headers": {
                "Content-Type": "application/x-www-form-urlencoded"
            }
        }

    def test_access_token_storage_with_custom_response_class(self):
        _state = "state"

        # AccessTokenResponse custom class
        class AccessTokenResponseWrapper(AccessTokenResponse):
            """Response wrapper to get "expires_in" in hours."""

            c_param = AccessTokenResponse.c_param.copy()
            c_param.update({"expires_in_hours": SINGLE_OPTIONAL_INT})

            def __init__(self, **kwargs):
                super(AccessTokenResponseWrapper, self).__init__(**kwargs)
                if "expires_in" in self and self["expires_in"]:
                    self["expires_in_hours"] = self["expires_in"] // 3600

        resp = AccessTokenResponseWrapper(
            access_token="2YotnFZFEjr1zCsiAB",
            token_type="Bearer",
            expires_in=3600,
            state=_state,
        )
        self.consumer.parse_response(AccessTokenResponseWrapper,
                                     resp.to_urlencoded(), "urlencoded")

        grant = self.consumer.grant[_state]
        assert len(grant.tokens) == 1
        assert grant.tokens[0].access_token == "2YotnFZFEjr1zCsiAB"
        assert grant.tokens[
            0].token_expiration_time > time_util.time_sans_frac()
        assert grant.tokens[0].expires_in_hours == 1  # type: ignore