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
Example #2
0
def test_register_routes(mock_platformweb_service):
    html_root = "/tmp/junk/html"
    attempt_to_get_file = "/tmp/junk/index.html"
    should_get_index_file = os.path.join(html_root, "index.html")
    file_contents_bad = "HOLY COW!"
    file_contents_good = "Woot there it is!"
    try:

        os.makedirs(html_root, exist_ok=True)
        with open(attempt_to_get_file, "w") as should_not_get:
            should_not_get.write(file_contents_bad)
        with open(should_get_index_file, "w") as should_get:
            should_get.write(file_contents_good)

        pws = mock_platformweb_service

        pws.register_path_route(f"/.*", html_root)
        pws.register_path_route(f"/flubber", ".")
        # Test to make sure the route is resolved to a full directory so easier
        # to detect chroot for html paths.
        assert len(pws.registeredroutes) == 2
        for x in pws.registeredroutes:
            # x is a tuple regex, 'path', directory
            assert Path(x[2]).is_absolute()

        start_response = MagicMock()
        data = pws.app_routing(get_test_web_env("/index.html"), start_response)
        data = "".join([x.decode("utf-8") for x in data])
        assert "200 OK" in start_response.call_args[0]
        assert data == file_contents_good

        # Test relative route to the index.html file above the html_root, but using a
        # rooted path to do so.
        start_response.reset_mock()
        data = pws.app_routing(get_test_web_env("/../index.html"),
                               start_response)
        data = "".join([x.decode("utf-8") for x in data])
        assert "403 Forbidden" in start_response.call_args[0]
        assert "403 Forbidden" in data

        # Test relative route to the index.html file above the html_root.
        start_response.reset_mock()
        data = pws.app_routing(get_test_web_env("../index.html"),
                               start_response)
        data = "".join([x.decode("utf-8") for x in data])
        assert "200 OK" not in start_response.call_args[0]
        assert data != file_contents_bad

    finally:
        shutil.rmtree(str(Path(html_root).parent), ignore_errors=True)
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
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
Example #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
Example #6
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')
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
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'])
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("."))
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('.'))
Example #11
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]
Example #12
0
def test_path_route():
    with get_master_web(web_secret_key="oh my goodnes") as ws:
        # Stage 1 create a temp dir and add index.html to that directory
        tempdir = tempfile.mkdtemp(prefix="web")
        html = """<html><head><title>sweet</title><body>Yay I am here</body></html>"""
        index_filepath = f"{tempdir}/myhtml/index.html"
        os.makedirs(os.path.dirname(index_filepath))
        with open(index_filepath, 'w') as fp:
            fp.write(html)

        # Stage 2 register the path route and specify the root directory as the
        # tempdirectory created above.
        interest = {"/myhtml": {"type": "path", "root_dir": tempdir}}
        registerd_routes_before = len(ws.registeredroutes)
        add_points_of_interest(ws, interest)

        assert 1 == len(ws.pathroutes)
        assert registerd_routes_before + 1 == len(ws.registeredroutes)

        # Stage 3 - emulate a request which will call the app_routing function
        #
        # We need to update the enf_fixture to what the webserver will normally send
        # in to the server.  So for this we are going to update the PATH_INFO
        #
        # since we registered the path /myhtml then this should route to
        # <tempdir>/myhtml/index.html for this example.
        env_fixture = get_test_web_env('/myhtml/index.html')
        mocked_start_response, response = get_server_response(env_fixture, ws)
        assert response == html
        assert mocked_start_response.call_count == 1
        mocked_start_response.reset_mock()

        # file not found
        env_fixture = get_test_web_env('/myhtml/alpha.jpg')
        mocked_start_response, response = get_server_response(env_fixture, ws)
        assert response == '<h1>Not Found</h1>'
        assert mocked_start_response.call_count == 1
        mocked_start_response.reset_mock()
Example #13
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
Example #14
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)
Example #15
0
def mock_jsonrpc_env(path="jsonrpc", input_data=None, method="POST"):
    yield get_test_web_env(path, input_data, method=method)