Skip to content

Commit 315249d

Browse files
authored
GG-32404: Add AuthenticationError (#22)
1 parent 3b8be56 commit 315249d

6 files changed

Lines changed: 100 additions & 15 deletions

File tree

pygridgain/connection/__init__.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
from pygridgain.constants import *
2929
from pygridgain.exceptions import (
30-
HandshakeError, ParameterError, SocketError, connection_errors,
30+
HandshakeError, ParameterError, SocketError, connection_errors, AuthenticationError,
3131
)
3232
from pygridgain.datatypes import Byte, ByteArrayObject, Int, Short, String, UUIDObject
3333
from pygridgain.datatypes.internal import Struct
@@ -41,6 +41,8 @@
4141

4242
from ..stream import BinaryStream, READ_BACKWARD
4343

44+
CLIENT_STATUS_AUTH_FAILURE = 2000
45+
4446

4547
class Connection:
4648
"""
@@ -204,6 +206,7 @@ def read_response(self) -> Union[dict, OrderedDict]:
204206
('version_minor', Short),
205207
('version_patch', Short),
206208
('message', String),
209+
('client_status', Int)
207210
])
208211
elif self.get_protocol_version() >= (1, 7, 0):
209212
response_end = Struct([
@@ -300,7 +303,7 @@ def _connect_version(
300303
# disconnect but keep in use
301304
self.close(release=False)
302305

303-
error_text = 'Handshake error: {}'.format(hs_response['message'])
306+
error_text = f'Handshake error: {hs_response["message"]}'
304307
# if handshake fails for any reason other than protocol mismatch
305308
# (i.e. authentication error), server version is 0.0.0
306309
if any([
@@ -318,6 +321,8 @@ def _connect_version(
318321
client_patch=protocol_version[2],
319322
**hs_response
320323
)
324+
elif hs_response['client_status'] == CLIENT_STATUS_AUTH_FAILURE:
325+
raise AuthenticationError(error_text)
321326
raise HandshakeError((
322327
hs_response['version_major'],
323328
hs_response['version_minor'],
@@ -422,7 +427,6 @@ def _recv(buffer, num_bytes):
422427
_recv(memoryview(data)[4:], response_len)
423428
return data
424429

425-
426430
def close(self, release=True):
427431
"""
428432
Try to mark socket closed, then unlink it. This is recommended but

pygridgain/exceptions.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ class ParseError(Exception):
2525
pass
2626

2727

28+
class AuthenticationError(Exception):
29+
"""
30+
This exception is raised on authentication failure.
31+
"""
32+
33+
def __init__(self, message: str):
34+
self.message = message
35+
36+
2837
class HandshakeError(SocketError):
2938
"""
3039
This exception is raised on GridGain binary protocol handshake failure,

tests/config/ignite-config.xml.jinja2

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,18 @@
2626
http://www.springframework.org/schema/util/spring-util.xsd">
2727

2828
<bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
29-
{% if use_ssl %}
30-
<property name="connectorConfiguration"><null/></property>
29+
{% if enable_auth %}
30+
<property name="authenticationEnabled" value="true"/>
31+
32+
<property name="persistentStoreConfiguration">
33+
<bean class="org.apache.ignite.configuration.PersistentStoreConfiguration"/>
34+
</property>
35+
36+
<property name="connectorConfiguration">
37+
<bean class="org.apache.ignite.configuration.ConnectorConfiguration">
38+
<property name="port" value="{{ connector_port }}"/>
39+
</bean>
40+
</property>
3141
{% endif %}
3242

3343
<property name="clientConnectorConfiguration">

tests/conftest.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,15 @@ def server3(request):
8282

8383
@pytest.fixture(scope='module')
8484
def start_ignite_server(use_ssl):
85-
def start(idx=1, cluster_idx=1, jvm_opts=''):
86-
return _start_ignite(idx, use_ssl=use_ssl, cluster_idx=cluster_idx, jvm_opts=jvm_opts)
85+
def start(idx=1, debug=False, enable_auth=False, cluster_idx=1, jvm_opts=''):
86+
return _start_ignite(
87+
idx=idx,
88+
debug=debug,
89+
use_ssl=use_ssl,
90+
enable_auth=enable_auth,
91+
cluster_idx=cluster_idx,
92+
jvm_opts=jvm_opts
93+
)
8794

8895
return start
8996

@@ -136,10 +143,9 @@ def cache(client):
136143

137144
@pytest.fixture(scope='module')
138145
def start_client(use_ssl, ssl_keyfile, ssl_keyfile_password, ssl_certfile, ssl_ca_certfile, ssl_cert_reqs, ssl_ciphers,
139-
ssl_version,username, password):
146+
ssl_version, username, password):
140147
def start(**kwargs):
141-
cli_kw = kwargs.copy()
142-
cli_kw.update({
148+
cli_kw = {
143149
'use_ssl': use_ssl,
144150
'ssl_keyfile': ssl_keyfile,
145151
'ssl_keyfile_password': ssl_keyfile_password,
@@ -150,7 +156,8 @@ def start(**kwargs):
150156
'ssl_version': ssl_version,
151157
'username': username,
152158
'password': password
153-
})
159+
}
160+
cli_kw.update(kwargs.copy())
154161
return Client(**cli_kw)
155162

156163
return start

tests/test_connection.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#
2+
# Copyright 2019 GridGain Systems, Inc. and Contributors.
3+
#
4+
# Licensed under the GridGain Community Edition License (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
import pytest
17+
18+
from pygridgain.exceptions import AuthenticationError
19+
from tests.util import kill_process_tree, clear_workdir
20+
21+
22+
def test_auth_success(start_ignite_server, start_client):
23+
clear_workdir()
24+
25+
server_id = 10
26+
server = start_ignite_server(idx=server_id, cluster_idx=2, enable_auth=True)
27+
try:
28+
client = start_client(username='ignite', password='ignite')
29+
client.connect('127.0.0.1', 10800 + server_id)
30+
finally:
31+
kill_process_tree(server.pid)
32+
33+
34+
def test_auth_failure(start_ignite_server, start_client):
35+
clear_workdir()
36+
37+
server_id = 10
38+
server = start_ignite_server(idx=server_id, cluster_idx=2, enable_auth=True, debug=True)
39+
try:
40+
client = start_client(username='incorrect-user-name', password='incorrect-password')
41+
with pytest.raises(AuthenticationError) as auth_error:
42+
client.connect('127.0.0.1', 10800 + server_id)
43+
assert auth_error.match('Handshake error: The user name or password is incorrect')
44+
finally:
45+
kill_process_tree(server.pid)

tests/util.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import glob
1818
import os
19+
import shutil
1920

2021
import jinja2 as jinja2
2122
import psutil
@@ -113,7 +114,7 @@ def create_config_file(tpl_name, file_name, **kwargs):
113114
f.write(template.render(**kwargs))
114115

115116

116-
def _start_ignite(idx=1, debug=False, use_ssl=False, cluster_idx=1, jvm_opts=''):
117+
def _start_ignite(idx=1, debug=False, use_ssl=False, enable_auth=False, cluster_idx=1, jvm_opts=''):
117118
clear_logs(idx)
118119

119120
runner = get_ignite_runner()
@@ -123,19 +124,21 @@ def _start_ignite(idx=1, debug=False, use_ssl=False, cluster_idx=1, jvm_opts='')
123124
if debug:
124125
env["JVM_OPTS"] = env.get("JVM_OPTS", '') + \
125126
"-Djava.net.preferIPv4Stack=true -Xdebug -Xnoagent -Djava.compiler=NONE " \
126-
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address={5005} "
127+
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 "
127128

128129
if jvm_opts:
129130
env["JVM_OPTS"] = env.get("JVM_OPTS", '') + jvm_opts
130131

131132
port_offset = (cluster_idx - 1) * 10
132133
params = {
133-
'ignite_instance_idx': str(idx),
134+
'ignite_instance_idx': idx,
134135
'ignite_client_port': 10800 + idx,
135136
'use_ssl': use_ssl,
137+
'enable_auth': enable_auth,
136138
'discovery_port': 48500 + port_offset,
137139
'discovery_port_range': 48510 + port_offset,
138140
'communication_port': 48100 + port_offset,
141+
'connector_port': 10080 + idx,
139142
}
140143

141144
create_config_file('log4j.xml.jinja2', f'log4j-{idx}.xml', **params)
@@ -146,7 +149,7 @@ def _start_ignite(idx=1, debug=False, use_ssl=False, cluster_idx=1, jvm_opts='')
146149

147150
srv = subprocess.Popen(ignite_cmd, env=env, cwd=get_test_dir())
148151

149-
started = wait_for_condition(lambda: check_server_started(idx), timeout=30)
152+
started = wait_for_condition(lambda: check_server_started(idx), timeout=60)
150153
if started:
151154
return srv
152155

@@ -168,3 +171,10 @@ def get_log_files(idx=1):
168171
def clear_logs(idx=1):
169172
for f in get_log_files(idx):
170173
os.remove(f)
174+
175+
176+
def clear_workdir():
177+
for path in get_ignite_dirs():
178+
work_dir = os.path.join(path, 'work')
179+
if os.path.exists(work_dir):
180+
shutil.rmtree(work_dir, ignore_errors=True)

0 commit comments

Comments
 (0)