Skip to content

Commit

Permalink
Merge branch '2fa-dev' of github.com:introlab/opentera into 2fa-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
doumdi committed Oct 7, 2024
2 parents a08f314 + 168f631 commit 5b90d8a
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ def post(self):
if new_password != confirm_password:
return gettext('New password and confirm password do not match'), 400

if not current_user.user_force_password_change:
return gettext('User not required to change password'), 400

# Change password, will be encrypted
# Will also reset force password change flag
try:
Expand All @@ -43,7 +46,7 @@ def post(self):
except UserNewPasswordSameAsOld:
return gettext('New password same as old password'), 400

return redirect(self._generate_login_url())
return 200
except Exception as e:
# Something went wrong, logout user
self._user_logout()
Expand Down
7 changes: 4 additions & 3 deletions teraserver/python/templates/login_change_password.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
// Send the form data to the backend with a post request
$.ajax({
type: "POST",
url: $(this).action,
url: 'api/user/login/change_password',
data: form.serialize(),
success: function(response) {
$('#dlgRedirect').removeClass("d-none").addClass("d-flex");
Expand All @@ -77,7 +77,8 @@
error: function(response) {
if (response.status === 401)
redirectToLogin();
$('#error_message')[0].innerHTML = response.responseText;
$('#error_message')[0].innerHTML = response.responseText.substring(1, response.responseText.length-2);
//$('#error_message').text(response.responseJSON);
$('#error_message').show();
}
});
Expand All @@ -104,7 +105,7 @@
<div id="timeLeft" class="">5:00</div>
</div>
<div class="card-body">
<form action="/login_change_password" method="post" id="password_change_form">
<form method="post" id="password_change_form">
<div class="form-group row">
<label for="new_password" class="col-md-4 col-form-label text-md-right">{{ gettext('New Password') }}</label>
<div class="col-md-6">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ def tearDown(self):
TeraUser.delete(self.user2['id_user'], hard_delete=True)
super().tearDown()


def _create_2fa_enabled_user(self, username, password, set_secret:bool = True):
user = TeraUser()
user.id_user = 0 # New user
Expand All @@ -41,7 +40,6 @@ def _create_2fa_enabled_user(self, username, password, set_secret:bool = True):
TeraUser.insert(user)
return user.to_json(minimal=False)


def _login_user(self, username, password):
response = self._get_with_user_http_auth(self.test_client, username, password, endpoint='/api/user/login')
self.assertEqual(200, response.status_code)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
from tests.modules.FlaskModule.API.user.BaseUserAPITest import BaseUserAPITest
from opentera.db.models.TeraUser import TeraUser


class UserLoginChangePassword(BaseUserAPITest):
test_endpoint = '/api/user/login/change_password'

def setUp(self):
super().setUp()
# Create users with password change needed
with self._flask_app.app_context():
self.user1: dict = self._create_change_password_user('test_user_1', 'Password12345!')

def tearDown(self):
# Delete users with 2fa enabled
with self._flask_app.app_context():
TeraUser.delete(self.user1['id_user'], hard_delete=True)
super().tearDown()

@staticmethod
def _create_change_password_user(username, password):
user = TeraUser()
user.id_user = 0 # New user
user.user_username = username
user.user_password = password
user.user_firstname = username
user.user_lastname = username
user.user_email = f"{username}@test.com"
user.user_enabled = True
user.user_profile = {}
user.user_force_password_change = True

TeraUser.insert(user)
return user.to_json(minimal=False)

def _login_user(self, username, password):
response = self._get_with_user_http_auth(self.test_client, username, password, endpoint='/api/user/login')
self.assertEqual(200, response.status_code)
self.assertEqual('application/json', response.headers['Content-Type'])
self.assertGreater(len(response.json), 0)
return response

def test_post_endpoint_no_auth(self):
with self._flask_app.app_context():
response = self.test_client.post(self.test_endpoint)
self.assertEqual(401, response.status_code)

def test_post_endpoint_invalid_token_auth(self):
with self._flask_app.app_context():
response = self._post_with_user_token_auth(self.test_client, 'invalid')
self.assertEqual(401, response.status_code)

def test_post_endpoint_with_no_session(self):
with self._flask_app.app_context():
response = self.test_client.post(self.test_endpoint)
self.assertEqual(401, response.status_code)

def test_get_endpoint(self):
with self._flask_app.app_context():
response = self.test_client.get(self.test_endpoint)
self.assertEqual(405, response.status_code)

def test_post_password_without_force_required(self):
with self._flask_app.app_context():
# First login to create session
response = self._login_user('admin', 'admin')
self.assertEqual(200, response.status_code)
self.assertFalse('redirect_url' in response.json)

def test_post_password_change_mismatched(self):
with self._flask_app.app_context():
# First login to create session
response = self._login_user('test_user_1', 'Password12345!')
self.assertEqual(200, response.status_code)
self.assertTrue('redirect_url' in response.json)
self.assertTrue('login_change_password' in response.json['redirect_url'])

params = {'new_password': 'NewPassword12345!',
'confirm_password': 'NotNewPassword12345!'}
response = self.test_client.post(self.test_endpoint, json=params)
self.assertEqual(400, response.status_code)

def test_post_password_change_same_as_old(self):
with self._flask_app.app_context():
# First login to create session
response = self._login_user('test_user_1', 'Password12345!')
self.assertEqual(200, response.status_code)
self.assertTrue('redirect_url' in response.json)
self.assertTrue('login_change_password' in response.json['redirect_url'])

params = {'new_password': 'Password12345!',
'confirm_password': 'Password12345!'}
response = self.test_client.post(self.test_endpoint, json=params)
self.assertEqual(400, response.status_code)

def test_post_password_change_insecure(self):
with self._flask_app.app_context():
# First login to create session
response = self._login_user('test_user_1', 'Password12345!')
self.assertEqual(200, response.status_code)
self.assertTrue('redirect_url' in response.json)
self.assertTrue('login_change_password' in response.json['redirect_url'])

json_data = {'new_password': 'password', 'confirm_password': 'password'}
response = self.test_client.post(self.test_endpoint, json=json_data)
self.assertEqual(400, response.status_code, msg="Password not long enough")

json_data['new_password'] = 'password12345!'
json_data['confirm_password'] = json_data['new_password']
response = self.test_client.post(self.test_endpoint, json=json_data)
self.assertEqual(400, response.status_code, msg="Password without capital letters")

json_data['new_password'] = 'PASSWORD12345!'
json_data['confirm_password'] = json_data['new_password']
response = self.test_client.post(self.test_endpoint, json=json_data)
self.assertEqual(400, response.status_code, msg="Password without lower case letters")

json_data['new_password'] = 'Password12345'
json_data['confirm_password'] = json_data['new_password']
response = self.test_client.post(self.test_endpoint, json=json_data)
self.assertEqual(400, response.status_code, msg="Password without special characters")

json_data['new_password'] = 'Password!!!!'
json_data['confirm_password'] = json_data['new_password']
response = self.test_client.post(self.test_endpoint, json=json_data)
self.assertEqual(400, response.status_code, msg="Password without numbers")

json_data['new_password'] = 'Password12345!!'
json_data['confirm_password'] = json_data['new_password']
response = self.test_client.post(self.test_endpoint, json=json_data)
self.assertEqual(200, response.status_code, msg="Password OK")

# Reset to original password
user = TeraUser.get_user_by_id(self.user1['id_user'])
user.user_force_password_change = True
user.db().session.commit()

json_data['new_password'] = 'Password12345!'
json_data['confirm_password'] = json_data['new_password']
response = self.test_client.post(self.test_endpoint, json=json_data)
self.assertEqual(200, response.status_code, msg="Password back to last")

def test_post_password_change_not_required(self):
with self._flask_app.app_context():
# First login to create session
response = self._login_user('test_user_1', 'Password12345!')
self.assertEqual(200, response.status_code)
self.assertTrue('redirect_url' in response.json)
self.assertTrue('login_change_password' in response.json['redirect_url'])

user = TeraUser.get_user_by_id(self.user1['id_user'])
user.user_force_password_change = False
user.db().session.commit()

json_data = {'new_password': 'Password12345!!', 'confirm_password': 'Password12345!!'}
response = self.test_client.post(self.test_endpoint, json=json_data)
self.assertEqual(400, response.status_code, msg="Password not required to be changed")

user = TeraUser.get_user_by_id(self.user1['id_user'])
user.user_force_password_change = True
user.db().session.commit()

def test_post_password_change_ok(self):
with self._flask_app.app_context():
# First login to create session
response = self._login_user('test_user_1', 'Password12345!')
self.assertEqual(200, response.status_code)
self.assertTrue('redirect_url' in response.json)
self.assertTrue('login_change_password' in response.json['redirect_url'])

json_data = {'new_password': 'Password12345!!', 'confirm_password': 'Password12345!!'}
response = self.test_client.post(self.test_endpoint, json=json_data)
self.assertEqual(200, response.status_code, msg="Password OK")

# Reset to original password
user = TeraUser.get_user_by_id(self.user1['id_user'])
user.user_force_password_change = True
user.user_password = 'Password12345!'
user.db().session.commit()
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def test_get_endpoint_with_admin_without_2fa_enabled(self):
def test_get_endpoint_login_user1_2fa_already_setup(self):
with self._flask_app.app_context():

# Fisrt login to create session
# First login to create session
response = self._login_user('test_user_2fa_1', 'Password12345!')
self.assertEqual(200, response.status_code)
self.assertTrue('redirect_url' in response.json)
Expand Down

0 comments on commit 5b90d8a

Please sign in to comment.