Finished "no password" environment option

This commit is contained in:
VakarisZ 2020-06-16 13:45:10 +03:00
parent a5b1ac22f9
commit ce5e415788
19 changed files with 129 additions and 45 deletions

View File

@ -7,9 +7,10 @@ from werkzeug.exceptions import NotFound
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
import monkey_island.cc.environment.environment_singleton as env_singleton
from monkey_island.cc.resources.client_run import ClientRun
from monkey_island.cc.resources.edge import Edge
from monkey_island.cc.resources.environment import Environment
from monkey_island.cc.resources.local_run import LocalRun
from monkey_island.cc.resources.log import Log
from monkey_island.cc.resources.island_logs import IslandLog
@ -70,7 +71,7 @@ def init_app_config(app, mongo_url):
app.config['MONGO_URI'] = mongo_url
app.config['SECRET_KEY'] = str(uuid.getnode())
app.config['JWT_AUTH_URL_RULE'] = '/api/auth'
app.config['JWT_EXPIRATION_DELTA'] = env.get_auth_expiration_time()
app.config['JWT_EXPIRATION_DELTA'] = env_singleton.env.get_auth_expiration_time()
def init_app_services(app):
@ -93,6 +94,7 @@ def init_app_url_rules(app):
def init_api_resources(api):
api.add_resource(Root, '/api')
api.add_resource(Registration, '/api/registration')
api.add_resource(Environment, '/api/environment')
api.add_resource(Monkey, '/api/monkey', '/api/monkey/', '/api/monkey/<string:guid>')
api.add_resource(Bootloader, '/api/bootloader/<string:os>')
api.add_resource(LocalRun, '/api/local-monkey', '/api/local-monkey/')

View File

@ -23,8 +23,8 @@ class Environment(object, metaclass=ABCMeta):
_testing = False
def __init__(self):
self._config = EnvironmentConfig("", "", UserCreds())
def __init__(self, config: EnvironmentConfig):
self._config = config
self._testing = False # Assume env is not for unit testing.
@property
@ -72,8 +72,11 @@ class Environment(object, metaclass=ABCMeta):
def testing(self, value):
self._testing = value
def set_config(self, config: EnvironmentConfig):
self._config = config
def save_config(self):
self._config.save_to_file()
def get_config(self) -> EnvironmentConfig:
return self._config
def get_island_port(self):
return self._ISLAND_PORT
@ -93,12 +96,15 @@ class Environment(object, metaclass=ABCMeta):
hash_obj.update(secret.encode('utf-8'))
return hash_obj.hexdigest()
def get_deployment(self):
def get_deployment(self) -> str:
deployment = 'unknown'
if self._config and self._config.deployment:
deployment = self._config.deployment
return deployment
def set_deployment(self, deployment: str):
self._config.deployment = deployment
@property
def mongo_db_name(self):
return self._MONGO_DB_NAME

View File

@ -9,8 +9,8 @@ class AwsEnvironment(Environment):
_credentials_required = True
def __init__(self):
super(AwsEnvironment, self).__init__()
def __init__(self, config):
super(AwsEnvironment, self).__init__(config)
# Not suppressing error here on purpose. This is critical if we're on AWS env.
self.aws_info = AwsInstance()
self._instance_id = self._get_instance_id()

View File

@ -1,8 +1,8 @@
import json
import logging
env = None
import monkey_island.cc.resources.auth.user_store as user_store
from monkey_island.cc.environment import standard, EnvironmentConfig
from monkey_island.cc.environment import testing
from monkey_island.cc.environment import aws
@ -24,11 +24,28 @@ ENV_DICT = {
TESTING: testing.TestingEnvironment
}
def set_env(env_type: str, env_config: EnvironmentConfig):
global env
if env_type in ENV_DICT:
env = ENV_DICT[env_type](env_config)
def set_to_standard():
global env
if env:
env_config = env.get_config()
env_config.server_config = 'standard'
set_env('standard', env_config)
env.save_config()
user_store.UserStore.set_users(env.get_auth_users())
try:
config = EnvironmentConfig.get_from_file()
__env_type = config.server_config
env = ENV_DICT[__env_type]()
env.set_config(config)
set_env(__env_type, config)
# noinspection PyUnresolvedReferences
logger.info('Monkey\'s env is: {0}'.format(env.__class__.__name__))
except Exception:
logger.error('Failed initializing environment', exc_info=True)

View File

@ -1,3 +1,4 @@
from monkey_island.cc.environment import EnvironmentConfig, UserCreds
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
@ -7,7 +8,7 @@ import hashlib
class TestAwsEnvironment(IslandTestCase):
def test_get_auth_users(self):
env = AwsEnvironment()
env = AwsEnvironment(EnvironmentConfig("", "", UserCreds()))
# This is "injecting" the instance id to the env. This is the UTs aren't always executed on the same AWS machine
# (might not be an AWS machine at all).
# Perhaps it would have been more elegant to create a Mock, but not worth it for

View File

@ -1,4 +1,4 @@
from monkey_island.cc.environment import Environment
from monkey_island.cc.environment import Environment, EnvironmentConfig
class TestingEnvironment(Environment):
@ -9,8 +9,8 @@ class TestingEnvironment(Environment):
_credentials_required = True
def __init__(self):
super(TestingEnvironment, self).__init__()
def __init__(self, config: EnvironmentConfig):
super(TestingEnvironment, self).__init__(config)
self.testing = True
def get_auth_users(self):

View File

@ -23,7 +23,7 @@ logger = logging.getLogger(__name__)
from monkey_island.cc.app import init_app
from monkey_island.cc.services.reporting.exporter_init import populate_exporter_list
from monkey_island.cc.network_utils import local_ip_addresses
from monkey_island.cc.environment.environment_singleton import env
import monkey_island.cc.environment.environment_singleton as env_singleton
from monkey_island.cc.database import is_db_server_up, get_db_version
from monkey_island.cc.resources.monkey_download import MonkeyDownload
from common.version import get_version
@ -33,7 +33,7 @@ from monkey_island.cc.setup import setup
def main(should_setup_only=False):
logger.info("Starting bootloader server")
mongo_url = os.environ.get('MONGO_URL', env.get_mongo_url())
mongo_url = os.environ.get('MONGO_URL', env_singleton.env.get_mongo_url())
bootloader_server_thread = Thread(target=BootloaderHttpServer(mongo_url).serve_forever, daemon=True)
bootloader_server_thread.start()
@ -46,7 +46,7 @@ def start_island_server(should_setup_only):
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
mongo_url = os.environ.get('MONGO_URL', env.get_mongo_url())
mongo_url = os.environ.get('MONGO_URL', env_singleton.env.get_mongo_url())
wait_for_mongo_db_server(mongo_url)
assert_mongo_db_version(mongo_url)
@ -62,13 +62,13 @@ def start_island_server(should_setup_only):
logger.warning("Setup only flag passed. Exiting.")
return
if env.is_debug():
if env_singleton.env.is_debug():
app.run(host='0.0.0.0', debug=True, ssl_context=(crt_path, key_path))
else:
http_server = HTTPServer(WSGIContainer(app),
ssl_options={'certfile': os.environ.get('SERVER_CRT', crt_path),
'keyfile': os.environ.get('SERVER_KEY', key_path)})
http_server.listen(env.get_island_port())
http_server.listen(env_singleton.env.get_island_port())
log_init_info()
IOLoop.instance().start()
@ -77,7 +77,7 @@ def log_init_info():
logger.info('Monkey Island Server is running!')
logger.info(f"version: {get_version()}")
logger.info('Listening on the following URLs: {}'.format(
", ".join(["https://{}:{}".format(x, env.get_island_port()) for x in local_ip_addresses()])
", ".join(["https://{}:{}".format(x, env_singleton.env.get_island_port()) for x in local_ip_addresses()])
)
)
MonkeyDownload.log_executable_hashes()

View File

@ -1,15 +1,15 @@
from mongoengine import connect
from monkey_island.cc.environment.environment_singleton import env
import monkey_island.cc.environment.environment_singleton as env_singleton
# This section sets up the DB connection according to the environment.
# If testing, use mongomock which only emulates mongo. for more information, see
# http://docs.mongoengine.org/guide/mongomock.html .
# Otherwise, use an actual mongod instance with connection parameters supplied by env.
if env.testing: # See monkey_island.cc.environment.testing
if env_singleton.env.testing: # See monkey_island.cc.environment.testing
connect('mongoenginetest', host='mongomock://localhost')
else:
connect(db=env.mongo_db_name, host=env.mongo_db_host, port=env.mongo_db_port)
connect(db=env_singleton.env.mongo_db_name, host=env_singleton.env.mongo_db_host, port=env_singleton.env.mongo_db_port)
# Order of importing matters here, for registering the embedded and referenced documents before using them.
from .config import Config # noqa: F401

View File

@ -4,23 +4,23 @@ from flask import current_app, abort
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
import monkey_island.cc.environment.environment_singleton as env_singleton
import monkey_island.cc.resources.auth.user_store as user_store
__author__ = 'itay.mizeretz'
def init_jwt(app):
UserStore.set_users(env.get_auth_users())
user_store.UserStore.set_users(env_singleton.env.get_auth_users())
def authenticate(username, secret):
user = UserStore.username_table.get(username, None)
user = user_store.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 UserStore.userid_table.get(user_id, None)
return user_store.UserStore.userid_table.get(user_id, None)
JWT(app, authenticate, identity)

View File

@ -0,0 +1,16 @@
import json
from flask import request
import flask_restful
import monkey_island.cc.environment.environment_singleton as env_singleton
class Environment(flask_restful.Resource):
def patch(self):
env_data = json.loads(request.data)
if env_data['server_config'] == "standard":
if env_singleton.env.needs_registration():
env_singleton.set_to_standard()
return {}

View File

@ -6,7 +6,7 @@ import sys
from flask import request, jsonify, make_response
import flask_restful
from monkey_island.cc.environment.environment_singleton import env
import monkey_island.cc.environment.environment_singleton as env_singleton
from monkey_island.cc.models import Monkey
from monkey_island.cc.resources.monkey_download import get_monkey_executable
from monkey_island.cc.services.node import NodeService
@ -43,7 +43,7 @@ def run_local_monkey():
# run the monkey
try:
args = ['"%s" m0nk3y -s %s:%s' % (target_path, local_ip_addresses()[0], env.get_island_port())]
args = ['"%s" m0nk3y -s %s:%s' % (target_path, local_ip_addresses()[0], env_singleton.env.get_island_port())]
if sys.platform == "win32":
args = "".join(args)
pid = subprocess.Popen(args, shell=True).pid

View File

@ -2,18 +2,18 @@ import flask_restful
from flask import request, make_response
from common.utils.exceptions import InvalidRegistrationCredentials
from monkey_island.cc.environment.environment_singleton import env
import monkey_island.cc.environment.environment_singleton as env_singleton
from monkey_island.cc.environment.user_creds import UserCreds
class Registration(flask_restful.Resource):
def get(self):
return {'needs_registration': env.needs_registration()}
return {'needs_registration': env_singleton.env.needs_registration()}
def post(self):
credentials = UserCreds.get_from_json(request.data)
try:
env.try_add_user(credentials)
env_singleton.env.try_add_user(credentials)
return make_response({"error": ""}, 200)
except InvalidRegistrationCredentials as e:
return make_response({"error": str(e)}, 400)

View File

@ -0,0 +1,4 @@
{
"server_config": "standard",
"deployment": "develop"
}

View File

@ -6,7 +6,7 @@ from jsonschema import Draft4Validator, validators
import monkey_island.cc.services.post_breach_files
from monkey_island.cc.database import mongo
from monkey_island.cc.environment.environment_singleton import env
import monkey_island.cc.environment.environment_singleton as env_singleton
from monkey_island.cc.network_utils import local_ip_addresses
from .config_schema import SCHEMA
from monkey_island.cc.encryptor import encryptor
@ -216,8 +216,8 @@ class ConfigService:
@staticmethod
def set_server_ips_in_config(config):
ips = local_ip_addresses()
config["cnc"]["servers"]["command_servers"] = ["%s:%d" % (ip, env.get_island_port()) for ip in ips]
config["cnc"]["servers"]["current_server"] = "%s:%d" % (ips[0], env.get_island_port())
config["cnc"]["servers"]["command_servers"] = ["%s:%d" % (ip, env_singleton.env.get_island_port()) for ip in ips]
config["cnc"]["servers"]["current_server"] = "%s:%d" % (ips[0], env_singleton.env.get_island_port())
@staticmethod
def save_initial_config_if_needed():

View File

@ -3,7 +3,7 @@ import logging
from monkey_island.cc.services.reporting.report_exporter_manager import ReportExporterManager
from monkey_island.cc.services.reporting.aws_exporter import AWSExporter
from monkey_island.cc.services.remote_run_aws import RemoteRunAwsService
from monkey_island.cc.environment.environment_singleton import env
import monkey_island.cc.environment.environment_singleton as env_singleton
logger = logging.getLogger(__name__)
@ -21,7 +21,7 @@ def try_add_aws_exporter_to_manager(manager):
# noinspection PyBroadException
try:
RemoteRunAwsService.init()
if RemoteRunAwsService.is_running_on_aws() and ('aws' == env.get_deployment()):
if RemoteRunAwsService.is_running_on_aws() and ('aws' == env_singleton.env.get_deployment()):
manager.add_exporter_to_list(AWSExporter)
except Exception:
logger.error("Failed adding aws exporter to manager. Exception info:", exc_info=True)

View File

@ -3,7 +3,7 @@ import logging
import requests
from common.version import get_version
from monkey_island.cc.environment.environment_singleton import env
import monkey_island.cc.environment.environment_singleton as env_singleton
__author__ = "itay.mizeretz"
@ -40,7 +40,7 @@ class VersionUpdateService:
Checks if newer monkey version is available
:return: False if not, version in string format ('1.6.2') otherwise
"""
url = VersionUpdateService.VERSION_SERVER_CHECK_NEW_URL % (env.get_deployment(), get_version())
url = VersionUpdateService.VERSION_SERVER_CHECK_NEW_URL % (env_singleton.env.get_deployment(), get_version())
reply = requests.get(url, timeout=15)
@ -54,4 +54,4 @@ class VersionUpdateService:
@staticmethod
def get_download_link():
return VersionUpdateService.VERSION_SERVER_DOWNLOAD_URL % (env.get_deployment(), get_version())
return VersionUpdateService.VERSION_SERVER_DOWNLOAD_URL % (env_singleton.env.get_deployment(), get_version())

View File

@ -1,12 +1,12 @@
import unittest
from monkey_island.cc.environment.environment_singleton import env
import monkey_island.cc.environment.environment_singleton as env_singleton
from monkey_island.cc.models import Monkey
from monkey_island.cc.models.zero_trust.finding import Finding
class IslandTestCase(unittest.TestCase):
def fail_if_not_testing_env(self):
self.assertFalse(not env.testing, "Change server_config.json to testing environment.")
self.assertFalse(not env_singleton.env.testing, "Change server_config.json to testing environment.")
@staticmethod
def clean_monkey_db():

View File

@ -9,6 +9,8 @@ import monkeyDetective from '../../images/detective-monkey.svg';
class RegisterPageComponent extends React.Component {
NO_AUTH_API_ENDPOINT = '/api/environment';
register = () => {
this.auth.register(this.username, this.password).then(res => {
this.setState({failed: false, error: ''});
@ -23,6 +25,29 @@ class RegisterPageComponent extends React.Component {
});
};
setNoAuth = () => {
let options = {}
options['headers'] = {
'Accept': 'application/json',
'Content-Type': 'application/json'
};
options['method'] = 'PATCH'
options['body'] = JSON.stringify({'server_config': 'standard'})
return fetch(this.NO_AUTH_API_ENDPOINT, options)
.then(res => {
if (res.status === 200) {
this.auth.attemptNoAuthLogin().then(() => {
this.redirectToHome();
});
}
this.setState({
failed: true,
error: res['error']
});
})
}
updateUsername = (evt) => {
this.username = evt.target.value;
};
@ -72,6 +97,9 @@ class RegisterPageComponent extends React.Component {
}}>
Lets Go!
</Button>
<a href='#' onClick={this.setNoAuth} className={'no-auth-link'}>
I want anyone to access the island
</a>
{
this.state.failed ?
<div className='alert alert-danger' role='alert'>{this.state.error}</div>

View File

@ -60,3 +60,13 @@
.registration-block h3 {
margin-bottom: 20px;
}
.no-auth-link {
float: right;
color: #6a5b00;
}
.no-auth-link:hover {
float: right;
color: #796900;
}