コード例 #1
0
def retrieve_jwks(jwks_url, httpFactory=Http):
    """
    Retrieves the potential keys used to sign issued tokens from the OP.
    """
    http = httpFactory()

    _, content = http.request(jwks_url)

    return JWKSet.from_json(content)
コード例 #2
0
    def jwkset(self):
        from authentic2.crypto import base64url_encode

        if self.idtoken_algo == self.ALGO_RSA:
            if self.jwkset_json:
                return JWKSet.from_json(json.dumps(self.jwkset_json))
        if self.idtoken_algo == self.ALGO_HMAC:
            return JWK(kty='oct',
                       k=base64url_encode(self.client_secret.encode('utf-8')))
        return None
コード例 #3
0
def _fetch_certs():
    """
    Fetches and caches certs
    :return: Google's OAuth2 server certs
    """
    global CACHED_CERTS
    if not CACHED_CERTS:
        resp = requests.get(JWKS_URI_ENDPOINT)
        key_set = JWKSet.from_json(resp.content)
        CACHED_CERTS = [k.export_to_pem() for k in key_set]
    return CACHED_CERTS
コード例 #4
0
def get_jwkset():
    try:
        jwkset = json.dumps(app_settings.JWKSET)
    except Exception as e:
        raise ImproperlyConfigured('invalid setting A2_IDP_OIDC_JWKSET: %s' %
                                   e)
    try:
        jwkset = JWKSet.from_json(jwkset)
    except InvalidJWKValue as e:
        raise ImproperlyConfigured('invalid setting A2_IDP_OIDC_JWKSET: %s' %
                                   e)
    if len(jwkset['keys']) < 1:
        raise ImproperlyConfigured('empty A2_IDP_OIDC_JWKSET')
    return jwkset
コード例 #5
0
 def get_keys(self):
     if self.jwks:
         return JWKSet.from_json(self.jwks)
     return JWKSet()
コード例 #6
0
def test_role_control_access(login_first, oidc_settings, oidc_client, simple_user, app):
    # authorized_role
    role_authorized = get_role_model().objects.create(
        name='Goth Kids', slug='goth-kids', ou=get_default_ou())
    oidc_client.add_authorized_role(role_authorized)

    redirect_uri = oidc_client.redirect_uris.split()[0]
    params = {
        'client_id': oidc_client.client_id,
        'scope': 'openid profile email',
        'redirect_uri': redirect_uri,
        'state': 'xxx',
        'nonce': 'yyy',
    }

    if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
        params['response_type'] = 'code'
    elif oidc_client.authorization_flow == oidc_client.FLOW_IMPLICIT:
        params['response_type'] = 'token id_token'
    authorize_url = make_url('oidc-authorize', params=params)

    if login_first:
        utils.login(app, simple_user)

    # user not authorized
    response = app.get(authorize_url)
    assert 'https://example.com/southpark/' in response.content

    # user authorized
    simple_user.roles.add(role_authorized)
    simple_user.save()
    response = app.get(authorize_url)

    if not login_first:
        response = response.follow()
        response.form.set('username', simple_user.username)
        response.form.set('password', simple_user.username)
        response = response.form.submit(name='login-password-submit')
        response = response.follow()
    if oidc_client.authorization_mode != oidc_client.AUTHORIZATION_MODE_NONE:
        response = response.form.submit('accept')
        assert OIDCAuthorization.objects.get()
    if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
        code = OIDCCode.objects.get()
    location = urlparse.urlparse(response['Location'])
    if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
        query = urlparse.parse_qs(location.query)
        code = query['code'][0]
        token_url = make_url('oidc-token')
        response = app.post(token_url, params={
            'grant_type': 'authorization_code',
            'code': code,
            'redirect_uri': oidc_client.redirect_uris.split()[0],
        }, headers=client_authentication_headers(oidc_client))
        id_token = response.json['id_token']
    elif oidc_client.authorization_flow == oidc_client.FLOW_IMPLICIT:
        query = urlparse.parse_qs(location.fragment)
        id_token = query['id_token'][0]

    if oidc_client.idtoken_algo == oidc_client.ALGO_RSA:
        key = JWKSet.from_json(app.get(reverse('oidc-certs')).content)
    elif oidc_client.idtoken_algo == oidc_client.ALGO_HMAC:
        key = JWK(kty='oct', k=base64.b64encode(oidc_client.client_secret.encode('utf-8')))
    else:
        raise NotImplementedError
    jwt = JWT(jwt=id_token, key=key)
    claims = json.loads(jwt.claims)
    if login_first:
        assert claims['acr'] == '0'
    else:
        assert claims['acr'] == '1'
コード例 #7
0
def test_authorization_code_sso(login_first, oidc_settings, oidc_client, simple_user, app):
    redirect_uri = oidc_client.redirect_uris.split()[0]
    params = {
        'client_id': oidc_client.client_id,
        'scope': 'openid profile email',
        'redirect_uri': redirect_uri,
        'state': 'xxx',
        'nonce': 'yyy',
    }

    if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
        params['response_type'] = 'code'
    elif oidc_client.authorization_flow == oidc_client.FLOW_IMPLICIT:
        params['response_type'] = 'token id_token'
    authorize_url = make_url('oidc-authorize', params=params)

    if login_first:
        utils.login(app, simple_user)
    response = app.get(authorize_url)
    if not login_first:
        response = response.follow()
        assert response.request.path == reverse('auth_login')
        response.form.set('username', simple_user.username)
        response.form.set('password', simple_user.username)
        response = response.form.submit(name='login-password-submit')
        response = response.follow()
        assert response.request.path == reverse('oidc-authorize')
    if oidc_client.authorization_mode != OIDCClient.AUTHORIZATION_MODE_NONE:
        assert 'a2-oidc-authorization-form' in response.content
        assert OIDCAuthorization.objects.count() == 0
        assert OIDCCode.objects.count() == 0
        assert OIDCAccessToken.objects.count() == 0
        response = response.form.submit('accept')
        assert OIDCAuthorization.objects.count() == 1
        authz = OIDCAuthorization.objects.get()
        assert authz.client == oidc_client
        assert authz.user == simple_user
        assert authz.scope_set() == set('openid profile email'.split())
        assert authz.expired >= now()
    if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
        assert OIDCCode.objects.count() == 1
        code = OIDCCode.objects.get()
        assert code.client == oidc_client
        assert code.user == simple_user
        assert code.scope_set() == set('openid profile email'.split())
        assert code.state == 'xxx'
        assert code.nonce == 'yyy'
        assert code.redirect_uri == redirect_uri
        assert code.session_key == app.session.session_key
        assert code.auth_time <= now()
        assert code.expired >= now()
    assert response['Location'].startswith(redirect_uri)
    location = urlparse.urlparse(response['Location'])
    if oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
        query = urlparse.parse_qs(location.query)
        assert set(query.keys()) == set(['code', 'state'])
        assert query['code'] == [code.uuid]
        code = query['code'][0]
        assert query['state'] == ['xxx']

        token_url = make_url('oidc-token')
        response = app.post(token_url, params={
            'grant_type': 'authorization_code',
            'code': code,
            'redirect_uri': oidc_client.redirect_uris.split()[0],
        }, headers=client_authentication_headers(oidc_client))
        assert 'error' not in response.json
        assert 'access_token' in response.json
        assert 'expires_in' in response.json
        assert 'id_token' in response.json
        assert response.json['token_type'] == 'Bearer'
        access_token = response.json['access_token']
        id_token = response.json['id_token']
    elif oidc_client.authorization_flow == oidc_client.FLOW_IMPLICIT:
        assert location.fragment
        query = urlparse.parse_qs(location.fragment)
        assert OIDCAccessToken.objects.count() == 1
        access_token = OIDCAccessToken.objects.get()
        assert set(query.keys()) == set(['access_token', 'token_type', 'expires_in', 'id_token',
                                         'state'])
        assert query['access_token'] == [access_token.uuid]
        assert query['token_type'] == ['Bearer']
        assert query['state'] == ['xxx']
        access_token = query['access_token'][0]
        id_token = query['id_token'][0]

    if oidc_client.idtoken_algo == oidc_client.ALGO_RSA:
        key = JWKSet.from_json(app.get(reverse('oidc-certs')).content)
    elif oidc_client.idtoken_algo == oidc_client.ALGO_HMAC:
        key = JWK(kty='oct', k=base64.b64encode(oidc_client.client_secret.encode('utf-8')))
    else:
        raise NotImplementedError
    jwt = JWT(jwt=id_token, key=key)
    claims = json.loads(jwt.claims)
    assert set(claims) >= set(['iss', 'sub', 'aud', 'exp', 'iat', 'nonce', 'auth_time', 'acr'])
    assert claims['nonce'] == 'yyy'
    assert response.request.url.startswith(claims['iss'])
    assert claims['aud'] == oidc_client.client_id
    assert parse_timestamp(claims['iat']) <= now()
    assert parse_timestamp(claims['auth_time']) <= now()
    exp_delta = (parse_timestamp(claims['exp']) - now()).total_seconds()
    assert exp_delta > 0
    if oidc_client.idtoken_duration:
        assert abs(exp_delta - oidc_client.idtoken_duration.total_seconds()) < 2
    else:
        assert abs(exp_delta - 30) < 2

    if login_first:
        assert claims['acr'] == '0'
    else:
        assert claims['acr'] == '1'
    assert claims['sub'] == make_sub(oidc_client, simple_user)
    assert claims['preferred_username'] == simple_user.username
    assert claims['given_name'] == simple_user.first_name
    assert claims['family_name'] == simple_user.last_name
    assert claims['email'] == simple_user.email
    assert claims['email_verified'] is False

    user_info_url = make_url('oidc-user-info')
    response = app.get(user_info_url, headers=bearer_authentication_headers(access_token))
    assert response.json['sub'] == make_sub(oidc_client, simple_user)
    assert response.json['preferred_username'] == simple_user.username
    assert response.json['given_name'] == simple_user.first_name
    assert response.json['family_name'] == simple_user.last_name
    assert response.json['email'] == simple_user.email
    assert response.json['email_verified'] is False

    # when adding extra attributes
    OIDCClaim.objects.create(client=oidc_client, name='ou', value='django_user_ou_name', scopes='profile')
    OIDCClaim.objects.create(client=oidc_client, name='roles', value='a2_role_names', scopes='profile, role')
    simple_user.roles.add(get_role_model().objects.create(
        name='Whatever', slug='whatever', ou=get_default_ou()))
    response = app.get(user_info_url, headers=bearer_authentication_headers(access_token))
    assert response.json['ou'] == simple_user.ou.name
    assert response.json['roles'][0] == 'Whatever'

    # check against a user without username
    simple_user.username = None
    simple_user.save()
    response = app.get(user_info_url, headers=bearer_authentication_headers(access_token))
    assert 'preferred_username' not in response.json

    # Now logout
    if oidc_client.post_logout_redirect_uris:
        params = {
            'post_logout_redirect_uri': oidc_client.post_logout_redirect_uris,
            'state': 'xyz',
        }
        logout_url = make_url('oidc-logout', params=params)
        response = app.get(logout_url)
        assert 'You have been logged out' in response.content
        assert 'https://example.com/?state=xyz' in response.content
        assert '_auth_user_id' not in app.session
    else:
        response = app.get(make_url('account_management'))
        response = response.click('Logout')
        if oidc_client.frontchannel_logout_uri:
            iframes = response.pyquery('iframe[src="https://example.com/southpark/logout/"]')
            assert iframes
            if oidc_client.frontchannel_timeout:
                assert iframes.attr('onload').endswith(', %d)' % oidc_client.frontchannel_timeout)
            else:
                assert iframes.attr('onload').endswith(', 10000)')
コード例 #8
0
def validate_jwkset(data):
    data = json.dumps(data)
    try:
        JWKSet.from_json(data)
    except InvalidJWKValue as e:
        raise ValidationError(_('Invalid JWKSet: %s') % e)
コード例 #9
0
    def get_key(kid: str, jwks_json: str) -> Tuple[str, str]:
        jwk = None
        if jwks_json:
            jwk = JWKSet.from_json(jwks_json).get_key(kid).export_public()

        return jwk, jwks_json