From 889bf359e1766a9167c152f0620f8cfd9f45903e Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Fri, 12 Jun 2020 11:50:07 +0300 Subject: [PATCH] Password setup - backend fixes --- monkey/monkey_island/cc/app.py | 2 +- .../monkey_island/cc/environment/__init__.py | 6 +- monkey/monkey_island/cc/environment/aws.py | 3 +- .../cc/environment/environment_config.py | 5 +- .../monkey_island/cc/environment/password.py | 3 +- .../monkey_island/cc/environment/standard.py | 2 +- .../cc/environment/test__init__.py | 19 ++++- .../monkey_island/cc/environment/test_aws.py | 2 +- .../cc/environment/user_creds.py | 2 +- .../cc/resources/attack/attack_config.py | 2 +- .../cc/resources/attack/attack_report.py | 2 +- .../cc/resources/auth/__init__.py | 0 .../cc/{ => resources/auth}/auth.py | 9 +- .../cc/{ => resources/auth}/auth_user.py | 0 .../cc/resources/auth/user_store.py | 15 ++++ .../cc/resources/island_configuration.py | 2 +- .../monkey_island/cc/resources/island_logs.py | 2 +- monkey/monkey_island/cc/resources/log.py | 2 +- .../cc/resources/monkey_configuration.py | 2 +- monkey/monkey_island/cc/resources/netmap.py | 2 +- monkey/monkey_island/cc/resources/node.py | 2 +- .../monkey_island/cc/resources/node_states.py | 2 +- .../cc/resources/pba_file_upload.py | 2 +- .../cc/resources/registration.py | 4 +- .../monkey_island/cc/resources/remote_run.py | 2 +- .../cc/resources/reporting/report.py | 2 +- monkey/monkey_island/cc/resources/root.py | 2 +- .../monkey_island/cc/resources/telemetry.py | 2 +- .../cc/resources/telemetry_feed.py | 2 +- .../cc/resources/test/clear_caches.py | 2 +- .../cc/resources/test/log_test.py | 2 +- .../cc/resources/test/monkey_test.py | 2 +- .../cc/resources/zero_trust/finding_event.py | 2 +- .../cc/ui/src/components/Main.js | 60 ++++++++----- .../cc/ui/src/components/pages/LoginPage.js | 13 ++- .../ui/src/components/pages/RegisterPage.js | 85 +++++++++++++++++++ .../cc/ui/src/services/AuthService.js | 37 +++++++- 37 files changed, 243 insertions(+), 62 deletions(-) create mode 100644 monkey/monkey_island/cc/resources/auth/__init__.py rename monkey/monkey_island/cc/{ => resources/auth}/auth.py (79%) rename monkey/monkey_island/cc/{ => resources/auth}/auth_user.py (100%) create mode 100644 monkey/monkey_island/cc/resources/auth/user_store.py create mode 100644 monkey/monkey_island/cc/ui/src/components/pages/RegisterPage.js diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index 4b887d94b..e480d2cd5 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -5,7 +5,7 @@ import flask_restful from flask import Flask, send_from_directory, Response from werkzeug.exceptions import NotFound -from monkey_island.cc.auth import init_jwt +from monkey_island.cc.resources.auth.auth import init_jwt from monkey_island.cc.database import mongo, database from monkey_island.cc.environment.environment_singleton import env from monkey_island.cc.resources.client_run import ClientRun diff --git a/monkey/monkey_island/cc/environment/__init__.py b/monkey/monkey_island/cc/environment/__init__.py index 62a702d73..adcb8aed0 100644 --- a/monkey/monkey_island/cc/environment/__init__.py +++ b/monkey/monkey_island/cc/environment/__init__.py @@ -5,7 +5,6 @@ from datetime import timedelta __author__ = 'itay.mizeretz' -from typing import Dict from common.utils.exceptions import InvalidRegistrationCredentials from monkey_island.cc.environment.environment_config import EnvironmentConfig @@ -25,7 +24,7 @@ class Environment(object, metaclass=ABCMeta): _testing = False def __init__(self): - self._config = None + self._config = EnvironmentConfig("", "", UserCreds()) self._testing = False # Assume env is not for unit testing. @property @@ -40,6 +39,9 @@ class Environment(object, metaclass=ABCMeta): def try_add_user(self, credentials: UserCreds): if self._credentials_required: if credentials: + if self._is_registered(): + raise InvalidRegistrationCredentials("User has already been registered. " + "Reset credentials or login.") self._config.add_user(credentials) else: raise InvalidRegistrationCredentials("Missing part of credentials.") diff --git a/monkey/monkey_island/cc/environment/aws.py b/monkey/monkey_island/cc/environment/aws.py index 96b74556d..b42fa910e 100644 --- a/monkey/monkey_island/cc/environment/aws.py +++ b/monkey/monkey_island/cc/environment/aws.py @@ -1,5 +1,4 @@ -import monkey_island.cc.auth -from monkey_island.cc.auth_user import User +from monkey_island.cc.resources.auth.auth_user import User from monkey_island.cc.environment import Environment from common.cloud.aws.aws_instance import AwsInstance diff --git a/monkey/monkey_island/cc/environment/environment_config.py b/monkey/monkey_island/cc/environment/environment_config.py index 20d70ef9e..4a50fb7cc 100644 --- a/monkey/monkey_island/cc/environment/environment_config.py +++ b/monkey/monkey_island/cc/environment/environment_config.py @@ -4,9 +4,10 @@ import json import os from typing import List, Dict -from monkey_island.cc.auth_user import User +from monkey_island.cc.resources.auth.auth_user import User from monkey_island.cc.consts import MONKEY_ISLAND_ABS_PATH from monkey_island.cc.environment.user_creds import UserCreds +from monkey_island.cc.resources.auth.user_store import UserStore class EnvironmentConfig: @@ -60,6 +61,8 @@ class EnvironmentConfig: def add_user(self, credentials: UserCreds): self.user_creds = credentials + self.save_to_file() + UserStore.set_users(self.get_users()) def get_users(self) -> List[User]: auth_user = self.user_creds.to_auth_user() diff --git a/monkey/monkey_island/cc/environment/password.py b/monkey/monkey_island/cc/environment/password.py index e181feb7c..8cfd495d2 100644 --- a/monkey/monkey_island/cc/environment/password.py +++ b/monkey/monkey_island/cc/environment/password.py @@ -1,5 +1,4 @@ from monkey_island.cc.environment import Environment -import monkey_island.cc.auth __author__ = 'itay.mizeretz' @@ -10,6 +9,6 @@ class PasswordEnvironment(Environment): def get_auth_users(self): if self._is_registered(): - return self._config.get_users + return self._config.get_users() else: return [] diff --git a/monkey/monkey_island/cc/environment/standard.py b/monkey/monkey_island/cc/environment/standard.py index 8f18824db..08851c94a 100644 --- a/monkey/monkey_island/cc/environment/standard.py +++ b/monkey/monkey_island/cc/environment/standard.py @@ -1,4 +1,4 @@ -from monkey_island.cc.auth_user import User +from monkey_island.cc.resources.auth.auth_user import User from monkey_island.cc.environment import Environment __author__ = 'itay.mizeretz' diff --git a/monkey/monkey_island/cc/environment/test__init__.py b/monkey/monkey_island/cc/environment/test__init__.py index ddca7e535..3115023a5 100644 --- a/monkey/monkey_island/cc/environment/test__init__.py +++ b/monkey/monkey_island/cc/environment/test__init__.py @@ -2,8 +2,10 @@ import json import os from typing import Dict from unittest import TestCase +from unittest.mock import patch, MagicMock -from monkey_island.cc.environment import Environment, EnvironmentConfig +from common.utils.exceptions import InvalidRegistrationCredentials +from monkey_island.cc.environment import Environment, EnvironmentConfig, UserCreds def get_server_config_file_path_test_version(): @@ -57,6 +59,21 @@ class TestEnvironment(TestCase): "4f2e9b3ca9f484f521d0ce464345cc1aec96779149c14" } + @patch.object(target=EnvironmentConfig, attribute="save_to_file", new=MagicMock()) + def test_try_add_user(self): + env = TestEnvironment.EnvironmentWithCredentials() + credentials = UserCreds(username="test", password_hash="1231234") + env.try_add_user(credentials) + + credentials = UserCreds(username="test") + with self.assertRaises(InvalidRegistrationCredentials): + env.try_add_user(credentials) + + env = TestEnvironment.EnvironmentNoCredentials() + credentials = UserCreds(username="test", password_hash="1231234") + with self.assertRaises(InvalidRegistrationCredentials): + env.try_add_user(credentials) + def test_needs_registration(self): env = TestEnvironment.EnvironmentWithCredentials() self._test_bool_env_method("needs_registration", env, TestEnvironment.CONFIG_WITH_CREDENTIALS, False) diff --git a/monkey/monkey_island/cc/environment/test_aws.py b/monkey/monkey_island/cc/environment/test_aws.py index 5cd37501a..65f8c3e58 100644 --- a/monkey/monkey_island/cc/environment/test_aws.py +++ b/monkey/monkey_island/cc/environment/test_aws.py @@ -1,4 +1,4 @@ -from monkey_island.cc.auth_user import User +from monkey_island.cc.resources.auth.auth_user import User from monkey_island.cc.testing.IslandTestCase import IslandTestCase from monkey_island.cc.environment.aws import AwsEnvironment diff --git a/monkey/monkey_island/cc/environment/user_creds.py b/monkey/monkey_island/cc/environment/user_creds.py index d60c61720..7d6ca4962 100644 --- a/monkey/monkey_island/cc/environment/user_creds.py +++ b/monkey/monkey_island/cc/environment/user_creds.py @@ -3,7 +3,7 @@ from __future__ import annotations import json from typing import Dict -from monkey_island.cc.auth_user import User +from monkey_island.cc.resources.auth.auth_user import User class UserCreds: diff --git a/monkey/monkey_island/cc/resources/attack/attack_config.py b/monkey/monkey_island/cc/resources/attack/attack_config.py index 021663521..129297b19 100644 --- a/monkey/monkey_island/cc/resources/attack/attack_config.py +++ b/monkey/monkey_island/cc/resources/attack/attack_config.py @@ -1,7 +1,7 @@ import flask_restful from flask import jsonify, request, json, current_app -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.attack.attack_config import AttackConfig __author__ = "VakarisZ" diff --git a/monkey/monkey_island/cc/resources/attack/attack_report.py b/monkey/monkey_island/cc/resources/attack/attack_report.py index dc63f6747..aa7a28a09 100644 --- a/monkey/monkey_island/cc/resources/attack/attack_report.py +++ b/monkey/monkey_island/cc/resources/attack/attack_report.py @@ -1,5 +1,5 @@ import flask_restful -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.attack.attack_report import AttackReportService from monkey_island.cc.services.attack.attack_schema import SCHEMA from flask import json, current_app diff --git a/monkey/monkey_island/cc/resources/auth/__init__.py b/monkey/monkey_island/cc/resources/auth/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/monkey/monkey_island/cc/auth.py b/monkey/monkey_island/cc/resources/auth/auth.py similarity index 79% rename from monkey/monkey_island/cc/auth.py rename to monkey/monkey_island/cc/resources/auth/auth.py index 0bbb385b0..c582f8706 100644 --- a/monkey/monkey_island/cc/auth.py +++ b/monkey/monkey_island/cc/resources/auth/auth.py @@ -5,23 +5,22 @@ from flask_jwt import JWT, _jwt_required, JWTError from werkzeug.security import safe_str_cmp from monkey_island.cc.environment.environment_singleton import env +from monkey_island.cc.resources.auth.user_store import UserStore __author__ = 'itay.mizeretz' def init_jwt(app): - users = env.get_auth_users() - username_table = {u.username: u for u in users} - userid_table = {u.id: u for u in users} + UserStore.set_users(env.get_auth_users()) def authenticate(username, secret): - user = username_table.get(username, None) + user = UserStore.username_table.get(username, None) if user and safe_str_cmp(user.secret.encode('utf-8'), secret.encode('utf-8')): return user def identity(payload): user_id = payload['identity'] - return userid_table.get(user_id, None) + return UserStore.userid_table.get(user_id, None) JWT(app, authenticate, identity) diff --git a/monkey/monkey_island/cc/auth_user.py b/monkey/monkey_island/cc/resources/auth/auth_user.py similarity index 100% rename from monkey/monkey_island/cc/auth_user.py rename to monkey/monkey_island/cc/resources/auth/auth_user.py diff --git a/monkey/monkey_island/cc/resources/auth/user_store.py b/monkey/monkey_island/cc/resources/auth/user_store.py new file mode 100644 index 000000000..7cb43e222 --- /dev/null +++ b/monkey/monkey_island/cc/resources/auth/user_store.py @@ -0,0 +1,15 @@ +from typing import List + +from monkey_island.cc.resources.auth.auth_user import User + + +class UserStore: + users = [] + username_table = {} + userid_table = {} + + @staticmethod + def set_users(users: List[User]): + UserStore.users = users + UserStore.username_table = {u.username: u for u in UserStore.users} + UserStore.userid_table = {u.id: u for u in UserStore.users} diff --git a/monkey/monkey_island/cc/resources/island_configuration.py b/monkey/monkey_island/cc/resources/island_configuration.py index 28ef32c46..81f922263 100644 --- a/monkey/monkey_island/cc/resources/island_configuration.py +++ b/monkey/monkey_island/cc/resources/island_configuration.py @@ -3,7 +3,7 @@ import json import flask_restful from flask import request, jsonify, abort -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.config import ConfigService diff --git a/monkey/monkey_island/cc/resources/island_logs.py b/monkey/monkey_island/cc/resources/island_logs.py index 724087e52..5ef64789b 100644 --- a/monkey/monkey_island/cc/resources/island_logs.py +++ b/monkey/monkey_island/cc/resources/island_logs.py @@ -2,7 +2,7 @@ import logging import flask_restful -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.island_logs import IslandLogService __author__ = "Maor.Rayzin" diff --git a/monkey/monkey_island/cc/resources/log.py b/monkey/monkey_island/cc/resources/log.py index 920890648..b7b405ddf 100644 --- a/monkey/monkey_island/cc/resources/log.py +++ b/monkey/monkey_island/cc/resources/log.py @@ -4,7 +4,7 @@ import flask_restful from bson import ObjectId from flask import request -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.database import mongo from monkey_island.cc.resources.test.utils.telem_store import TestTelemStore from monkey_island.cc.services.log import LogService diff --git a/monkey/monkey_island/cc/resources/monkey_configuration.py b/monkey/monkey_island/cc/resources/monkey_configuration.py index 1c067892f..3877ec9ee 100644 --- a/monkey/monkey_island/cc/resources/monkey_configuration.py +++ b/monkey/monkey_island/cc/resources/monkey_configuration.py @@ -3,7 +3,7 @@ import json import flask_restful from flask import request, jsonify, abort -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.config import ConfigService __author__ = 'Barak' diff --git a/monkey/monkey_island/cc/resources/netmap.py b/monkey/monkey_island/cc/resources/netmap.py index 3b7e471d8..221a8c60a 100644 --- a/monkey/monkey_island/cc/resources/netmap.py +++ b/monkey/monkey_island/cc/resources/netmap.py @@ -1,6 +1,6 @@ import flask_restful -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.edge import EdgeService from monkey_island.cc.services.node import NodeService from monkey_island.cc.database import mongo diff --git a/monkey/monkey_island/cc/resources/node.py b/monkey/monkey_island/cc/resources/node.py index e4c2761c9..a38af4b48 100644 --- a/monkey/monkey_island/cc/resources/node.py +++ b/monkey/monkey_island/cc/resources/node.py @@ -1,7 +1,7 @@ from flask import request import flask_restful -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.node import NodeService __author__ = 'Barak' diff --git a/monkey/monkey_island/cc/resources/node_states.py b/monkey/monkey_island/cc/resources/node_states.py index bb5a978b6..3a4e674cc 100644 --- a/monkey/monkey_island/cc/resources/node_states.py +++ b/monkey/monkey_island/cc/resources/node_states.py @@ -1,6 +1,6 @@ import flask_restful -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.utils.node_states import NodeStates as NodeStateList diff --git a/monkey/monkey_island/cc/resources/pba_file_upload.py b/monkey/monkey_island/cc/resources/pba_file_upload.py index 3a636459c..2d1954c31 100644 --- a/monkey/monkey_island/cc/resources/pba_file_upload.py +++ b/monkey/monkey_island/cc/resources/pba_file_upload.py @@ -2,7 +2,7 @@ import flask_restful from flask import request, send_from_directory, Response from monkey_island.cc.services.config import ConfigService from monkey_island.cc.services.post_breach_files import PBA_WINDOWS_FILENAME_PATH, PBA_LINUX_FILENAME_PATH, UPLOADS_DIR -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required import os from werkzeug.utils import secure_filename import logging diff --git a/monkey/monkey_island/cc/resources/registration.py b/monkey/monkey_island/cc/resources/registration.py index 0e55b697a..237972ee6 100644 --- a/monkey/monkey_island/cc/resources/registration.py +++ b/monkey/monkey_island/cc/resources/registration.py @@ -14,7 +14,7 @@ class Registration(flask_restful.Resource): credentials = UserCreds.get_from_json(request.data) try: env.try_add_user(credentials) - return make_response({"error": ""}, 300) + return make_response({"error": ""}, 200) except InvalidRegistrationCredentials as e: - return make_response({"error": e}, 400) + return make_response({"error": str(e)}, 400) diff --git a/monkey/monkey_island/cc/resources/remote_run.py b/monkey/monkey_island/cc/resources/remote_run.py index 98d3694bf..1d9cdf4d6 100644 --- a/monkey/monkey_island/cc/resources/remote_run.py +++ b/monkey/monkey_island/cc/resources/remote_run.py @@ -4,7 +4,7 @@ from botocore.exceptions import NoCredentialsError, ClientError from flask import request, jsonify, make_response import flask_restful -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService from common.cloud.aws.aws_service import AwsService diff --git a/monkey/monkey_island/cc/resources/reporting/report.py b/monkey/monkey_island/cc/resources/reporting/report.py index 961e745a8..6197b1e0c 100644 --- a/monkey/monkey_island/cc/resources/reporting/report.py +++ b/monkey/monkey_island/cc/resources/reporting/report.py @@ -3,7 +3,7 @@ import http.client import flask_restful from flask import jsonify -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.reporting.report import ReportService from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService diff --git a/monkey/monkey_island/cc/resources/root.py b/monkey/monkey_island/cc/resources/root.py index 5b319072b..18521a377 100644 --- a/monkey/monkey_island/cc/resources/root.py +++ b/monkey/monkey_island/cc/resources/root.py @@ -4,7 +4,7 @@ import threading import flask_restful from flask import request, make_response, jsonify -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.database import mongo from monkey_island.cc.services.database import Database from monkey_island.cc.services.infection_lifecycle import InfectionLifecycle diff --git a/monkey/monkey_island/cc/resources/telemetry.py b/monkey/monkey_island/cc/resources/telemetry.py index f6e833eeb..a8d7c2fbd 100644 --- a/monkey/monkey_island/cc/resources/telemetry.py +++ b/monkey/monkey_island/cc/resources/telemetry.py @@ -6,7 +6,7 @@ import dateutil import flask_restful from flask import request -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.database import mongo from monkey_island.cc.resources.test.utils.telem_store import TestTelemStore from monkey_island.cc.services.node import NodeService diff --git a/monkey/monkey_island/cc/resources/telemetry_feed.py b/monkey/monkey_island/cc/resources/telemetry_feed.py index 6333f2feb..cb35fcf82 100644 --- a/monkey/monkey_island/cc/resources/telemetry_feed.py +++ b/monkey/monkey_island/cc/resources/telemetry_feed.py @@ -6,7 +6,7 @@ import flask_restful from flask import request import flask_pymongo -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.database import mongo from monkey_island.cc.services.node import NodeService diff --git a/monkey/monkey_island/cc/resources/test/clear_caches.py b/monkey/monkey_island/cc/resources/test/clear_caches.py index f17193821..525841803 100644 --- a/monkey/monkey_island/cc/resources/test/clear_caches.py +++ b/monkey/monkey_island/cc/resources/test/clear_caches.py @@ -2,7 +2,7 @@ import logging import flask_restful -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.attack.attack_report import AttackReportService from monkey_island.cc.services.reporting.report import ReportService diff --git a/monkey/monkey_island/cc/resources/test/log_test.py b/monkey/monkey_island/cc/resources/test/log_test.py index f0f9af936..60222deac 100644 --- a/monkey/monkey_island/cc/resources/test/log_test.py +++ b/monkey/monkey_island/cc/resources/test/log_test.py @@ -2,7 +2,7 @@ from bson import json_util import flask_restful from flask import request -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.database import mongo, database diff --git a/monkey/monkey_island/cc/resources/test/monkey_test.py b/monkey/monkey_island/cc/resources/test/monkey_test.py index 100624780..900fde6ae 100644 --- a/monkey/monkey_island/cc/resources/test/monkey_test.py +++ b/monkey/monkey_island/cc/resources/test/monkey_test.py @@ -2,7 +2,7 @@ from bson import json_util import flask_restful from flask import request -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.database import mongo diff --git a/monkey/monkey_island/cc/resources/zero_trust/finding_event.py b/monkey/monkey_island/cc/resources/zero_trust/finding_event.py index 16c545241..44f686235 100644 --- a/monkey/monkey_island/cc/resources/zero_trust/finding_event.py +++ b/monkey/monkey_island/cc/resources/zero_trust/finding_event.py @@ -1,7 +1,7 @@ import flask_restful import json -from monkey_island.cc.auth import jwt_required +from monkey_island.cc.resources.auth.auth import jwt_required from monkey_island.cc.services.reporting.zero_trust_service import ZeroTrustService diff --git a/monkey/monkey_island/cc/ui/src/components/Main.js b/monkey/monkey_island/cc/ui/src/components/Main.js index 4e8c0b1a0..07f9638d6 100644 --- a/monkey/monkey_island/cc/ui/src/components/Main.js +++ b/monkey/monkey_island/cc/ui/src/components/Main.js @@ -1,9 +1,9 @@ import React from 'react'; import {BrowserRouter as Router, NavLink, Redirect, Route, Switch} from 'react-router-dom'; import {Col, Grid, Row} from 'react-bootstrap'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faCheck } from '@fortawesome/free-solid-svg-icons/faCheck' -import { faUndo } from '@fortawesome/free-solid-svg-icons/faUndo' +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome' +import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck' +import {faUndo} from '@fortawesome/free-solid-svg-icons/faUndo' import RunServerPage from 'components/pages/RunServerPage'; import ConfigurePage from 'components/pages/ConfigurePage'; @@ -15,6 +15,7 @@ import ReportPage from 'components/pages/ReportPage'; import LicensePage from 'components/pages/LicensePage'; import AuthComponent from 'components/AuthComponent'; import LoginPageComponent from 'components/pages/LoginPage'; +import RegisterPageComponent from 'components/pages/RegisterPage'; import Notifier from 'react-desktop-notification'; import NotFoundPage from 'components/pages/NotFoundPage'; @@ -43,6 +44,15 @@ class AppComponent extends AuthComponent { }); } + if (!res){ + this.auth.needsRegistration() + .then(result => { + this.setState({ + needsRegistration: result + }); + }) + } + if (res) { this.authFetch('/api') .then(res => res.json()) @@ -70,10 +80,16 @@ class AppComponent extends AuthComponent { case true: return page_component; case false: - return ; + switch (this.state.needsRegistration){ + case true: + return + case false: + return ; + default: + return page_component; + } default: return page_component; - } }; @@ -85,8 +101,8 @@ class AppComponent extends AuthComponent { }; redirectTo = (userPath, targetPath) => { - let pathQuery = new RegExp(userPath+'[\/]?$', 'g'); - if(window.location.pathname.match(pathQuery)){ + let pathQuery = new RegExp(userPath + '[\/]?$', 'g'); + if (window.location.pathname.match(pathQuery)) { return } }; @@ -100,7 +116,8 @@ class AppComponent extends AuthComponent { run_monkey: false, infection_done: false, report_done: false, - isLoggedIn: undefined + isLoggedIn: undefined, + needsRegistration: undefined } }; } @@ -201,19 +218,20 @@ class AppComponent extends AuthComponent { - ()}/> - {this.renderRoute('/', , true)} - {this.renderRoute('/configure', )} - {this.renderRoute('/run-monkey', )} - {this.renderRoute('/infection/map', )} - {this.renderRoute('/infection/telemetry', )} - {this.renderRoute('/start-over', )} - {this.redirectTo('/report', '/report/security')} - {this.renderRoute('/report/security', )} - {this.renderRoute('/report/attack', )} - {this.renderRoute('/report/zeroTrust', )} - {this.renderRoute('/license', )} - + ()}/> + ()}/> + {this.renderRoute('/', , true)} + {this.renderRoute('/configure', )} + {this.renderRoute('/run-monkey', )} + {this.renderRoute('/infection/map', )} + {this.renderRoute('/infection/telemetry', )} + {this.renderRoute('/start-over', )} + {this.redirectTo('/report', '/report/security')} + {this.renderRoute('/report/security', )} + {this.renderRoute('/report/attack', )} + {this.renderRoute('/report/zeroTrust', )} + {this.renderRoute('/license', )} + diff --git a/monkey/monkey_island/cc/ui/src/components/pages/LoginPage.js b/monkey/monkey_island/cc/ui/src/components/pages/LoginPage.js index 2fdba21aa..dc2406802 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/LoginPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/LoginPage.js @@ -1,7 +1,7 @@ import React from 'react'; import {Col} from 'react-bootstrap'; -import AuthService from '../../services/AuthService' +import AuthService from '../../services/AuthService'; class LoginPageComponent extends React.Component { login = () => { @@ -26,6 +26,10 @@ class LoginPageComponent extends React.Component { window.location.href = '/'; }; + redirectToRegistration = () => { + window.location.href = '/register'; + }; + constructor(props) { super(props); this.username = ''; @@ -34,6 +38,13 @@ class LoginPageComponent extends React.Component { this.state = { failed: false }; + + this.auth.needsRegistration() + .then(result => { + if(result){ + this.redirectToRegistration() + } + }) this.auth.loggedIn() .then(res => { if (res) { diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RegisterPage.js b/monkey/monkey_island/cc/ui/src/components/pages/RegisterPage.js new file mode 100644 index 000000000..13ae82ddd --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RegisterPage.js @@ -0,0 +1,85 @@ +import React from 'react'; +import {Col} from 'react-bootstrap'; + +import AuthService from '../../services/AuthService'; + +class RegisterPageComponent extends React.Component { + + register = () => { + this.auth.register(this.username, this.password).then(res => { + this.setState({failed: false, error: ""}); + if (res['result']) { + this.redirectToHome(); + } else { + this.setState({failed: true, + error: res['error']}); + } + }); + }; + updateUsername = (evt) => { + this.username = evt.target.value; + }; + + updatePassword = (evt) => { + this.password = evt.target.value; + }; + redirectToHome = () => { + window.location.href = '/'; + }; + + constructor(props) { + super(props); + this.username = ''; + this.password = ''; + this.auth = new AuthService(); + this.state = { + failed: false, + loading: false + }; + + this.auth.needsRegistration() + .then(result => { + if(!result){ + this.redirectToHome() + } + }) + } + + render() { + return ( + +

First time?

+

Let's secure your island

+
+
+
+ Register +
+
+
+ this.updateUsername(evt)}/> + this.updatePassword(evt)}/> + + { + this.state.failed ? +
{this.state.error}
+ : + '' + } +
+
+
+
+ + ); + } +} + +export default RegisterPageComponent; diff --git a/monkey/monkey_island/cc/ui/src/services/AuthService.js b/monkey/monkey_island/cc/ui/src/services/AuthService.js index 6163e95cd..19454b231 100644 --- a/monkey/monkey_island/cc/ui/src/services/AuthService.js +++ b/monkey/monkey_island/cc/ui/src/services/AuthService.js @@ -8,6 +8,8 @@ export default class AuthService { '8d2c8d0b1538d2208c1444ac66535b764a3d902b35e751df3faec1e477ed3557'; SECONDS_BEFORE_JWT_EXPIRES = 20; + AUTHENTICATION_API_ENDPOINT = '/api/auth'; + REGISTRATION_API_ENDPOINT = '/api/registration'; login = (username, password) => { return this._login(username, this.hashSha3(password)); @@ -30,7 +32,7 @@ export default class AuthService { } _login = (username, password) => { - return this._authFetch('/api/auth', { + return this._authFetch(this.AUTHENTICATION_API_ENDPOINT, { method: 'POST', body: JSON.stringify({ username, @@ -48,6 +50,28 @@ export default class AuthService { }) }; + register = (username, password) => { + return this._register(username, this.hashSha3(password)); + }; + + _register = (username, password) => { + return this._authFetch(this.REGISTRATION_API_ENDPOINT, { + method: 'POST', + body: JSON.stringify({ + 'user': username, + 'password_hash': password + }) + }).then(res => { + if (res.status === 200) { + return this._login(username, password) + } else { + return res.json().then(res_json => { + return {result: false, error: res_json['error']}; + }) + } + }) + }; + _authFetch = (url, options = {}) => { const headers = { 'Accept': 'application/json', @@ -72,7 +96,16 @@ export default class AuthService { this._removeToken(); } return res; - }); + }) + }; + + needsRegistration = () => { + return fetch(this.REGISTRATION_API_ENDPOINT, + {method: 'GET'}) + .then(response => response.json()) + .then(res => { + return res['needs_registration'] + }) }; async loggedIn() {