diff --git a/monkey/monkey_island/Pipfile b/monkey/monkey_island/Pipfile index d95999cba..7e008e51d 100644 --- a/monkey/monkey_island/Pipfile +++ b/monkey/monkey_island/Pipfile @@ -32,6 +32,8 @@ marshmallow-enum = "*" readerwriterlock = "*" pymongo = "*" cryptography = "*" +flask-login = "*" +flask-wtf = "*" [dev-packages] virtualenv = ">=20.0.26" diff --git a/monkey/monkey_island/Pipfile.lock b/monkey/monkey_island/Pipfile.lock index babf8a552..50a23d677 100644 --- a/monkey/monkey_island/Pipfile.lock +++ b/monkey/monkey_island/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "09e1b190955d23328ac5e2de385904f7b109eb6b748e7ae9b2b5c7bfd62f690c" + "sha256": "6b6bff4ffa42faed7e784a6c6820aca5d882e0ec7ddf20834af42f46b5b551fa" }, "pipfile-spec": 6, "requires": { @@ -32,11 +32,11 @@ }, "attrs": { "hashes": [ - "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", - "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" + "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6", + "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.4.0" + "markers": "python_version >= '3.5'", + "version": "==22.1.0" }, "bcrypt": { "hashes": [ @@ -210,19 +210,27 @@ }, "flask": { "hashes": [ - "sha256:15972e5017df0575c3d6c090ba168b6db90259e620ac8d7ea813a396bad5b6cb", - "sha256:9013281a7402ad527f8fd56375164f3aa021ecfaff89bfe3825346c24f87e04c" + "sha256:10dc2bae7a9b6ab59111d6dbece2e08fb0015d2e88d296c40323cc0c7aac2c2e", + "sha256:98b33b13ad76ee9c7a80d2f56a6c578780e55bf8281790c62d50d4b7fadec2b8" ], "index": "pypi", - "version": "==2.1.3" + "version": "==2.2.0" }, "flask-jwt-extended": { "hashes": [ - "sha256:793f9e720d0e679cea8f99af6436819bfd1622fc345afeff48878c09f42548f6", - "sha256:f582bba980fcf728ab7250dbb6fbdca8d4e074e24eb2915b01184376ffff98c7" + "sha256:188907ea9332bdd123a95a457e7487556770480264ce3b78c8835b4347e324cc", + "sha256:a2571df484c5635ad996d364242ec28fc69f386915cd69b1842639712b84c36d" ], "index": "pypi", - "version": "==4.4.2" + "version": "==4.4.3" + }, + "flask-login": { + "hashes": [ + "sha256:1ef79843f5eddd0f143c2cd994c1b05ac83c0401dc6234c143495af9a939613f", + "sha256:c0a7baa9fdc448cdd3dd6f0939df72eec5177b2f7abe6cb82fc934d29caac9c3" + ], + "index": "pypi", + "version": "==0.6.2" }, "flask-pymongo": { "hashes": [ @@ -240,6 +248,14 @@ "index": "pypi", "version": "==0.3.9" }, + "flask-wtf": { + "hashes": [ + "sha256:34fe5c6fee0f69b50e30f81a3b7ea16aa1492a771fe9ad0974d164610c09a6c9", + "sha256:9d733658c80be551ce7d5bc13c7a7ac0d80df509be1e23827c847d9520f4359a" + ], + "index": "pypi", + "version": "==1.0.1" + }, "future": { "hashes": [ "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d" @@ -799,11 +815,11 @@ }, "setuptools": { "hashes": [ - "sha256:0d33c374d41c7863419fc8f6c10bfe25b7b498aa34164d135c622e52580c6b16", - "sha256:c04b44a57a6265fe34a4a444e965884716d34bae963119a76353434d6f18e450" + "sha256:273b6847ae61f7829c1affcdd9a32f67aa65233be508f4fbaab866c5faa4e408", + "sha256:d5340d16943a0f67057329db59b564e938bb3736c6e50ae16ea84d5e5d9ba6d0" ], "markers": "python_version >= '3.7'", - "version": "==63.2.0" + "version": "==63.3.0" }, "six": { "hashes": [ @@ -823,19 +839,19 @@ }, "urllib3": { "hashes": [ - "sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec", - "sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6" + "sha256:c33ccba33c819596124764c23a97d25f32b28433ba0dedeb77d873a38722c9bc", + "sha256:ea6e8fb210b19d950fab93b60c9009226c63a28808bc8386e05301e25883ac0a" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'", - "version": "==1.26.10" + "version": "==1.26.11" }, "werkzeug": { "hashes": [ - "sha256:1ce08e8093ed67d638d63879fd1ba3735817f7a80de3674d293f5984f25fb6e6", - "sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255" + "sha256:4d7013ef96fd197d1cdeb03e066c6c5a491ccb44758a5b2b91137319383e5a5a", + "sha256:7e1db6a5ba6b9a8be061e47e900456355b8714c0f238b0313f53afce1a55a79a" ], "index": "pypi", - "version": "==2.1.2" + "version": "==2.2.1" }, "wirerope": { "hashes": [ @@ -843,6 +859,14 @@ ], "version": "==0.4.5" }, + "wtforms": { + "hashes": [ + "sha256:6b351bbb12dd58af57ffef05bc78425d08d1914e0fd68ee14143b7ade023c5bc", + "sha256:837f2f0e0ca79481b92884962b914eba4e72b7a2daaf1f939c890ed0124b834b" + ], + "markers": "python_version >= '3.7'", + "version": "==3.0.1" + }, "zipp": { "hashes": [ "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2", @@ -933,18 +957,18 @@ }, "attrs": { "hashes": [ - "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", - "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" + "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6", + "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.4.0" + "markers": "python_version >= '3.5'", + "version": "==22.1.0" }, "babel": { "hashes": [ "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51", "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb" ], - "markers": "python_full_version >= '3.6.0'", + "markers": "python_version >= '3.6'", "version": "==2.10.3" }, "black": { @@ -1236,7 +1260,7 @@ "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" ], - "markers": "python_full_version >= '3.6.0'", + "markers": "python_version >= '3.6'", "version": "==1.0.0" }, "py": { @@ -1268,7 +1292,7 @@ "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb", "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519" ], - "markers": "python_full_version >= '3.6.0'", + "markers": "python_version >= '3.6'", "version": "==2.12.0" }, "pyparsing": { @@ -1326,11 +1350,11 @@ }, "setuptools": { "hashes": [ - "sha256:0d33c374d41c7863419fc8f6c10bfe25b7b498aa34164d135c622e52580c6b16", - "sha256:c04b44a57a6265fe34a4a444e965884716d34bae963119a76353434d6f18e450" + "sha256:273b6847ae61f7829c1affcdd9a32f67aa65233be508f4fbaab866c5faa4e408", + "sha256:d5340d16943a0f67057329db59b564e938bb3736c6e50ae16ea84d5e5d9ba6d0" ], "markers": "python_version >= '3.7'", - "version": "==63.2.0" + "version": "==63.3.0" }, "six": { "hashes": [ @@ -1392,7 +1416,7 @@ "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07", "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2" ], - "markers": "python_full_version >= '3.6.0'", + "markers": "python_version >= '3.6'", "version": "==2.0.0" }, "sphinxcontrib-jsmath": { @@ -1483,19 +1507,19 @@ }, "urllib3": { "hashes": [ - "sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec", - "sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6" + "sha256:c33ccba33c819596124764c23a97d25f32b28433ba0dedeb77d873a38722c9bc", + "sha256:ea6e8fb210b19d950fab93b60c9009226c63a28808bc8386e05301e25883ac0a" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'", - "version": "==1.26.10" + "version": "==1.26.11" }, "virtualenv": { "hashes": [ - "sha256:288171134a2ff3bfb1a2f54f119e77cd1b81c29fc1265a2356f3e8d14c7d58c4", - "sha256:b30aefac647e86af6d82bfc944c556f8f1a9c90427b2fb4e3bfbf338cb82becf" + "sha256:0ef5be6d07181946891f5abc8047fda8bc2f0b4b9bf222c64e6e8963baee76db", + "sha256:635b272a8e2f77cb051946f46c60a54ace3cb5e25568228bd6b57fc70eca9ff3" ], "index": "pypi", - "version": "==20.15.1" + "version": "==20.16.2" }, "vulture": { "hashes": [ diff --git a/monkey/monkey_island/cc/app.py b/monkey/monkey_island/cc/app.py index 37cae6cdb..a5723c86e 100644 --- a/monkey/monkey_island/cc/app.py +++ b/monkey/monkey_island/cc/app.py @@ -5,7 +5,9 @@ from datetime import timedelta from typing import Iterable, Type import flask_restful -from flask import Flask, Response, send_from_directory +from flask import Flask, Response, jsonify, send_from_directory +from flask_login import LoginManager, UserMixin, login_required, logout_user +from mongoengine import Document, StringField from werkzeug.exceptions import NotFound from common import DIContainer @@ -84,28 +86,44 @@ def serve_home(): def init_app_config(app, mongo_url): app.config["MONGO_URI"] = mongo_url - # See https://flask-jwt-extended.readthedocs.io/en/stable/options - app.config["JWT_ACCESS_TOKEN_EXPIRES"] = AUTH_EXPIRATION_TIME - # Invalidate the signature of JWTs if the server process restarts. This avoids the edge case - # of getting a JWT, - # deciding to reset credentials and then still logging in with the old JWT. - app.config["JWT_SECRET_KEY"] = str(uuid.uuid4()) + app.secret_key = str(uuid.uuid4()) # By default, Flask sorts keys of JSON objects alphabetically. # See https://flask.palletsprojects.com/en/1.1.x/config/#JSON_SORT_KEYS. app.config["JSON_SORT_KEYS"] = False + app.config.update( + SESSION_COOKIE_HTTPONLY=True, + REMEMBER_COOKIE_HTTPONLY=True, + SESSION_COOKIE_SAMESITE="Strict", + ) app.url_map.strict_slashes = False app.json_encoder = CustomJSONEncoder +# TODO move +class User(Document, UserMixin): + username = StringField() + password_hash = StringField() + + @staticmethod + def get_by_id(id: str): + return User.objects.get(id=id) + + def init_app_services(app): - init_jwt(app) + login_manager = LoginManager() + login_manager.init_app(app) + login_manager.session_protection = "strong" mongo.init_app(app) with app.app_context(): database.init() + @login_manager.user_loader + def load_user(user_id): + return User.get_by_id(user_id) + def init_app_url_rules(app): app.add_url_rule("/", "serve_home", serve_home) @@ -222,4 +240,10 @@ def init_app(mongo_url: str, container: DIContainer): flask_resource_manager = FlaskDIWrapper(api, container) init_api_resources(flask_resource_manager) + @app.route("/api/logout") + @login_required + def logout(): + logout_user() + return jsonify({"logout": True}) + return app diff --git a/monkey/monkey_island/cc/models/user.py b/monkey/monkey_island/cc/models/user.py new file mode 100644 index 000000000..f2ba837f1 --- /dev/null +++ b/monkey/monkey_island/cc/models/user.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from flask_login import UserMixin +from mongoengine import Document, StringField + + +class User(Document, UserMixin): + username = StringField() + password_hash = StringField() + + @staticmethod + def get_by_id(id: str): + return User.objects.get(id) diff --git a/monkey/monkey_island/cc/resources/auth/auth.py b/monkey/monkey_island/cc/resources/auth/auth.py index 34632bf7e..697f6070f 100644 --- a/monkey/monkey_island/cc/resources/auth/auth.py +++ b/monkey/monkey_island/cc/resources/auth/auth.py @@ -2,9 +2,11 @@ import logging from http import HTTPStatus import flask_jwt_extended -from flask import make_response, request +from flask import jsonify, make_response, request +from flask_login import current_user, login_required, login_user from common.utils.exceptions import IncorrectCredentialsError +from monkey_island.cc.models.user import User from monkey_island.cc.resources.AbstractResource import AbstractResource from monkey_island.cc.resources.auth.credential_utils import get_username_password_from_request from monkey_island.cc.resources.request_authentication import create_access_token @@ -22,8 +24,6 @@ def init_jwt(app): class Authenticate(AbstractResource): """ - Resource for user authentication. The user provides the username and password and we \ - give them a JWT. \ See `AuthService.js` file for the frontend counterpart for this code. \ """ @@ -33,6 +33,9 @@ class Authenticate(AbstractResource): def __init__(self, authentication_service: AuthenticationService): self._authentication_service = authentication_service + def get(self): + return jsonify({"authenticated": current_user.is_authenticated}) + def post(self): """ Example request: \ @@ -45,10 +48,10 @@ class Authenticate(AbstractResource): username, password = get_username_password_from_request(request) try: - self._authentication_service.authenticate(username, password) - access_token = create_access_token(username) + user = self._authentication_service.authenticate(username, password) except IncorrectCredentialsError: return make_response({"error": "Invalid credentials"}, HTTPStatus.UNAUTHORIZED) # API Spec: Why are we sending "error" here? - return make_response({"access_token": access_token, "error": ""}, HTTPStatus.OK) + login_user(user) + return jsonify({"login": True}) diff --git a/monkey/monkey_island/cc/resources/island_mode.py b/monkey/monkey_island/cc/resources/island_mode.py index 84f30c4ce..854a1cb44 100644 --- a/monkey/monkey_island/cc/resources/island_mode.py +++ b/monkey/monkey_island/cc/resources/island_mode.py @@ -2,10 +2,10 @@ import json import logging from flask import make_response, request +from flask_login import login_required from monkey_island.cc.models import IslandMode as IslandModeEnum from monkey_island.cc.resources.AbstractResource import AbstractResource -from monkey_island.cc.resources.request_authentication import jwt_required from monkey_island.cc.services import IslandModeService logger = logging.getLogger(__name__) @@ -18,7 +18,6 @@ class IslandMode(AbstractResource): self._island_mode_service = island_mode_service # API Spec: Instead of POST, this should be PUT - @jwt_required def post(self): try: body = json.loads(request.data) @@ -35,7 +34,7 @@ class IslandMode(AbstractResource): except ValueError: return make_response({}, 422) - @jwt_required + @login_required def get(self): island_mode = self._island_mode_service.get_mode() return make_response({"mode": island_mode.value}, 200) diff --git a/monkey/monkey_island/cc/resources/root.py b/monkey/monkey_island/cc/resources/root.py index ef53ff788..341b79e6f 100644 --- a/monkey/monkey_island/cc/resources/root.py +++ b/monkey/monkey_island/cc/resources/root.py @@ -26,7 +26,6 @@ class Root(AbstractResource): else: return make_response(400, {"error": "unknown action"}) - @jwt_required def get_server_info(self): return jsonify( ip_addresses=local_ip_addresses(), diff --git a/monkey/monkey_island/cc/services/authentication_service.py b/monkey/monkey_island/cc/services/authentication_service.py index 7b32e4f1c..4309ebc8d 100644 --- a/monkey/monkey_island/cc/services/authentication_service.py +++ b/monkey/monkey_island/cc/services/authentication_service.py @@ -8,6 +8,7 @@ from common.utils.exceptions import ( UnknownUserError, ) from monkey_island.cc.models import UserCredentials +from monkey_island.cc.models.user import User from monkey_island.cc.repository import IUserRepository from monkey_island.cc.server_utils.encryption import ( ILockableEncryptor, @@ -29,20 +30,21 @@ class AuthenticationService: self._repository_encryptor = repository_encryptor def needs_registration(self) -> bool: - return not self._user_repository.has_registered_users() + return not User.objects.first() def register_new_user(self, username: str, password: str): if not username or not password: raise InvalidRegistrationCredentialsError("Username or password can not be empty.") credentials = UserCredentials(username, _hash_password(password)) - self._user_repository.add_user(credentials) + # self._user_repository.add_user(credentials) + User(username=username, password_hash=_hash_password(password)).save() self._reset_repository_encryptor(username, password) reset_database() def authenticate(self, username: str, password: str): try: - registered_user = self._user_repository.get_user_credentials(username) + registered_user = User.objects.first() except UnknownUserError: raise IncorrectCredentialsError() @@ -50,6 +52,7 @@ class AuthenticationService: raise IncorrectCredentialsError() self._unlock_repository_encryptor(username, password) + return registered_user def _unlock_repository_encryptor(self, username: str, password: str): secret = _get_secret_from_credentials(username, password) diff --git a/monkey/monkey_island/cc/services/database.py b/monkey/monkey_island/cc/services/database.py index a73e182f5..4d146a7f1 100644 --- a/monkey/monkey_island/cc/services/database.py +++ b/monkey/monkey_island/cc/services/database.py @@ -36,6 +36,7 @@ class Database(object): return ( not collection.startswith("system.") and not collection == AttackMitigations.COLLECTION_NAME + and not collection == "user" ) @staticmethod diff --git a/monkey/monkey_island/cc/ui/src/components/Main.tsx b/monkey/monkey_island/cc/ui/src/components/Main.tsx index 4a4370294..08efcd197 100644 --- a/monkey/monkey_island/cc/ui/src/components/Main.tsx +++ b/monkey/monkey_island/cc/ui/src/components/Main.tsx @@ -11,7 +11,7 @@ import LicensePage from './pages/LicensePage'; import AuthComponent from './AuthComponent'; import LoginPageComponent from './pages/LoginPage'; import RegisterPageComponent from './pages/RegisterPage'; -import LandingPage from "./pages/LandingPage"; +import LandingPage from './pages/LandingPage'; import Notifier from 'react-desktop-notification'; import NotFoundPage from './pages/NotFoundPage'; import GettingStartedPage from './pages/GettingStartedPage'; @@ -21,13 +21,13 @@ import 'normalize.css/normalize.css'; import 'styles/App.css'; import 'react-table/react-table.css'; import LoadingScreen from './ui-components/LoadingScreen'; -import SidebarLayoutComponent from "./layouts/SidebarLayoutComponent"; -import {CompletedSteps} from "./side-menu/CompletedSteps"; +import SidebarLayoutComponent from './layouts/SidebarLayoutComponent'; +import {CompletedSteps} from './side-menu/CompletedSteps'; import Timeout = NodeJS.Timeout; -import IslandHttpClient from "./IslandHttpClient"; -import _ from "lodash"; -import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; -import {faFileCode, faLightbulb} from "@fortawesome/free-solid-svg-icons"; +import IslandHttpClient from './IslandHttpClient'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faFileCode, faLightbulb} from '@fortawesome/free-solid-svg-icons'; +import LogoutPageComponent from './pages/LogoutPage'; let notificationIcon = require('../images/notification-logo-512x512.png'); @@ -41,6 +41,7 @@ export const Routes = { SecurityReport: '/report/security', RansomwareReport: '/report/ransomware', LoginPage: '/login', + Logout: '/logout', RegisterPage: '/register', ConfigurePage: '/configure', RunMonkeyPage: '/run-monkey', @@ -49,7 +50,7 @@ export const Routes = { LicensePage: '/license' } -export function isReportRoute(route){ +export function isReportRoute(route) { return route.startsWith(Routes.Report); } @@ -73,43 +74,23 @@ class AppComponent extends AuthComponent { return } - let res = this.auth.loggedIn(); + this.auth.loggedIn().then((res) => { + console.log("called") + if (this.state.isLoggedIn !== res) { + this.setState({ + isLoggedIn: res + }); + } - if (this.state.isLoggedIn !== res) { - this.setState({ - isLoggedIn: res - }); - } - - if (!res) { - this.auth.needsRegistration() - .then(result => { - this.setState({ - needsRegistration: result - }); - }) - } - - if (res) { - this.setMode() - .then(() => { - if (this.state.islandMode === "unset") { - return - } - this.authFetch('/api') - .then(res => res.json()) - .then(res => { - let completedSteps = CompletedSteps.buildFromResponse(res.completed_steps); - // This check is used to prevent unnecessary re-rendering - if (_.isEqual(this.state.completedSteps, completedSteps)) { - return; - } - this.setState({completedSteps: completedSteps}); - this.showInfectionDoneNotification(); - }); - } - ) - } + if (!res) { + this.auth.needsRegistration() + .then(result => { + this.setState({ + needsRegistration: result + }); + }) + } + }); }; setMode = () => { @@ -121,6 +102,7 @@ class AppComponent extends AuthComponent { renderRoute = (route_path, page_component, is_exact_path = false) => { let render_func = () => { + console.log(this.state.isLoggedIn); switch (this.state.isLoggedIn) { case true: if (this.needsRedirectionToLandingPage(route_path)) { @@ -151,12 +133,12 @@ class AppComponent extends AuthComponent { }; needsRedirectionToLandingPage = (route_path) => { - return (this.state.islandMode === "unset" && route_path !== Routes.LandingPage) + return (this.state.islandMode === 'unset' && route_path !== Routes.LandingPage) } needsRedirectionToGettingStarted = (route_path) => { return route_path === Routes.LandingPage && - this.state.islandMode !== "unset" && this.state.islandMode !== undefined + this.state.islandMode !== 'unset' && this.state.islandMode !== undefined } redirectTo = (userPath, targetPath) => { @@ -176,43 +158,49 @@ class AppComponent extends AuthComponent { } getDefaultReport() { - if(this.state.islandMode === 'ransomware'){ + if (this.state.islandMode === 'ransomware') { return Routes.RansomwareReport; } else { return Routes.SecurityReport; } } - getIslandModeTitle(){ - if(this.state.islandMode === 'ransomware'){ - return this.formIslandModeTitle("Ransomware", faFileCode); + getIslandModeTitle() { + if (this.state.islandMode === 'ransomware') { + return this.formIslandModeTitle('Ransomware', faFileCode); } else { - return this.formIslandModeTitle("Custom", faLightbulb); + return this.formIslandModeTitle('Custom', faLightbulb); } } - formIslandModeTitle(title, icon){ + formIslandModeTitle(title, icon) { return (<>
- {title} + {title}
) } render() { - let defaultSideNavProps = {completedSteps: this.state.completedSteps, - onStatusChange: this.updateStatus, - islandMode: this.state.islandMode, - defaultReport: this.getDefaultReport(), - sideNavHeader: this.getIslandModeTitle()} + let defaultSideNavProps = { + completedSteps: this.state.completedSteps, + onStatusChange: this.updateStatus, + islandMode: this.state.islandMode, + defaultReport: this.getDefaultReport(), + sideNavHeader: this.getIslandModeTitle() + } return ( - ()}/> - ()}/> + ()}/> + ()}/> + ()}/> {this.renderRoute(Routes.LandingPage, { event.preventDefault() this.auth.login(this.username, this.password).then(res => { - if (res['result']) { + console.log("HERE") + console.log(res) + if (res) { this.redirectToHome(); } else { this.setState({failed: true}); @@ -42,17 +44,16 @@ class LoginPageComponent extends React.Component { failed: false }; - this.auth.needsRegistration() - .then(result => { - if (result) { - this.redirectToRegistration() - } - }) - - if (this.auth.loggedIn()) { - this.redirectToHome(); - } + //this.auth.needsRegistration() + // .then(result => { + // if (result) { + // this.redirectToRegistration() + // } + // }) + this.auth.loggedIn().then((res) => { + if(res){this.redirectToHome();} + }) } render() { diff --git a/monkey/monkey_island/cc/ui/src/components/pages/LogoutPage.js b/monkey/monkey_island/cc/ui/src/components/pages/LogoutPage.js new file mode 100644 index 000000000..26b572bd9 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/LogoutPage.js @@ -0,0 +1,26 @@ +import React from 'react'; +import {Button, Col, Container, Form, Row} from 'react-bootstrap'; + +import AuthService from '../../services/AuthService'; +import monkeyGeneral from '../../images/militant-monkey.svg'; +import ParticleBackground from '../ui-components/ParticleBackground'; +import {Redirect} from 'react-router-dom'; +import {Routes} from '../Main'; + +class LogoutPageComponent extends React.Component { + + redirectToLogin = () => { + window.location.href = '/login'; + }; + + constructor(props) { + super(props); + fetch('/api/logout').then(this.redirectToLogin); + } + + render() { + return (

Logging out

); + } +} + +export default LogoutPageComponent; diff --git a/monkey/monkey_island/cc/ui/src/services/AuthService.js b/monkey/monkey_island/cc/ui/src/services/AuthService.js index 7838a8563..d847a2234 100644 --- a/monkey/monkey_island/cc/ui/src/services/AuthService.js +++ b/monkey/monkey_island/cc/ui/src/services/AuthService.js @@ -28,13 +28,7 @@ export default class AuthService { }) }).then(response => response.json()) .then(res => { - if (Object.prototype.hasOwnProperty.call(res, 'access_token')) { - this._setToken(res['access_token']); - return {result: true}; - } else { - this._removeToken(); - return {result: false}; - } + return res["login"] }) }; @@ -61,31 +55,8 @@ export default class AuthService { }; _authFetch = (url, options = {}) => { - const headers = { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }; - - if (this.loggedIn()) { - headers['Authorization'] = 'Bearer ' + this._getToken(); - } - - if (Object.prototype.hasOwnProperty.call(options, 'headers')) { - for (let header in headers) { - options['headers'][header] = headers[header]; - } - } else { - options['headers'] = headers; - } - return fetch(url, options) .then(res => { - if (res.status === 401) { - res.clone().json().then(res_json => { - console.log('Got 401 from server while trying to authFetch: ' + JSON.stringify(res_json)); - }); - this._removeToken(); - } return res; }) }; @@ -100,8 +71,12 @@ export default class AuthService { }; loggedIn() { - const token = this._getToken(); - return ((token !== null) && !this._isTokenExpired(token)); + return fetch(this.AUTHENTICATION_API_ENDPOINT) + .then(response => response.json()) + .then(res => { + console.log(res); + return res['authenticated']; + }) } logout = () => {