Exemplo n.º 1
0
    def test_validate_static(self):
        """Test all static user/pass authentication paths."""
        config = "anchor.jsonloader.conf._config"
        data = {
            'auth': {
                'static': {
                    'secret': 'simplepassword',
                    'user': '******'
                }
            }
        }

        with mock.patch.dict(config, data):
            # can't import until mock'd
            from anchor import auth
            from anchor.auth import results

            valid_user = data['auth']['static']['user']
            valid_pass = data['auth']['static']['secret']

            expected = results.AuthDetails(username=valid_user, groups=[])
            self.assertEqual(auth.validate(valid_user, valid_pass), expected)
            with self.assertRaises(http_status.HTTPUnauthorized):
                auth.validate(valid_user, 'badpass')
            with self.assertRaises(http_status.HTTPUnauthorized):
                auth.validate('baduser', valid_pass)
            with self.assertRaises(http_status.HTTPUnauthorized):
                auth.validate('baduser', 'badpass')
Exemplo n.º 2
0
def login(_, token):
    """Authenticate with the keystone endpoint from configuration file

    :param token: A Keystone Token
    :returns: AuthDetails -- Class used for authentication information
    """
    data = json.dumps(
        {"auth": {
            "identity": {
                "methods": ["token"],
                "token": {
                    "id": token
                }
            }
        }})
    req = requests.post(jsonloader.conf.auth['keystone']['url'] +
                        '/v3/auth/tokens',
                        headers={'Content-Type': 'application/json'},
                        data=data)
    if req.status_code != 200:
        logger.info("Authentication failed for token <%s>, status %s", token,
                    req.status_code)
        return None

    try:
        res = req.json()
        user = res['token']['user']['name']

        roles = [role['name'] for role in res['token']['roles']]
    except Exception:
        logger.exception("Keystone response was not in the expected format")
        return None

    return results.AuthDetails(username=user, groups=roles)
Exemplo n.º 3
0
def login(_, token):
    """Authenticate with the keystone endpoint from configuration file

    :param token: A Keystone Token
    :returns: AuthDetails -- Class used for authentication information
    """
    req = requests.get(jsonloader.conf.auth['keystone']['url'] +
                       '/v3/auth/tokens',
                       headers={
                           'X-Auth-Token': token,
                           'X-Subject-Token': token
                       })
    if req.status_code != 200:
        logger.info("Authentication failed for token <%s>, status %s", token,
                    req.status_code)
        return None

    try:
        res = req.json()
        user = res['token']['user']['name']

        roles = [role['name'] for role in res['token']['roles']]
    except Exception:
        logger.exception("Keystone response was not in the expected format")
        return None

    return results.AuthDetails(username=user, groups=roles)
Exemplo n.º 4
0
def login(user, secret):
    """Validates a user supplied user/password against an expected value.

       The expected value is pulled from the pecan config. Note that this
       value is currently stored in the clear inside that config, so we
       are assuming that the config is protected using file perms, etc.

       This function provides some resistance to timing attacks, but
       information on the expected user/password lengths can still be
       leaked. It may also be possible to use a timing attack to see
       which input failed validation. See comments below for details.

       :param user: The user supplied username (unicode or string)
       :param secret: The user supplied password (unicode or string)
       :return: None on failure or an AuthDetails object on success
    """
    # convert input to strings
    user = str(user)
    secret = str(secret)

    # expected values
    try:
        expected_user = str(jsonloader.conf.auth['static']['user'])
        expected_secret = str(jsonloader.conf.auth['static']['secret'])
    except (KeyError, TypeError):
        logger.warning("auth conf missing static user or secret")
        return None

    # In python, len(<string>) is O(1)
    # Short circuit this if lengths don't match
    if len(user) != len(expected_user):
        logger.info("failed static auth: invalid username ({})".format(user))
        return None
    if len(secret) != len(expected_secret):
        logger.info("failed static auth: invalid password")
        return None

    # This technique is used to provide a constant time string compare
    # between the user input and the expected values.
    valid_user = util.constant_time_compare(user, expected_user)
    valid_secret = util.constant_time_compare(secret, expected_secret)

    # This if statement results in a potential timing attack where the
    # statement could return more quickly if valid_secret=False. We
    # do not see an obvious solution to this problem, but also believe
    # that leaking which input was valid isn't as big of a concern.
    if valid_user and valid_secret:
        return results.AuthDetails(username=expected_user, groups=[])

    logger.info("failed static auth for user {}".format(user))
Exemplo n.º 5
0
    def test_login_good(self, mock_connection):
        """Test all static user/pass authentication paths."""
        jsonloader.conf.load_extensions()
        config = "anchor.jsonloader.conf._config"

        mock_ldc = mock.Mock()
        mock_connection.return_value = mock_ldc
        mock_ldc.result = {'result': 0}
        mock_ldc.response = [{'attributes': {}}]

        with mock.patch.dict(config, self.sample_conf):
            expected = results.AuthDetails(username='******', groups=[])
            self.assertEqual(auth.validate('default_ra', 'user', 'pass'),
                             expected)
Exemplo n.º 6
0
def login(ra_name, user, secret):
    """Attempt to Authenitcate user using LDAP

    :param ra_name: name of registration authority
    :param user: Username
    :param secret: Secret/Passphrase
    :returns: AuthDetails -- Class used for authentication information
    """
    conf = jsonloader.authentication_for_registration_authority(ra_name)
    ldap_port = int(conf.get('port', 389))
    use_ssl = conf.get('ssl', ldap_port == 636)

    lds = ldap3.Server(conf['host'],
                       port=ldap_port,
                       get_info=ldap3.ALL,
                       use_ssl=use_ssl)

    try:
        ldap_user = "******" % (user, conf['domain'])
        ldc = ldap3.Connection(lds,
                               auto_bind=True,
                               client_strategy=ldap3.SYNC,
                               user=ldap_user,
                               password=secret,
                               authentication=ldap3.SIMPLE,
                               check_names=True)

        filter_str = ('(sAMAccountName=%s)' %
                      ldap3.utils.conv.escape_bytes(user))
        ldc.search(conf['base'],
                   filter_str,
                   ldap3.SUBTREE,
                   attributes=['memberOf'])
        if ldc.result['result'] != 0:
            return None
        user_attrs = ldc.response[0]['attributes']
        user_groups = user_get_groups(user_attrs)
        return results.AuthDetails(username=user, groups=user_groups)
    except ldap3.LDAPSocketOpenError:
        logger.error("cannot connect to LDAP host '%s' (authority '%s')",
                     conf['host'], ra_name)
        return None
    except ldap3.LDAPBindError:
        logger.info("failed ldap auth for user %s", user)
        return None
Exemplo n.º 7
0
    def test_auth_login(self):

        config = "anchor.jsonloader.conf._config"
        data = {'auth': {'keystone': {'url': 'http://localhost:35357'}}}
        with mock.patch.dict(config, data):

            from anchor.auth import keystone
            from anchor.auth import results

            keystone_url = data['auth']['keystone']['url'] + '/v3/auth/tokens'
            keystone_token = uuid.uuid4().hex

            json_response = {
                "token": {
                    "roles": [{
                        "name": "admin"
                    }],
                    "user": {
                        "name": "priti"
                    },
                }
            }

            user = json_response['token']['user']['name']
            roles = [role['name'] for role in json_response['token']['roles']]
            expected = results.AuthDetails(username=user, groups=roles)

            with requests_mock.mock() as m:
                m.post(keystone_url, json=json_response, status_code=200)
                requests.post(keystone_url)
                # Check that it can parse Keystone response when
                # response has valid json and status code of 200
                self.assertEqual(keystone.login(None, keystone_token),
                                 expected)

                # Check that it fails and returns appropriate auth
                # failure when Keystone authentication fails
                m.post(keystone_url, status_code=201)
                self.assertEqual(keystone.login(None, keystone_token), None)

                # Check that it fails and returns appropriate auth
                # failure when Keystone response is corrupted
                m.post(keystone_url, json={}, status_code=200)
                self.assertEqual(keystone.login(None, keystone_token), None)
Exemplo n.º 8
0
    def test_login_good_with_groups(self, mock_connection):
        """Test all static user/pass authentication paths."""
        jsonloader.conf.load_extensions()
        config = "anchor.jsonloader.conf._config"

        mock_ldc = mock.Mock()
        mock_connection.return_value = mock_ldc
        mock_ldc.result = {'result': 0}
        mock_ldc.response = [{
            'attributes': {
                'memberOf': [
                    u'CN=some_group,OU=Groups,DC=example,DC=com',
                    u'CN=other_group,OU=Groups,DC=example,DC=com'
                ]
            }
        }]

        with mock.patch.dict(config, self.sample_conf):
            expected = results.AuthDetails(
                username='******', groups=[u'some_group', u'other_group'])
            self.assertEqual(auth.validate('default_ra', 'user', 'pass'),
                             expected)
Exemplo n.º 9
0
def login(user, secret):
    """Attempt to Authenitcate user using LDAP

    :param user: Username
    :param secret: Secret/Passphrase
    :returns: AuthDetails -- Class used for authentication information
    """
    ldap_port = int(jsonloader.conf.auth['ldap'].get('port', 389))
    use_ssl = jsonloader.conf.auth['ldap'].get('ssl', ldap_port == 636)

    lds = ldap3.Server(jsonloader.conf.auth['ldap']['host'],
                       port=ldap_port,
                       get_info=ldap3.ALL,
                       use_ssl=use_ssl)

    try:
        ldap_user = "******" % (user, jsonloader.conf.auth['ldap']['domain'])
        ldc = ldap3.Connection(lds,
                               auto_bind=True,
                               client_strategy=ldap3.SYNC,
                               user=ldap_user,
                               password=secret,
                               authentication=ldap3.SIMPLE,
                               check_names=True)

        filter_str = ('(sAMAccountName=%s)' %
                      ldap3.utils.conv.escape_bytes(user))
        ldc.search(jsonloader.conf.auth['ldap']['base'],
                   filter_str,
                   ldap3.SUBTREE,
                   attributes=['memberOf'])
        if ldc.result['result'] != 0:
            return None
        user_attrs = ldc.response[0]['attributes']
        user_groups = user_get_groups(user_attrs)
        return results.AuthDetails(username=user, groups=user_groups)
    except ldap3.LDAPBindError:
        return None
Exemplo n.º 10
0
    def test_validate_static(self):
        """Test all static user/pass authentication paths."""
        jsonloader.conf.load_extensions()
        config = "anchor.jsonloader.conf._config"
        self.sample_conf_auth['default_auth'] = {
            "backend": "static",
            "user": "******",
            "secret": "simplepassword"
        }
        data = self.sample_conf

        with mock.patch.dict(config, data):
            valid_user = self.sample_conf_auth['default_auth']['user']
            valid_pass = self.sample_conf_auth['default_auth']['secret']

            expected = results.AuthDetails(username=valid_user, groups=[])
            self.assertEqual(
                auth.validate('default_ra', valid_user, valid_pass), expected)
            with self.assertRaises(http_status.HTTPUnauthorized):
                auth.validate('default_ra', valid_user, 'badpass')
            with self.assertRaises(http_status.HTTPUnauthorized):
                auth.validate('default_ra', 'baduser', valid_pass)
            with self.assertRaises(http_status.HTTPUnauthorized):
                auth.validate('default_ra', 'baduser', 'badpass')
Exemplo n.º 11
0
def login(user, secret):
    """Attempt to Authenitcate user using LDAP

    :param user: Username
    :param secret: Secret/Passphrase
    :returns: AuthDetails -- Class used for authentication information
    """
    ldo = ldap.initialize("ldap://%s" % (jsonloader.conf.auth['ldap']['host']))
    ldo.set_option(ldap.OPT_REFERRALS, 0)
    try:
        ldo.simple_bind_s(
            "%s@%s" % (user, jsonloader.conf.auth['ldap']['domain']), secret)

        filter_str = ('(sAMAccountName=%s)' %
                      ldap.filter.escape_filter_chars(user))
        ret = ldo.search_s(jsonloader.conf.auth['ldap']['base'],
                           ldap.SCOPE_SUBTREE,
                           filterstr=filter_str,
                           attrlist=['memberOf'])
        user_attrs = [x for x in ret if x[0] is not None][0][1]
        user_groups = user_get_groups(user_attrs)
        return results.AuthDetails(username=user, groups=user_groups)
    except ldap.INVALID_CREDENTIALS:
        return None
Exemplo n.º 12
0
    def setUp(self):
        self.config = "anchor.jsonloader.conf._config"
        self.data = {'auth': {'keystone': {'url': 'http://localhost:35357'}}}
        self.json_response = {
            "token": {
                "audit_ids": ["TPDsHuK_QCaKwvkVlAer8A"],
                "catalog": [{
                    "endpoints": [{
                        "id": "1390df96096d4bd19add44811db34397",
                        "interface": "public",
                        "region": "RegionOne",
                        "region_id": "RegionOne",
                        "url": "http://10.0.2.15:5000/v2.0"
                    }, {
                        "id": "534bcae735614781a03069d637b21570",
                        "interface": "internal",
                        "region": "RegionOne",
                        "region_id": "RegionOne",
                        "url": "http://10.0.2.15:5000/v2.0"
                    }, {
                        "id": "cc7e879d691e4e4b9f4afecb1a3ce8f0",
                        "interface": "admin",
                        "region": "RegionOne",
                        "region_id": "RegionOne",
                        "url": "http://10.0.2.15:35357/v2.0"
                    }],
                    "id":
                    "3010a0c9af684db28659f0e9e08ee863",
                    "name":
                    "keystone",
                    "type":
                    "identity"
                }],
                "expires_at":
                "2015-07-27T02:38:09.000000Z",
                "extras": {},
                "issued_at":
                "2015-07-27T01:38:09.409616",
                "methods": ["password", "token"],
                "project": {
                    "domain": {
                        "id": "default",
                        "name": "Default"
                    },
                    "id": "5b2e7bd5d5954fdaa2d931285df8a132",
                    "name": "demo"
                },
                "roles": [{
                    "id": "35a1d29b54f64c969aa9be288ec9d39a",
                    "name": "anotherrole"
                }, {
                    "id": "9f64371fcbd64c669ab1a24686a1a367",
                    "name": "Member"
                }],
                "user": {
                    "domain": {
                        "id": "default",
                        "name": "Default"
                    },
                    "id": "b2016b9338214cda926d5631c1fbc40c",
                    "name": "demo"
                }
            }
        }

        self.user = self.json_response['token']['user']['name']
        self.roles = [
            role['name'] for role in self.json_response['token']['roles']
        ]
        self.expected = results.AuthDetails(username=self.user,
                                            groups=self.roles)

        self.keystone_url = self.data['auth']['keystone'][
            'url'] + '/v3/auth/tokens'
        self.keystone_token = uuid.uuid4().hex

        super(AuthKeystoneTests, self).setUp()