def test_ssh_success(vo, rest_client): """AUTHENTICATION (REST): SSH RSA public key exchange (correct credentials).""" root = InternalAccount('root', vo=vo) try: add_account_identity(PUBLIC_KEY, IdentityType.SSH, root, email='*****@*****.**') except Duplicate: pass # might already exist, can skip headers_dict = {'X-Rucio-Account': 'root'} response = rest_client.get('/auth/ssh_challenge_token', headers=headers(hdrdict(headers_dict), vohdr(vo))) assert response.status_code == 200 assert 'challenge-' in response.headers.get('X-Rucio-SSH-Challenge-Token') signature = ssh_sign(PRIVATE_KEY, response.headers.get('X-Rucio-SSH-Challenge-Token')) headers_dict = { 'X-Rucio-Account': 'root', 'X-Rucio-SSH-Signature': signature } response = rest_client.get('/auth/ssh', headers=headers(hdrdict(headers_dict), vohdr(vo))) assert response.status_code == 200 assert len(response.headers.get('X-Rucio-Auth-Token')) > 32 del_account_identity(PUBLIC_KEY, IdentityType.SSH, root)
def test_get_auth_token_ssh_success(self): """AUTHENTICATION (CORE): SSH RSA public key exchange (good signature).""" try: add_account_identity(PUBLIC_KEY, IdentityType.SSH, 'root', email='*****@*****.**') except Duplicate: pass # might already exist, can skip challenge_token = get_ssh_challenge_token(account='root', appid='test', ip='127.0.0.1').token signature = base64.b64decode(ssh_sign(PRIVATE_KEY, challenge_token)) result = get_auth_token_ssh(account='root', signature=signature, appid='test', ip='127.0.0.1') assert_is_not_none(result) del_account_identity(PUBLIC_KEY, IdentityType.SSH, 'root')
def test_invalid_padding(self): """AUTHENTICATION (CORE): SSH RSA public key exchange (public key with invalid padding).""" root = InternalAccount('root', **self.vo) try: add_account_identity(INVALID_PADDED_PUBLIC_KEY, IdentityType.SSH, root, email='*****@*****.**') except Duplicate: pass # might already exist, can skip challenge_token = get_ssh_challenge_token(account='root', appid='test', ip='127.0.0.1', **self.vo).get('token') ssh_sign_string = ssh_sign(PRIVATE_KEY, challenge_token) signature = base64.b64decode(ssh_sign_string) result = get_auth_token_ssh(account='root', signature=signature, appid='test', ip='127.0.0.1', **self.vo) assert result is not None del_account_identity(INVALID_PADDED_PUBLIC_KEY, IdentityType.SSH, root)
def test_ssh_fail(self): """AUTHENTICATION (REST): SSH RSA public key exchange (wrong credentials).""" root = InternalAccount('root', **self.vo) try: add_account_identity(PUBLIC_KEY, IdentityType.SSH, root, email='*****@*****.**') except Duplicate: pass # might already exist, can skip signature = ssh_sign(PRIVATE_KEY, 'sign_something_else') options = [] headers = { 'X-Rucio-Account': 'root', 'X-Rucio-SSH-Signature': signature } headers.update(self.vo_header) result = TestApp(APP.wsgifunc(*options)).get('/ssh', headers=headers, expect_errors=True) assert result.status == 401 del_account_identity(PUBLIC_KEY, IdentityType.SSH, root)
def test_ssh_success(self): """AUTHENTICATION (REST): SSH RSA public key exchange (correct credentials).""" try: add_account_identity(PUBLIC_KEY, IdentityType.SSH, 'root', email='*****@*****.**') except Duplicate: pass # might already exist, can skip options = [] headers = {'X-Rucio-Account': 'root'} result = TestApp(APP.wsgifunc(*options)).get('/ssh_challenge_token', headers=headers, expect_errors=True) assert_equal(result.status, 200) assert_in('challenge-', result.header('X-Rucio-SSH-Challenge-Token')) signature = ssh_sign(PRIVATE_KEY, result.header('X-Rucio-SSH-Challenge-Token')) headers = { 'X-Rucio-Account': 'root', 'X-Rucio-SSH-Signature': signature } result = TestApp(APP.wsgifunc(*options)).get('/ssh', headers=headers, expect_errors=True) assert_equal(result.status, 200) assert_greater(len(result.header('X-Rucio-Auth-Token')), 32) del_account_identity(PUBLIC_KEY, IdentityType.SSH, 'root')
def test_auth_ssh(self): """ MULTI VO (REST): Test ssh authentication to multiple VOs """ mw = [] try: add_account_identity(PUBLIC_KEY, 'SSH', 'root', '*****@*****.**', 'root', **self.vo) add_account_identity(PUBLIC_KEY, 'SSH', 'root', '*****@*****.**', 'root', **self.new_vo) except Duplicate: pass # Might already exist, can skip headers_tst = {'X-Rucio-Account': 'root'} headers_tst.update(self.vo_header) res_tst = TestApp(auth_app.wsgifunc(*mw)).get('/ssh_challenge_token', headers=headers_tst, expect_errors=True) assert_equal(res_tst.status, 200) challenge_tst = str(res_tst.header('X-Rucio-SSH-Challenge-Token')) headers_tst.update({'X-Rucio-SSH-Signature': ssh_sign(PRIVATE_KEY, challenge_tst)}) res_tst = TestApp(auth_app.wsgifunc(*mw)).get('/ssh', headers=headers_tst, expect_errors=True) assert_equal(res_tst.status, 200) token_tst = str(res_tst.header('X-Rucio-Auth-Token')) headers_new = {'X-Rucio-Account': 'root'} headers_new.update(self.new_header) res_new = TestApp(auth_app.wsgifunc(*mw)).get('/ssh_challenge_token', headers=headers_new, expect_errors=True) assert_equal(res_new.status, 200) challenge_tst = str(res_new.header('X-Rucio-SSH-Challenge-Token')) headers_new.update({'X-Rucio-SSH-Signature': ssh_sign(PRIVATE_KEY, challenge_tst)}) res_new = TestApp(auth_app.wsgifunc(*mw)).get('/ssh', headers=headers_new, expect_errors=True) assert_equal(res_new.status, 200) token_new = str(res_new.header('X-Rucio-Auth-Token')) headers_tst = {'X-Rucio-Auth-Token': str(token_tst)} res_tst = TestApp(account_app.wsgifunc(*mw)).get('/', headers=headers_tst, expect_errors=True) assert_equal(res_tst.status, 200) accounts_tst = [parse_response(a)['account'] for a in res_tst.body.decode().split('\n')[:-1]] assert_not_equal(len(accounts_tst), 0) assert_in(self.account_tst, accounts_tst) assert_not_in(self.account_new, accounts_tst) headers_new = {'X-Rucio-Auth-Token': str(token_new)} res_new = TestApp(account_app.wsgifunc(*mw)).get('/', headers=headers_new, expect_errors=True) assert_equal(res_new.status, 200) accounts_new = [parse_response(a)['account'] for a in res_new.body.decode().split('\n')[:-1]] assert_not_equal(len(accounts_new), 0) assert_in(self.account_new, accounts_new) assert_not_in(self.account_tst, accounts_new)
def __get_token_ssh(self): """ Sends a request to get an auth token from the server and stores it as a class attribute. Uses SSH key exchange authentication. :returns: True if the token was successfully received. False otherwise. """ headers = {} private_key_path = self.creds['ssh_private_key'] if not path.exists(private_key_path): self.logger.error('given private key (%s) doesn\'t exist' % private_key_path) return False if private_key_path is not None and not path.exists(private_key_path): self.logger.error('given private key (%s) doesn\'t exist' % private_key_path) return False url = build_url(self.auth_host, path='auth/ssh_challenge_token') result = self._send_request(url, get_token=True) if not result: self.logger.error('cannot get ssh_challenge_token') return False if result.status_code != codes.ok: # pylint: disable-msg=E1101 exc_cls, exc_msg = self._get_exception(headers=result.headers, status_code=result.status_code, data=result.content) raise exc_cls(exc_msg) self.ssh_challenge_token = result.headers['x-rucio-ssh-challenge-token'] self.logger.debug('got new ssh challenge token \'%s\'' % self.ssh_challenge_token) # sign the challenge token with the private key with open(private_key_path, 'r') as fd_private_key_path: private_key = fd_private_key_path.read() signature = ssh_sign(private_key, self.ssh_challenge_token) headers['X-Rucio-SSH-Signature'] = signature url = build_url(self.auth_host, path='auth/ssh') result = self._send_request(url, headers=headers, get_token=True) if not result: self.logger.error('Cannot retrieve authentication token!') return False if result.status_code != codes.ok: # pylint: disable-msg=E1101 exc_cls, exc_msg = self._get_exception(headers=result.headers, status_code=result.status_code, data=result.content) raise exc_cls(exc_msg) self.auth_token = result.headers['x-rucio-auth-token'] return True
def test_get_auth_token_ssh_fail(self): """AUTHENTICATION (CORE): SSH RSA public key exchange (wrong signature).""" root = InternalAccount('root', **self.vo) try: add_account_identity(PUBLIC_KEY, IdentityType.SSH, root, email='*****@*****.**') except Duplicate: pass # might already exist, can skip signature = ssh_sign(PRIVATE_KEY, 'sign_something_else') result = get_auth_token_ssh(account='root', signature=signature, appid='test', ip='127.0.0.1', **self.vo) assert_is_none(result) del_account_identity(PUBLIC_KEY, IdentityType.SSH, root)
def test_ssh_fail(vo, rest_client): """AUTHENTICATION (REST): SSH RSA public key exchange (wrong credentials).""" root = InternalAccount('root', vo=vo) try: add_account_identity(PUBLIC_KEY, IdentityType.SSH, root, email='*****@*****.**') except Duplicate: pass # might already exist, can skip signature = ssh_sign(PRIVATE_KEY, 'sign_something_else') headers_dict = { 'X-Rucio-Account': 'root', 'X-Rucio-SSH-Signature': signature } response = rest_client.get('/auth/ssh', headers=headers(hdrdict(headers_dict), vohdr(vo))) assert response.status_code == 401 del_account_identity(PUBLIC_KEY, IdentityType.SSH, root)
def test_ssh_success(self): """AUTHENTICATION (REST): SSH RSA public key exchange (correct credentials).""" root = InternalAccount('root', **self.vo) try: add_account_identity(PUBLIC_KEY, IdentityType.SSH, root, email='*****@*****.**') except Duplicate: pass # might already exist, can skip options = [] headers = {'X-Rucio-Account': 'root'} headers.update(self.vo_header) result = TestApp(APP.wsgifunc(*options)).get('/ssh_challenge_token', headers=headers, expect_errors=True) assert result.status == 200 assert 'challenge-' in result.header('X-Rucio-SSH-Challenge-Token') signature = ssh_sign(PRIVATE_KEY, result.header('X-Rucio-SSH-Challenge-Token')) headers = { 'X-Rucio-Account': 'root', 'X-Rucio-SSH-Signature': signature } headers.update(self.vo_header) result = TestApp(APP.wsgifunc(*options)).get('/ssh', headers=headers, expect_errors=True) assert result.status == 200 assert len(result.header('X-Rucio-Auth-Token')) > 32 del_account_identity(PUBLIC_KEY, IdentityType.SSH, root)
def __get_token_ssh(self): """ Sends a request to get an auth token from the server and stores it as a class attribute. Uses SSH key exchange authentication. :returns: True if the token was successfully received. False otherwise. """ headers = {'X-Rucio-Account': self.account} private_key_path = self.creds['ssh_private_key'] if not path.exists(private_key_path): LOG.error('given private key (%s) doesn\'t exist' % private_key_path) return False if private_key_path is not None and not path.exists(private_key_path): LOG.error('given private key (%s) doesn\'t exist' % private_key_path) return False url = build_url(self.auth_host, path='auth/ssh_challenge_token') result = None for retry in range(self.AUTH_RETRIES + 1): try: result = self.session.get(url, headers=headers, verify=self.ca_cert) break except ConnectionError as error: if 'alert certificate expired' in str(error): raise CannotAuthenticate(str(error)) LOG.warning('ConnectionError: ' + str(error)) self.ca_cert = False if retry > self.request_retries: raise if not result: LOG.error('cannot get ssh_challenge_token') return False if result.status_code != codes.ok: # pylint: disable-msg=E1101 exc_cls, exc_msg = self._get_exception( headers=result.headers, status_code=result.status_code, data=result.content) raise exc_cls(exc_msg) self.ssh_challenge_token = result.headers[ 'x-rucio-ssh-challenge-token'] LOG.debug('got new ssh challenge token \'%s\'' % self.ssh_challenge_token) # sign the challenge token with the private key with open(private_key_path, 'r') as fd_private_key_path: private_key = fd_private_key_path.read() signature = ssh_sign(private_key, self.ssh_challenge_token) headers['X-Rucio-SSH-Signature'] = signature url = build_url(self.auth_host, path='auth/ssh') result = None for retry in range(self.AUTH_RETRIES + 1): try: result = self.session.get(url, headers=headers, verify=self.ca_cert) break except ConnectionError as error: if 'alert certificate expired' in str(error): raise CannotAuthenticate(str(error)) LOG.warning('ConnectionError: ' + str(error)) self.ca_cert = False if retry > self.request_retries: raise if not result: LOG.error('cannot get auth_token') return False if result.status_code != codes.ok: # pylint: disable-msg=E1101 exc_cls, exc_msg = self._get_exception( headers=result.headers, status_code=result.status_code, data=result.content) raise exc_cls(exc_msg) self.auth_token = result.headers['x-rucio-auth-token'] LOG.debug('got new token') return True