Пример #1
0
def test_jwt_encode(encryption_type):
    with get_test_volttron_home(messagebus='zmq') as vhome:
        if encryption_type == "private_key":
            algorithm = "HS256"
            encoded_key = get_random_key().encode("utf-8")
        else:
            with certs_profile_1(vhome) as certs:
                algorithm = "RS256"
                encoded_key = CertWrapper.get_private_key(
                    certs.server_certs[0].key_file)
        claims = {
            "woot": ["bah"],
            "all I want": 3210,
            "do it next": {
                "foo": "billy"
            }
        }
        token = jwt.encode(claims, encoded_key, algorithm)
        if encryption_type == 'tls':
            decode_key = CertWrapper.get_cert_public_key(
                certs.server_certs[0].cert_file)
            new_claimes = jwt.decode(token, decode_key, algorithm)
        else:
            new_claimes = jwt.decode(token, encoded_key, algorithm)

        assert not DeepDiff(claims, new_claimes)
Пример #2
0
def test_authenticate_get_request_fails():
    with get_test_volttron_home(messagebus='zmq'):
        authorize_ep, test_user = set_test_admin()
        env = get_test_web_env('/authenticate', method='GET')
        response = authorize_ep.handle_authenticate(env, test_user)
        assert ('Content-Type', 'text/plain') in response.headers.items()
        assert '405 Method Not Allowed' in response.status
Пример #3
0
def test_update_platform_config():
    my_config = {"bind-web-address": "http://v2:8080",
                 "vip-address": "tcp://127.0.0.1:22196"}
    with get_test_volttron_home(messagebus='zmq') as vhome:
        # Empty platform config currently (note this wouldn't be if the platform actually has started)
        config = get_platform_config()

        assert 0 == len(config)

        # Test the config is updated
        update_platform_config(my_config)

        # Tests that we get back the correct data.
        config = get_platform_config()

        for k, v in my_config.items():
            assert v == config.get(k)

        assert 0 == len(set(my_config) - set(config))

        # Make sure that it persisted in the correct file.
        from configparser import ConfigParser
        cfg = ConfigParser()
        cfg.read(get_config_path())
        assert cfg.has_section("volttron")
        for k, v in my_config.items():
            assert v == cfg.get("volttron", k)
Пример #4
0
def test_discovery(scheme):
    vhome = create_volttron_home()
    # creates a vhome level key store
    keystore = KeyStore()
    serverkey = decode_key(keystore.public)

    # Depending upon scheme we enable/disable password jwt and certificate based jwt.
    if scheme == 'https':
        with certs_profile_1('/'.join([vhome, 'certs'])) as certs:
            config_params = dict(web_ssl_key=certs.server_certs[0].key_file,
                                 web_ssl_cert=certs.server_certs[0].cert_file)
    else:
        config_params = dict(web_secret_key=get_random_key())

    with get_test_volttron_home(messagebus='zmq', config_params=config_params):
        instance_name = "booballoon"
        host, port = get_hostname_and_random_port()

        # this is the vip address
        address = f"tcp://{host}:{port}"

        def _construct_query_mock(core):
            """
            Internal function that creates a concrete response for the data.
            when query('instance-name').get() is called the passed instance name
            is returned
            """
            nonlocal instance_name, address

            kv = {"instance-name": instance_name, "addresses": [address]}
            return MockQuery(**kv)

        with mock.patch('volttron.platform.vip.agent.subsystems.query.Query',
                        _construct_query_mock):
            host, port = get_hostname_and_random_port()
            bind_web_address = f"{scheme}://{host}:{port}"
            serverkey = decode_key(keystore.public)

            mws = MasterWebService(serverkey=serverkey,
                                   identity=MASTER_WEB,
                                   address=address,
                                   bind_web_address=bind_web_address,
                                   **config_params)
            mws.startupagent(sender='testweb')

            env = get_test_web_env("/discovery/")
            mock_start_response = mock.Mock()
            # A closingiterator is returned from the response object so we use the next
            # on the returned response.  Then we can do json responses.
            response = mws.app_routing(env, mock_start_response).__next__()
            # load json into a dict for testing responses.
            response = jsonapi.loads(response.decode('utf-8'))

            assert response.get('instance-name') is not None
            assert instance_name == response.get('instance-name')
            assert keystore.public == response.get('serverkey')
            assert address == response.get('vip-address')
Пример #5
0
def test_authenticate_must_use_post_request():
    with get_test_volttron_home(messagebus='zmq'):

        env = get_test_web_env('/authenticate', method='GET')

        authorize_ep = AuthenticateEndpoints(web_secret_key=get_random_key())
        response = authorize_ep.get_auth_token(env, {})
        assert ('Content-Type', 'text/html') in response.headers.items()
        assert '401 Unauthorized' in response.status
Пример #6
0
def test_both_private_key_and_passphrase():
    with pytest.raises(
            ValueError,
            match="Must use either ssl_private_key or web_secret_key not both!"
    ):
        with get_test_volttron_home(messagebus='zmq') as vhome:
            with certs_profile_1(vhome) as certs:
                authorizeep = AuthenticateEndpoints(
                    web_secret_key=get_random_key(),
                    tls_private_key=certs.server_certs[0].key)
Пример #7
0
def auth_file_platform_tuple():
    with get_test_volttron_home('zmq') as vhome:
        auth_file = AuthFile(os.path.join(vhome, 'auth.json'))
        gevent.sleep(0.5)
        yield auth_file

        allow_entries = auth_file.read_allow_entries()

        auth_file.remove_by_indices(list(range(3, len(allow_entries))))
        gevent.sleep(0.5)
Пример #8
0
def test_persistent_users():
    with get_test_volttron_home(messagebus='zmq'):
        username_test = "mytest"
        username_test_passwd = "value-plus"
        adminep = AdminEndpoints()
        oid = id(adminep)
        adminep.add_user(username_test, username_test_passwd, ['admin'])

        another_ep = AdminEndpoints()
        assert oid != id(another_ep)
        assert len(another_ep._userdict) == 1
        assert username_test == list(another_ep._userdict)[0]
Пример #9
0
def test_authenticate_post_request():
    with get_test_volttron_home(messagebus='zmq'):
        authorize_ep, test_user = set_test_admin()
        env = get_test_web_env('/authenticate', method='POST')
        response = authorize_ep.handle_authenticate(env, test_user)
        assert ('Content-Type', 'application/json') in response.headers.items()
        assert '200 OK' in response.status
        response_token = json.loads(response.response[0].decode('utf-8'))
        refresh_token = response_token['refresh_token']
        access_token = response_token["access_token"]
        assert 3 == len(refresh_token.split('.'))
        assert 3 == len(access_token.split("."))
Пример #10
0
def test_authenticate_endpoint(scheme):
    kwargs = {}

    # Note this is not a context wrapper, it just does the creation for us
    vhome = create_volttron_home()

    if scheme == 'https':
        with certs_profile_1(vhome) as certs:
            kwargs['web_ssl_key'] = certs.server_certs[0].key_file
            kwargs['web_ssl_cert'] = certs.server_certs[0].cert_file
    else:
        kwargs['web_secret_key'] = get_random_key()

    # We are specifying the volttron_home here so we don't create an additional one.
    with get_test_volttron_home(messagebus='zmq',
                                config_params=kwargs,
                                volttron_home=vhome):

        user = '******'
        passwd = 'cat'
        adminep = AdminEndpoints()
        adminep.add_user(user, passwd)

        env = get_test_web_env('/authenticate', method='POST')

        if scheme == 'http':
            authorizeep = AuthenticateEndpoints(
                web_secret_key=kwargs.get('web_secret_key'))
        else:
            authorizeep = AuthenticateEndpoints(
                tls_private_key=CertWrapper.load_key(kwargs.get(
                    'web_ssl_key')))

        invalid_login_username_params = dict(username='******', password=passwd)

        response = authorizeep.get_auth_tokens(env,
                                               invalid_login_username_params)

        # assert '401 Unauthorized' in response.content
        assert '401 UNAUTHORIZED' == response.status

        invalid_login_password_params = dict(username=user, password='******')
        response = authorizeep.get_auth_tokens(env,
                                               invalid_login_password_params)

        assert '401 UNAUTHORIZED' == response.status
        valid_login_params = urlencode(dict(username=user, password=passwd))
        response = authorizeep.get_auth_tokens(env, valid_login_params)
        assert '200 OK' == response.status
        assert "application/json" in response.content_type
        response_data = json.loads(response.data.decode('utf-8'))
        assert 3 == len(response_data["refresh_token"].split('.'))
        assert 3 == len(response_data["access_token"].split('.'))
Пример #11
0
def test_authenticate_delete_request():
    with get_test_volttron_home(messagebus='zmq'):
        authorize_ep, test_user = set_test_admin()
        # Get tokens for test
        env = get_test_web_env('/authenticate', method='POST')
        response = authorize_ep.handle_authenticate(env, test_user)

        # Touch Delete endpoint
        env = get_test_web_env('/authenticate', method='DELETE')
        response = authorize_ep.handle_authenticate(env, test_user)
        assert ('Content-Type', 'text/plain') in response.headers.items()
        assert '501 Not Implemented' in response.status
Пример #12
0
def test_admin_unauthorized():
    config_params = {"web-secret-key": get_random_key()}
    with get_test_volttron_home(messagebus='zmq', config_params=config_params):
        myuser = '******'
        mypass = '******'
        adminep = AdminEndpoints()
        adminep.add_user(myuser, mypass)

        # User hasn't logged in so this should be not authorized.
        env = get_test_web_env('/admin/api/boo')
        response = adminep.admin(env, {})
        assert '401 Unauthorized' == response.status
        assert b'Unauthorized User' in response.response[0]
Пример #13
0
def test_add_user():
    with get_test_volttron_home(messagebus='zmq') as vhome:
        webuserpath = os.path.join(vhome, ___WEB_USER_FILE_NAME__)
        assert not os.path.exists(webuserpath)

        username_test = "test"
        username_test_passwd = "passwd"
        adminep = AdminEndpoints()
        adminep.add_user(username_test, username_test_passwd, ['admin'])

        # since add_user is async with persistance we use sleep to allow the write
        # gevent.sleep(0.01)
        assert os.path.exists(webuserpath)

        with open(webuserpath) as fp:
            users = jsonapi.load(fp)

        assert len(users) == 1
        assert users.get(username_test) is not None
        user = users.get(username_test)
        objid = id(user)
        assert ['admin'] == user['groups']
        assert user['hashed_password'] is not None
        original_hashed_passwordd = user['hashed_password']

        # raise ValueError if not overwrite == True
        with pytest.raises(
                ValueError,
                match=
                f"The user {username_test} is already present and overwrite not set to True"
        ):
            adminep.add_user(username_test, username_test_passwd, ['admin'])

        # make sure the overwrite works because we are changing the group
        adminep.add_user(username_test,
                         username_test_passwd, ['read_only', 'jr-devs'],
                         overwrite=True)
        assert os.path.exists(webuserpath)

        with open(webuserpath) as fp:
            users = jsonapi.load(fp)

        assert len(users) == 1
        assert users.get(username_test) is not None
        user = users.get(username_test)
        assert objid != id(user)
        assert ['read_only', 'jr-devs'] == user['groups']
        assert user['hashed_password'] is not None
        assert original_hashed_passwordd != user['hashed_password']
Пример #14
0
def test_admin_login_page():
    with get_test_volttron_home(messagebus='zmq'):
        username_test = "mytest"
        username_test_passwd = "value-plus"
        adminep = AdminEndpoints()
        adminep.add_user(username_test, username_test_passwd, ['admin'])
        myenv = get_test_web_env(path='login.html')
        response = adminep.admin(myenv, {})
        jinja_mock = myenv['JINJA2_TEMPLATE_ENV']
        assert 1 == jinja_mock.get_template.call_count
        assert ('login.html', ) == jinja_mock.get_template.call_args[0]
        assert 1 == jinja_mock.get_template.return_value.render.call_count
        assert 'text/html' == response.headers.get('Content-Type')
        # assert ('Content-Type', 'text/html') in response.headers
        assert '200 OK' == response.status
Пример #15
0
def test_authenticate_put_request():
    with get_test_volttron_home(messagebus='zmq'):

        authorize_ep, test_user = set_test_admin()
        # Get tokens for test
        env = get_test_web_env('/authenticate', method='POST')
        response = authorize_ep.handle_authenticate(env, test_user)
        response_token = json.loads(response.response[0].decode('utf-8'))
        refresh_token = response_token['refresh_token']
        access_token = response_token["access_token"]

        # Test PUT Request
        env = get_test_web_env('/authenticate', method='PUT')
        env["HTTP_AUTHORIZATION"] = "BEARER " + refresh_token
        response = authorize_ep.handle_authenticate(env, data={})
        assert ('Content-Type', 'application/json') in response.headers.items()
        assert '200 OK' in response.status
Пример #16
0
def test_get_random_key():
    with get_test_volttron_home(messagebus='zmq'):
        key = get_random_key()
        # According to docs the default length is 65
        #
        # Note 2x default is what we should get due to hex encoding.
        assert 130 == len(key)

        with pytest.raises(ValueError) as err:
            key = get_random_key(0)

        with pytest.raises(ValueError) as err:
            key = get_random_key(-1)

        key = get_random_key(20)
        # note 2x the passed random key
        assert 40 == len(key)
Пример #17
0
def test_authenticate_put_request_refresh_expires():
    with get_test_volttron_home(messagebus='zmq'):

        authorize_ep, test_user = set_test_admin()
        # Get tokens for test
        env = get_test_web_env('/authenticate', method='POST')
        response = authorize_ep.handle_authenticate(env, test_user)
        response_token = json.loads(response.response[0].decode('utf-8'))
        refresh_token = response_token['refresh_token']
        access_token = response_token["access_token"]

        # Wait for refresh token to expire
        gevent.sleep(20)
        env = get_test_web_env('/authenticate', method='PUT')
        env["HTTP_AUTHORIZATION"] = "BEARER " + refresh_token
        response = authorize_ep.handle_authenticate(env, data={})
        assert ('Content-Type', 'text/html') in response.headers.items()
        assert "401 Unauthorized" in response.status
Пример #18
0
def test_authenticate_endpoint(scheme):
    kwargs = {}

    # Note this is not a context wrapper, it just does the creation for us
    vhome = create_volttron_home()

    if scheme == 'https':
        with certs_profile_1(vhome) as certs:
            kwargs['web_ssl_key'] = certs.server_certs[0].key_file
            kwargs['web_ssl_cert'] = certs.server_certs[0].cert_file
    else:
        kwargs['web_secret_key'] = binascii.hexlify(
            os.urandom(65)).decode('utf-8')
    host, port = get_hostname_and_random_port()
    kwargs['bind_web_address'] = f"{scheme}://{host}:{port}"

    # We are specifying the volttron_home here so we don't create an additional one.
    with get_test_volttron_home(messagebus='zmq',
                                config_params=kwargs,
                                volttron_home=vhome):

        # add a user so that we can actually log in.
        user = '******'
        passwd = 'cat'
        adminep = AdminEndpoints()
        adminep.add_user(user, passwd, groups=['foo', 'read-only'])
        expected_claims = dict(groups=['foo', 'read-only'])

        with get_master_web(**kwargs) as mw:

            data = urlencode(dict(username=user,
                                  password=passwd)).encode('utf-8')
            assert len(data) > 0
            # test not sending any parameters.
            env = get_test_web_env("/authenticate",
                                   input_data=data,
                                   method='POST')
            mocked_start_response, response = get_server_response(env, mw)
            assert 3 == len(response.split("."))

            claims = mw.get_user_claims(response)
            assert claims
            assert not DeepDiff(expected_claims, claims)
Пример #19
0
def test_set_platform_password_setup():
    with get_test_volttron_home(messagebus='zmq') as vhome:
        # Note these passwords are not right so we expect to be redirected back to the
        # first.html
        params = urlencode(
            dict(username='******', password1='goodwin', password2='wowsa'))
        env = get_test_web_env("/admin/setpassword",
                               method='POST')  # , input_data=input)
        jinja_mock = env['JINJA2_TEMPLATE_ENV']
        adminep = AdminEndpoints()
        response = adminep.admin(env, params)

        assert 'Location' not in response.headers
        assert 200 == response.status_code
        assert 'text/html' == response.headers.get('Content-Type')

        assert 1 == jinja_mock.get_template.call_count
        assert ('first.html', ) == jinja_mock.get_template.call_args[0]
        assert 1 == jinja_mock.get_template.return_value.render.call_count
        jinja_mock.reset_mock()

        # Now we have the correct password1 and password2 set we expect to redirected to
        # /admin/login.html
        params = urlencode(
            dict(username='******', password1='wowsa', password2='wowsa'))
        env = get_test_web_env("/admin/setpassword",
                               method='POST')  # , input_data=input)

        # expect Location and Content-Type headers to be set
        response = adminep.admin(env, params)
        assert 3 == len(response.headers)
        assert 'Location' in response.headers
        assert '/admin/login.html' == response.headers.get('Location')
        assert 302 == response.status_code

        webuserpath = os.path.join(vhome, 'web-users.json')
        with open(webuserpath) as wup:
            users = jsonapi.load(wup)
        assert users.get('bart') is not None
        user = users.get('bart')
        assert user['hashed_password'] is not None
        assert argon2.verify("wowsa", user['hashed_password'])