Beispiel #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)
Beispiel #2
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)
def set_test_admin():
    authorize_ep = MockAuthenticateEndpoints(web_secret_key=get_random_key())
    authorize_ep.set_access_token_timeout(0.1)
    authorize_ep.set_refresh_token_timeout(0.2)
    AdminEndpoints().add_user("test_admin", "Pass123", groups=['admin'])
    test_user = {"username": "******", "password": "******"}
    gevent.sleep(1)
    return authorize_ep, test_user
Beispiel #4
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
Beispiel #5
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')
Beispiel #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)
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('.'))
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]
def get_test_volttron_home(messagebus: str,
                           web_https=False,
                           web_http=False,
                           has_vip=True,
                           volttron_home: str = None,
                           config_params: dict = None,
                           env_options: dict = None):
    """
    Create a full volttronn_home test environment with all of the options available in the environment
    (os.environ) and configuration file (volttron_home/config) in order to test from.

    @param messagebus:
        Currently supports rmq and zmq strings
    @param web_https:
        Determines if https should be used and enabled.  If this is specified then the cert_fixtures.certs_profile_1
        function will be used to generate certificates for  the server and signed ca.  Either web_https or web_http
        may be specified not both.
    @param has_vip:
        Allows the rmq message bus to not specify a vip address if backward compatibility is not needed.
    @param config_params:
        Configuration parameters that should go into the volttron configuration file, note if the basic ones are
        set via the previous arguments (i.e. web_https) then it is an error to specify bind-web-address (or other)
        duplicate.
    @param env_options:
        Other options that should be specified in the os.environ during the setup of this environment.
    """
    # Make these not None so that we can use set operations on them to see if we have any overlap between
    # common configuration params and environment.
    if config_params is None:
        config_params = {}
    if env_options is None:
        env_options = {}

    # make a copy so we can restore in cleanup
    env_cpy = os.environ.copy()

    # start validating input
    assert messagebus in (
        'rmq', 'zmq'), 'Invalid messagebus specified, must be rmq or zmq.'

    if web_http and web_https:
        raise ValueError(
            "Incompatabile tyeps web_https and web_Http cannot both be specified as True"
        )

    default_env_options = ('VOLTTRON_HOME', 'MESSAGEBUS')

    for v in default_env_options:
        if v in env_options:
            raise ValueError(
                f"Cannot specify {v} in env_options as it is set already.")

    # All is well.Create vhome
    if volttron_home:
        os.makedirs(volttron_home, exist_ok=True)
    else:
        volttron_home = create_volttron_home()

    # Create env
    envs = dict(VOLTTRON_HOME=volttron_home, MESSAGEBUS=messagebus)
    os.environ.update(envs)
    os.environ.update(env_options)

    # make the top level dirs
    os.mkdir(os.path.join(volttron_home, "agents"))
    os.mkdir(os.path.join(volttron_home, "configuration_store"))
    os.mkdir(os.path.join(volttron_home, "keystores"))
    os.mkdir(os.path.join(volttron_home, "run"))

    # create the certs. This will create the certs dirs
    web_certs_dir = os.path.join(volttron_home, "web_certs")
    web_certs = None
    if web_https:
        web_certs = certs_profile_1(web_certs_dir)

    vip_address = None
    bind_web_address = None
    web_ssl_cert = None
    web_ssl_key = None
    web_secret_key = None

    config_file = {}
    if messagebus == 'rmq':
        if has_vip:
            ip, port = get_rand_ip_and_port()
            vip_address = f"tcp://{ip}:{port}"
        web_https = True
    elif messagebus == 'zmq':
        if web_http or web_https:
            ip, port = get_rand_ip_and_port()
            vip_address = f"tcp://{ip}:{port}"

    if web_https:
        hostname, port = get_hostname_and_random_port()
        bind_web_address = f"https://{hostname}:{port}"
        web_ssl_cert = web_certs.server_certs[0].cert_file
        web_ssl_key = web_certs.server_certs[0].key_file
    elif web_http:
        hostname, port = get_hostname_and_random_port()
        bind_web_address = f"http://{hostname}:{port}"
        web_secret_key = get_random_key()

    if vip_address:
        config_file['vip-address'] = vip_address
    if bind_web_address:
        config_file['bind-web-address'] = bind_web_address
    if web_ssl_cert:
        config_file['web-ssl-cert'] = web_ssl_cert
    if web_ssl_key:
        config_file['web-ssl-key'] = web_ssl_key
    if web_secret_key:
        config_file['web-secret-key'] = web_secret_key

    config_intersect = set(config_file).intersection(set(config_params))
    if len(config_intersect) > 0:
        raise ValueError(
            f"passed configuration params {list(config_intersect)} are built internally"
        )

    config_file.update(config_params)

    update_platform_config(config_file)

    try:
        yield volttron_home
    finally:
        os.environ.clear()
        os.environ.update(env_cpy)
        if not os.environ.get("DEBUG", 0) != 1 and not os.environ.get(
                "DEBUG_MODE", 0):
            shutil.rmtree(volttron_home, ignore_errors=True)