Beispiel #1
0
    def get_current_user(self):
        """Set current user, authenticated via HTTP basic auth"""

        auth_header = self.request.headers.get('Authorization')
        if auth_header is None or not auth_header.startswith('Basic '):
            return None
        auth_decoded = base64.decodestring(auth_header[6:])
        if not auth_decoded.count(':'):
            return None
        login, password = auth_decoded.split(':', 2)
        if not login or not password: return None

        try:
            encrypted_password = self.mongo.user.find_one({'_id': login},
                    {'password': 1})['password']
        except:
            return None
        if encrypted_password and Password.verify(password, encrypted_password):
            return login
        else:
            return None
Beispiel #2
0
    def get_current_user(self):
        """Set current user, authenticated via HTTP basic auth"""

        auth_header = self.request.headers.get('Authorization')
        if auth_header is None or not auth_header.startswith('Basic '):
            return None
        auth_decoded = base64.decodestring(auth_header[6:])
        if not auth_decoded.count(':'):
            return None
        login, password = auth_decoded.split(':', 2)
        if not login or not password: return None

        try:
            encrypted_password = self.mongo.user.find_one({'_id': login},
                    {'password': 1})['password']
        except:
            return None
        if encrypted_password and Password.verify(password, encrypted_password):
            return login
        else:
            return None
Beispiel #3
0
    def do_POST(self):

        # Get the parameters of the POST request
        params = query.Parameters(self)

        print ""
        print Storyboard.SEPARATOR2
        if Storyboard.ENABLE_PASSWORD:
            print(
                "* INFO: trngsrv: Request POST parameters: [not shown because password use is enabled]"
            )
        else:
            print(
                "* INFO: trngsrv: Request POST parameters: {}".format(params))

        # Get the values of the parameters for given keys
        user_id = params.get(query.Parameters.USER)
        password = params.get(query.Parameters.PASSWORD)
        action = params.get(query.Parameters.ACTION)
        language = params.get(query.Parameters.LANG)
        instance_count = params.get(query.Parameters.COUNT)
        ttype = params.get(query.Parameters.TYPE)
        scenario = params.get(query.Parameters.SCENARIO)
        level = params.get(query.Parameters.LEVEL)
        range_id = params.get(query.Parameters.RANGE_ID)

        if DEBUG:
            print Storyboard.SEPARATOR1
            print "POST PARAMETERS:"
            print Storyboard.SEPARATOR1
            print "USER: %s" % (user_id)
            if password:
                print "PASSWORD: ******"
            print "ACTION: %s" % (action)
            print "LANGUAGE: %s" % (language)
            print "COUNT: %s" % (instance_count)
            print "TYPE: %s" % (ttype)
            print "SCENARIO: %s" % (scenario)
            print "LEVEL: %s" % (level)
            print "RANGE_ID: %s" % (range_id)
            print Storyboard.SEPARATOR1

        ## Verify user information

        # Get user information from YAML file
        # Note: Only reading data that is (potentially) modified externally =>
        #       no need for synchronization
        user_info = userinfo.UserInfo()
        if not user_info.parse_YAML_file(DATABASE_DIR + USERS_FILE):
            self.respond_error(Storyboard.USER_SETTINGS_LOADING_ERROR)
            return
        if DEBUG:
            user_info.pretty_print()

        # Check that user id is valid
        if not user_id:
            self.respond_error(Storyboard.USER_ID_MISSING_ERROR)
            return
        user_obj = user_info.get_user(user_id)
        if not user_obj:
            self.respond_error(Storyboard.USER_ID_INVALID_ERROR)
            return

        # Check password (if enabled)
        if Storyboard.ENABLE_PASSWORD:
            # Check whether password exists in database for current user
            if not user_obj.password:
                self.respond_error(
                    Storyboard.USER_PASSWORD_NOT_IN_DATABASE_ERROR)
                return
            # If a password was provided, verify that it matches the encrypted one from the database
            if password:
                if not Password.verify(password, user_obj.password):
                    self.respond_error(
                        Storyboard.USER_ID_PASSWORD_INVALID_ERROR)
                    return
            else:
                self.respond_error(Storyboard.USER_PASSWORD_MISSING_ERROR)
                return

        ## Verify action information

        # Check that action is valid
        if not action:
            self.respond_error(Storyboard.ACTION_MISSING_ERROR)
            return
        if action not in self.VALID_ACTIONS:
            self.respond_error(Storyboard.ACTION_INVALID_ERROR)
            return

        # Create training database content information object
        training_info = trnginfo.TrainingInfo()

        # Check that language is valid
        if not language:
            self.respond_error(Storyboard.LANGUAGE_MISSING_ERROR)
            return
        if language not in self.VALID_LANGUAGES:
            self.respond_error(Storyboard.LANGUAGE_INVALID_ERROR)
            return

        # Select the scenario information file based on the
        # requested language
        if language == query.Parameters.JA:
            training_settings_file = DATABASE_DIR + SCENARIOS_FILE_JA
        else:
            training_settings_file = DATABASE_DIR + SCENARIOS_FILE_EN

        if DEBUG:
            print "* DEBUG: trngsrv: Read training settings from '%s'..." % (
                training_settings_file)

        # Note: Only reading data that is (potentially) modified externally =>
        #       no need for synchronization
        result = training_info.parse_YAML_file(training_settings_file)

        if not result:
            self.respond_error(Storyboard.TRAINING_SETTINGS_LOADING_ERROR)
            return

        if DEBUG:
            training_info.pretty_print()

        # If we reached this point, it means processing was successful
        # => act according to each action

        ####################################################################
        # Fetch content action
        # Note: Only reading data that is (potentially) modified externally =>
        #       no need for synchronization
        if action == query.Parameters.FETCH_CONTENT:

            # Convert the training info to the external JSON
            # representation that will be provided to the client
            response_data = training_info.get_JSON_representation()

        ####################################################################
        # Create training action
        # Note: Requires synchronized access to active sessions list
        elif action == query.Parameters.CREATE_TRAINING:

            if not instance_count:
                self.respond_error(Storyboard.INSTANCE_COUNT_MISSING_ERROR)
                return

            try:
                instance_count_value = int(instance_count)
            except ValueError as error:
                self.respond_error(Storyboard.INSTANCE_COUNT_INVALID_ERROR)
                return

            if not ttype:
                self.respond_error(Storyboard.TRAINING_TYPE_MISSING_ERROR)
                return

            if not scenario:
                self.respond_error(Storyboard.SCENARIO_NAME_MISSING_ERROR)
                return

            if not level:
                self.respond_error(Storyboard.LEVEL_NAME_MISSING_ERROR)
                return

            # Synchronize access to active sessions list and related variables
            self.lock_active_sessions.acquire()
            try:
                cyber_range_id = self.generate_cyber_range_id(
                    self.pending_sessions)
                if cyber_range_id:
                    # Convert to string for internal representation
                    cyber_range_id = str(cyber_range_id)
                    self.pending_sessions.append(cyber_range_id)
                    print "* INFO: trngsrv: Allocated session with ID #%s." % (
                        cyber_range_id)
                else:
                    self.respond_error(Storyboard.SESSION_ALLOCATION_ERROR)
                    return
            finally:
                self.lock_active_sessions.release()

            ########################################
            # Handle content upload
            content_file_name = training_info.get_content_name(scenario, level)
            if content_file_name == None:
                self.removePendingSession(cyber_range_id)
                self.respond_error(Storyboard.CONTENT_IDENTIFICATION_ERROR)
                return

            content_file_name = DATABASE_DIR + content_file_name

            if DEBUG:
                print "* DEBUG: trngsrv: Training content file: %s" % (
                    content_file_name)

            # Open the content file
            try:
                content_file = open(content_file_name, "r")
                content_file_content = content_file.read()
                content_file.close()

            except IOError as error:
                print "* ERROR: trngsrv: File error: %s." % (error)
                self.removePendingSession(cyber_range_id)
                self.respond_error(Storyboard.CONTENT_LOADING_ERROR)
                return

            try:
                # Note: creating a dictionary as below does not
                # preserve the order of the parameters, but this has
                # no negative influence in our implementation
                query_tuples = {
                    query.Parameters.USER: user_id,
                    query.Parameters.ACTION: query.Parameters.UPLOAD_CONTENT,
                    query.Parameters.DESCRIPTION_FILE: content_file_content,
                    query.Parameters.RANGE_ID: cyber_range_id
                }

                query_params = urllib.urlencode(query_tuples)
                print "* INFO: trngsrv: Send upload request to content server %s." % (
                    CONTENT_SERVER_URL)
                if DEBUG:
                    print "* DEBUG: trngsrv: POST parameters: %s" % (
                        query_params)
                data_stream = urllib.urlopen(CONTENT_SERVER_URL, query_params)
                data = data_stream.read()
                if DEBUG:
                    print "* DEBUG: trngsrv: Content server response body: %s" % (
                        data)

                (status,
                 activity_id) = query.Response.parse_server_response(data)

                if DEBUG:
                    print(
                        "* DEBUG: trngsrv: Response status: {}".format(status))
                    print("* DEBUG: trngsrv: Response activity_id: {}".format(
                        activity_id))

                if status == Storyboard.SERVER_STATUS_SUCCESS:
                    # Store activity id in session description
                    pass
                else:
                    print "* ERROR: trngsrv: Content upload error."
                    self.removePendingSession(cyber_range_id)
                    self.respond_error(Storyboard.CONTENT_UPLOAD_ERROR)
                    return

                # Save the response data
                contsrv_response = data

            except IOError as error:
                print "* ERROR: trngsrv: URL error: %s." % (error)
                self.removePendingSession(cyber_range_id)
                self.respond_error(Storyboard.CONTENT_SERVER_ERROR)
                return

            ########################################
            # Handle instantiation
            spec_file_name = training_info.get_specification_name(
                scenario, level)
            if spec_file_name == None:
                self.removePendingSession(cyber_range_id)
                self.respond_error(Storyboard.TEMPLATE_IDENTIFICATION_ERROR)
                return

            spec_file_name = DATABASE_DIR + spec_file_name

            if DEBUG:
                print "* DEBUG: trngsrv: Scenario specification file: %s" % (
                    spec_file_name)

            # Open the specification file (template)
            try:
                spec_file = open(spec_file_name, "r")
                spec_file_content = spec_file.read()
                spec_file.close()

            except IOError as error:
                print "* ERROR: trngsrv: File error: %s." % (error)
                self.removePendingSession(cyber_range_id)
                self.respond_error(Storyboard.TEMPLATE_LOADING_ERROR)
                return

            # Do instantiation
            try:
                # Replace variables in the specification file
                spec_file_content = user_obj.replace_variables(
                    spec_file_content, cyber_range_id, instance_count_value)

                # Note: creating a dictionary as below does not
                # preserve the order of the parameters, but this has
                # no negative influence in our implementation
                query_tuples = {
                    query.Parameters.USER: user_id,
                    query.Parameters.ACTION:
                    query.Parameters.INSTANTIATE_RANGE,
                    query.Parameters.DESCRIPTION_FILE: spec_file_content,
                    query.Parameters.RANGE_ID: cyber_range_id
                }

                query_params = urllib.urlencode(query_tuples)
                print "* INFO: trngsrv: Send instantiate request to instantiation server %s." % (
                    INSTANTIATION_SERVER_URL)
                if DEBUG:
                    print "* DEBUG: trngsrv: POST parameters: %s" % (
                        query_params)
                data_stream = urllib.urlopen(INSTANTIATION_SERVER_URL,
                                             query_params)
                data = data_stream.read()
                if DEBUG:
                    print "* DEBUG: trngsrv: Instantiation server response body: %s" % (
                        data)

                # Remove pending session
                self.removePendingSession(cyber_range_id)

                (status, message) = query.Response.parse_server_response(data)

                if DEBUG:
                    print "* DEBUG: trngsrv: Response status:", status
                    print "* DEBUG: trngsrv: Response message:", message

                if status == Storyboard.SERVER_STATUS_SUCCESS:
                    session_name = "Training Session #%s" % (cyber_range_id)
                    crt_time = time.asctime()
                    print "* INFO: trngsrv: Instantiation successful => save training session: %s (time: %s)." % (
                        session_name, crt_time)

                    # Synchronize access to active sessions list
                    self.lock_active_sessions.acquire()
                    try:
                        # Read session info
                        session_info = sessinfo.SessionInfo()
                        session_info.parse_YAML_file(ACTIVE_SESSIONS_FILE)

                        # Add new session and save to file
                        # Scenarios and levels should be given as arrays,
                        # so we convert values to arrays when passing arguments
                        session_info.add_session(session_name, cyber_range_id,
                                                 user_id, crt_time, ttype,
                                                 [scenario], [level], language,
                                                 instance_count, activity_id)
                        session_info.write_YAML_file(ACTIVE_SESSIONS_FILE)
                    finally:
                        self.lock_active_sessions.release()
                else:
                    print "* ERROR: trngsrv: Range instantiation error."
                    self.respond_error(Storyboard.INSTANTIATION_ERROR)
                    return

                # Save the response data
                instsrv_response = data

                if DEBUG:
                    print "* DEBUG: trngsrv: contsrv response: %s" % (
                        contsrv_response)
                    print "* DEBUG: trngsrv: instsrv response: %s" % (
                        instsrv_response)

                # Prepare the response as a message
                # TODO: Should create a function to handle this
                if message:
                    response_data = '[{{"{0}": "{1}"}}]'.format(
                        Storyboard.SERVER_MESSAGE_KEY, message)
                else:
                    response_data = None

            except IOError as error:
                print "* ERROR: trngsrv: URL error: %s." % (error)
                self.removePendingSession(cyber_range_id)
                self.respond_error(Storyboard.INSTANTIATION_SERVER_ERROR)
                return

        ####################################################################
        # Retrieve saved training configurations action
        # Note: Requires synchronized access to saved configurations list
        elif action == query.Parameters.GET_CONFIGURATIONS:

            self.lock_saved_configurations.acquire()
            try:
                # Read session info
                session_info = sessinfo.SessionInfo()
                session_info.parse_YAML_file(SAVED_CONFIGURATIONS_FILE)

                # TODO: Catch error in operation above
            finally:
                self.lock_saved_configurations.release()

            # Convert the training session info to the external JSON
            # representation that will be provided to the client
            response_data = session_info.get_JSON_representation(user_id)

        ####################################################################
        # Retrieve active training sessions action
        # Note: Requires synchronized access to active sessions list
        elif action == query.Parameters.GET_SESSIONS:

            self.lock_active_sessions.acquire()
            try:
                # Read session info
                session_info = sessinfo.SessionInfo()
                session_info.parse_YAML_file(ACTIVE_SESSIONS_FILE)

                # TODO: Catch error in operation above
            finally:
                self.lock_active_sessions.release()

            # Convert the training session info to the external JSON
            # representation that will be provided to the client
            response_data = session_info.get_JSON_representation(user_id)

        ####################################################################
        # End training action
        # Note: Requires synchronized access to active sessions list
        elif action == query.Parameters.END_TRAINING:

            if not range_id:
                print "* ERROR: trngsrv: %s." % (
                    Storyboard.SESSION_ID_MISSING_ERROR)
                self.respond_error(Storyboard.SESSION_ID_MISSING_ERROR)
                return

            activity_id = None
            self.lock_active_sessions.acquire()
            try:
                activity_id = self.check_range_id_exists(range_id, user_id)
                if not activity_id:
                    print "* ERROR: trngsrv: Session with ID " + range_id + " doesn't exist for user " + user_id
                    error_msg = Storyboard.SESSION_ID_INVALID_ERROR + ": " + range_id
                    self.respond_error(error_msg)
                    return
            finally:
                self.lock_active_sessions.release()

            ########################################
            # Handle content removal
            try:
                # Note: Creating a dictionary as below does not
                # preserve the order of the parameters, but this has
                # no negative influence in our implementation
                query_tuples = {
                    query.Parameters.USER: user_id,
                    query.Parameters.ACTION: query.Parameters.REMOVE_CONTENT,
                    query.Parameters.RANGE_ID: range_id,
                    query.Parameters.ACTIVITY_ID: activity_id
                }

                query_params = urllib.urlencode(query_tuples)
                print "* INFO: trngsrv: Send removal request to content server %s." % (
                    CONTENT_SERVER_URL)
                print "* INFO: trngsrv: POST parameters: %s" % (query_params)
                data_stream = urllib.urlopen(CONTENT_SERVER_URL, query_params)
                data = data_stream.read()
                if DEBUG:
                    print "* DEBUG: trngsrv: Content server response body: %s" % (
                        data)

                # We don't parse the response since the content server does not provide
                # a uniformly formatted one; instead we only check for SUCCESS key
                if Storyboard.SERVER_STATUS_SUCCESS in data:
                    # Nothing to do on success as there is no additional info provided
                    pass
                else:
                    print "* ERROR: trngsrv: Content removal error."
                    self.respond_error(Storyboard.CONTENT_REMOVAL_ERROR)
                    return

                # Save the response data
                contsrv_response = data

            except IOError as error:
                print "* ERROR: trngsrv: URL error: %s." % (error)
                self.respond_error(Storyboard.CONTENT_SERVER_ERROR)
                return

            ########################################
            # Handle range destruction
            try:
                # Note: creating a dictionary as below does not
                # preserve the order of the parameters, but this has
                # no negative influence in our implementation
                query_tuples = {
                    query.Parameters.USER: user_id,
                    query.Parameters.ACTION: query.Parameters.DESTROY_RANGE,
                    query.Parameters.RANGE_ID: range_id
                }

                query_params = urllib.urlencode(query_tuples)
                print "* INFO: trngsrv: Send destroy request to instantiation server %s." % (
                    INSTANTIATION_SERVER_URL)
                print "* INFO: trngsrv: POST parameters: %s" % (query_params)
                data_stream = urllib.urlopen(INSTANTIATION_SERVER_URL,
                                             query_params)
                data = data_stream.read()
                if DEBUG:
                    print "* DEBUG: trngsrv: Instantiation server response body: %s" % (
                        data)

                (status, message) = query.Response.parse_server_response(data)

                if status == Storyboard.SERVER_STATUS_SUCCESS:

                    self.lock_active_sessions.acquire()
                    try:
                        # Read session info
                        session_info = sessinfo.SessionInfo()
                        session_info.parse_YAML_file(ACTIVE_SESSIONS_FILE)

                        # Remove session and save to file
                        if not session_info.remove_session(range_id, user_id):
                            print "* ERROR: Cannot remove training session %s." % (
                                range_id)
                            self.respond_error(
                                Storyboard.SESSION_INFO_CONSISTENCY_ERROR)
                            return
                        else:
                            session_info.write_YAML_file(ACTIVE_SESSIONS_FILE)
                    finally:
                        self.lock_active_sessions.release()

                else:
                    print "* ERROR: trngsrv: Range destruction error: %s." % (
                        message)
                    self.respond_error(Storyboard.DESTRUCTION_ERROR)
                    return

                instsrv_response = data

                if DEBUG:
                    print "* DEBUG: trngsrv: contsrv response: %s" % (
                        contsrv_response)
                    print "* DEBUG: trngsrv: instsrv response: %s" % (
                        instsrv_response)

                # Prepare the response: no data needs to be returned,
                # hence we set the content to None
                response_data = None

            except IOError as error:
                print "* ERROR: trngsrv: URL error: %s." % (error)
                self.respond_error(Storyboard.INSTANTIATION_SERVER_ERROR)
                return

        ####################################################################
        # Catch unknown actions
        else:
            print "* WARNING: trngsrv: Unknown action: %s." % (action)

        # Emulate communication delay
        if EMULATE_DELAY:
            sleep_time = random.randint(2, 5)
            print "* INFO: trngsrv: Simulate communication by sleeping %d s." % (
                sleep_time)
            time.sleep(sleep_time)

        # Respond to requester with SUCCESS
        self.respond_success(response_data)