Ejemplo n.º 1
0
 def get(self, request):
     auth_code = extract_parameter(request['query'], AUTH_CODE_LABEL,
                                   QUERY_LABEL)
     device_name = extract_parameter(request['query'], DEVICE_NAME_LABEL,
                                     QUERY_LABEL)
     user = request['session']['user']
     system_authtoken = request['system_authtoken']
     return handle_query(auth_code, device_name, user, system_authtoken)
Ejemplo n.º 2
0
 def post(self, request):
     """
     Updates whether the specified app is enabled or not
     """
     authtoken = request['session']['authtoken']
     system_authtoken = request['system_authtoken']
     feature_name = extract_parameter(request[QUERY_LABEL], FEATURE_NAME_LABEL, QUERY_LABEL)
     body = json.loads(request['payload'])
     new_state = extract_parameter(body, FEATURE_ENABLED_LABEL, 'body')
     return set_state_of_app(feature_name, authtoken, system_authtoken, new_state)
Ejemplo n.º 3
0
    def post(self, request):
        """
        Deletes the specified device from the kvstore. Parses necessary data and credentials
        out of the request object, validates permissions, and makes the deletion request.

        Uses POST because DELETE method doesn't work from the Splunk UI
        """
        user = request['session']['user']
        device_owner = user
        if 'device_owner' in request['query'] and py23.py2_check_unicode(
                request['query']['device_owner']):
            device_owner = request['query']['device_owner']
        device_key = extract_parameter(request['query'], DEVICE_KEY_LABEL,
                                       'query')
        system_authtoken = request['system_authtoken']
        user_authtoken = request['session']['authtoken']

        key_bundle = None
        if config.get_mtls_enabled():
            key_bundle = build_key_bundle(system_authtoken)

        LOGGER.info(
            'Deleting device_key=%s in kvstore of device_owner=%s for user=%s'
            % (device_key, device_owner, user))

        return delete_device(user, device_owner, device_key, system_authtoken,
                             user_authtoken, key_bundle)
Ejemplo n.º 4
0
    def post(self, request):
        auth_code = extract_parameter(request['query'], AUTH_CODE_LABEL, QUERY_LABEL)
        user = request['session']['user']
        session_token = request['session']['authtoken']
        system_authtoken = request['system_authtoken']
        body = json.loads(request['payload'])

        return handle_confirmation(auth_code, user, session_token, system_authtoken, body)
Ejemplo n.º 5
0
 def async_delete(self, request):
     """Deletes a workspace by ID."""
     context = RequestContext.from_rest_request(request)
     workspace_id = extract_parameter(request[QUERY], WORKSPACE_ID_LABEL,
                                      QUERY)
     deleted_ids = yield ar_workspace_request_processor.delete_ar_workspace(
         context, self.async_client_factory.kvstore_client(),
         self.async_client_factory.ar_permissions_client(), [workspace_id])
     defer.returnValue({
         PAYLOAD: {
             WORKSPACE_ID_LABEL: deleted_ids
         },
         STATUS: http.OK,
     })
Ejemplo n.º 6
0
    def get(self, request):
        """
        Returns whether a given app_type is enabled or not

        :param query[feature_name] <string> or query[feature_names] <json array>
        """
        authtoken = request['system_authtoken']

        if FEATURE_NAMES_LABEL in request[QUERY_LABEL]:
            try:
                feature_names = json.loads(request[QUERY_LABEL][FEATURE_NAMES_LABEL])
            except ValueError:
                raise Errors.SpacebridgeRestError('Error: "feature_names" query parameter must be a valid JSON array', 400)

            return get_state_of_apps(feature_names, authtoken)

        feature_name = extract_parameter(request[QUERY_LABEL], FEATURE_NAME_LABEL, QUERY_LABEL)
        return get_state_of_app(feature_name, authtoken)
    def delete(self, request):
        """ delete a companion app using comma separated list of app_ids.
        e.g. app_ids=id1,id2,id3
        """
        session_token = request['session']['authtoken']
        app_ids = extract_parameter(request['query'], self.APP_IDS_LABEL, "query")
        app_ids_lst = app_ids.strip().split(',')

        query = {constants.OR_OPERATOR: [{constants.KEY: app_id} for app_id in app_ids_lst]}
        kvstore_client = KVStoreCollectionAccessObject(collection=self.COMPANION_APPS_COLLECTION_NAME,
                                                       session_key=session_token)

        r, content = kvstore_client.delete_items_by_query(query)

        return {
            'payload': content.decode('utf-8'),
            'status': r.status
        }
Ejemplo n.º 8
0
    def get(self, request):
        """
        Handler which generates QR codes using a deep link generated from a dashboard ID, and
        returns it to the client as a binary body of the specified type. This function:
            1. Extracts request data
            2. Validates the requested file type
            3. Validates and transforms the dashboard ID into a deep link
            4. Generates and returns the QR code
        """
        # Extracts request data
        user = request['session']['user']
        dashboard_id = extract_parameter(request['query'], DASHBOARD_ID_LABEL,
                                         'query')
        file_type = request['path_info'].split('.')[-1]
        id_type = 'a' if 'isAr' in request['query'] else 's'

        # Validates the requested file type
        if file_type not in get_valid_file_types(with_names=False):
            raise Errors.SpacebridgeRestError(
                'QR code was requested with invalid file_type=%s' % file_type)

        # Validates and transforms the dashboard ID into a deep link
        deep_link = shorten_dashboard_id_from_url(dashboard_id)
        if deep_link == dashboard_id:  # Nothing was shortened so it must be an invalid dashboard_id
            raise Errors.SpacebridgeRestError(
                'QR code was requested for invalid dashboard_id=%s' %
                dashboard_id)
        deep_link = 'https://spl.mobi/%s%s/%s' % (
            id_type, QR_CODE_DASHBOARD_VERSION, deep_link)

        LOGGER.info('Generated QR code of deep_link=%s for user=%s' %
                    (deep_link, user))

        # Generates and returns the QR code
        return {
            'binary': generate_qr_code(deep_link, file_type),
            'status': 200,
        }
Ejemplo n.º 9
0
    def get(self, request):
        """
        Handler which checks if a dashboard is compatible with mobile
        """
        # Extracts request data
        user = request['session']['user']
        dashboard_id = extract_parameter(request['query'], DASHBOARD_ID_LABEL,
                                         'query')

        # TODO: This.
        is_compatible = True

        LOGGER.info(
            'Checked mobile compatibility of dashboard_id=%s for user=%s. is_compatible=%s'
            % (dashboard_id, user, is_compatible))

        # Generates and returns the QR code
        return {
            'payload': {
                'valid': is_compatible,
            },
            'status': 200,
        }
Ejemplo n.º 10
0
def handle_confirmation(auth_code, user, session_token, system_authtoken, body):
    """
    Handler for the final DevicePairingConfirmationRequest call. This function:
        1. Authenticates the supplied username and password
        2. Retrieves temporary record from the kvstore
        3. Checks if app_type has been disabled since registration
        4. Makes the DevicePairingConfirmationRequest request to the server
        5. Creates a new permanent record for the device in the kvstore
        6. Deletes the temporary kvstore record

    :param auth_code: User-entered authorization code to be returned to Spacebridge
    :param body: Parsed JSON body of the incoming POST request
    :param kvstore_unconfirmed: Access object for the temporary registration kvstore
    :param system_authtoken: System-level access token for writing to the kvstore
    :return: Success message
    """

    # Authenticates the supplied username and password
    kvstore_temp = KvStore(constants.UNCONFIRMED_DEVICES_COLLECTION_NAME, system_authtoken, owner=user)
    encryption_context = SplunkEncryptionContext(system_authtoken, constants.SPACEBRIDGE_APP_NAME)
    username = extract_parameter(body, USERNAME_LABEL, BODY_LABEL)
    password = extract_parameter(body, PASSWORD_LABEL, BODY_LABEL)

    try:
        # use what Splunk thinks the username is to generate the session token
        auth =  BasicAuthHeader(username, password)
        content = get_current_context(auth)
        username = content[constants.ENTRY][0][constants.CONTENT][constants.USERNAME]
    except SpacebridgePermissionsError as e:
        LOGGER.exception('Invalid credentials passed to current-context API')
        raise e


    LOGGER.info('Received new registration confirmation request by user=%s for device_owner=%s' % (user, username))

    # Retrieves temporary record from the kvstore
    temp_key = extract_parameter(body, KVSTORE_TEMPORARY_ID_LABEL, BODY_LABEL)
    r, temp_record = kvstore_temp.get_item_by_key(temp_key)
    temp_record = json.loads(temp_record)

    device_id = temp_record[DEVICE_ID_LABEL]
    device_id_raw = base64.b64decode(device_id)

    device_registration = {'_key': py23.urlsafe_b64encode_to_str(device_id_raw)}
    device_public_keys = {'_key': py23.urlsafe_b64encode_to_str(device_id_raw)}

    for k in temp_record.keys():
        if k in DEVICE_REGISTRATION_ATTRS:
            device_registration[k] = temp_record[k]
        if k in DEVICE_PUBLIC_KEYS_ATTRS:
            device_public_keys[k] = temp_record[k]


    # Checks if app_type has been disabled since registration
    app_name = temp_record[DEVICE_TYPE_LABEL]

    if not retrieve_state_of_app(app_name, system_authtoken):
        disabled_message = 'Registration Error: Application type app_name="%s" is disabled' % app_name
        LOGGER.info(disabled_message)
        return {
            'payload': {
                'message': disabled_message,
                'app_name': app_name,
            },
            'status': 422,
        }

    device_encryption_info = DeviceInfo(
        base64.b64decode(temp_record['encrypt_public_key']),
        base64.b64decode(temp_record['sign_public_key']),
        base64.b64decode(temp_record['device_id']),
        "NA",
        app_id=temp_record['app_id'],
        app_name=temp_record['device_type']
    )

    deployment_friendly_name = get_deployment_friendly_name(system_authtoken)

    try:
        credentials = SplunkJWTCredentials(username, password=password)
        credentials.load_jwt_token(SplunkAuthHeader(session_token))
        LOGGER.info("Successfully fetched jwt token")
    except Exception as e:
        LOGGER.info("Failed to fetch jwt token with message={}. Using basic credentials instead.".format(e))
        credentials = SimpleUserCredentials(username, password)

    pair_device(auth_code, credentials, device_encryption_info, encryption_context,
                server_name=deployment_friendly_name, config=config, server_app_id=constants.SPLAPP_APP_ID)

    # Creates a new permanent record for the device in the kvstore
    kvstore_user = KvStore(constants.REGISTERED_DEVICES_COLLECTION_NAME, system_authtoken, owner=username)
    kvstore_user.insert_single_item(device_registration)

    # Adds the user to the list of users with registered devices, if not already there
    kvstore_users = KvStore(constants.REGISTERED_USERS_COLLECTION_NAME, system_authtoken)
    kvstore_users.insert_or_update_item_containing_key({'_key': username})

    kvstore_nobody = KvStore(constants.DEVICE_PUBLIC_KEYS_COLLECTION_NAME, system_authtoken)
    kvstore_nobody.insert_single_item(device_public_keys)

    # Deletes the temporary kvstore record
    kvstore_temp.delete_item_by_key(temp_key)

    LOGGER.info('Device registration confirmed. Device with device_name=\"%s\" was recorded in the kvstore.' %
                temp_record[DEVICE_NAME_LABEL])

    return {
        'payload': 'Device registration successful',
        'status': 201,
    }
Ejemplo n.º 11
0
    def handle_saml_mdm_request(self, user, session_token, system_authtoken,
                                mdm_signing_bundle, body):
        """
        Handles the MDM SAML Registration Request.
        Validates signature sent from client, validates session token, generates a JWT token,
        and sends it encrypted using splapp's keys and the client public key
        :param user: string provided by rest handler
        :param session_token: string
        :param system_authtoken: string
        :param mdm_signing_bundle: Object
        :param body: JSON
        :return: Reponse object with payload and status
        """
        public_key = base64.b64decode(
            extract_parameter(body, PUBLIC_KEY_LABEL, BODY_LABEL))
        mdm_signature = base64.b64decode(
            extract_parameter(body, MDM_SIGNATURE_LABEL, BODY_LABEL))

        client_keys = EncryptionKeys(None, None, public_key, None)
        client_encryption_context = EncryptionContext(client_keys)

        try:
            valid_signature = yield sign_verify(
                SodiumClient(LOGGER.getChild("sodium_client")),
                base64.b64decode(
                    mdm_signing_bundle['sign_public_key'].encode('utf8')),
                client_encryption_context.encrypt_public_key(), mdm_signature)
        except Exception as e:
            LOGGER.exception(
                "Exception verifying signature from client for user={}".format(
                    user))
            defer.returnValue({
                'payload': {
                    'token': "",
                    'user': user,
                    'status': http.UNAUTHORIZED
                },
                'status': http.OK
            })

        async_splunk_client = self.async_client_factory.splunk_client()
        valid_request = yield valid_session_token(user, session_token,
                                                  async_splunk_client)

        LOGGER.info(
            "Received new mdm registration request by user={}".format(user))

        if valid_signature and valid_request:
            try:
                credentials = SplunkJWTCredentials(user)
                credentials.load_jwt_token(SplunkAuthHeader(system_authtoken))
                LOGGER.info("Successfully fetched jwt token")
            except Exception as e:
                LOGGER.exception(
                    "Exception fetching jwt token for user={} with message={}".
                    format(user, e))
                defer.returnValue({
                    'payload': {
                        'token': "",
                        'user': user,
                        'status': 422
                    },
                    'status': http.OK
                })

            splapp_encryption_context = SplunkEncryptionContext(
                system_authtoken, constants.SPACEBRIDGE_APP_NAME,
                SodiumClient(LOGGER.getChild("sodium_client")))

            # Encrypt session token using splapp keys
            secured_session_token = splapp_encryption_context.secure_session_token(
                credentials.get_credentials())
            # Encrypt session token using client's given public key
            encrypted_jwt_token = yield encrypt_for_send(
                SodiumClient(LOGGER.getChild("sodium_client")),
                client_encryption_context.encrypt_public_key(),
                secured_session_token)
            base64_encrypted_jwt_token = base64.b64encode(encrypted_jwt_token)

            defer.returnValue({
                'payload': {
                    'token': base64_encrypted_jwt_token,
                    'user': user,
                    'status': http.OK
                },
                'status': http.OK
            })
        else:
            LOGGER.info(
                "Error: Mismatched user={} and session token".format(user))
            defer.returnValue({
                'payload': {
                    'token': "",
                    'user': user,
                    'status': http.UNAUTHORIZED
                },
                'status': http.OK
            })
Ejemplo n.º 12
0
def handle_saml_confirmation(auth_code, user, session_token, system_authtoken,
                             body):
    """
    Handler for the final DevicePairingConfirmationRequest call. This function:
        1. Authenticates the supplied user name
        2. Retrieves temporary record from the kvstore
        3. Checks if app_type has been disabled since registration
        4. Makes the DevicePairingConfirmationRequest request to the server
        5. Creates a new permanent record for the device in the kvstore
        6. Deletes the temporary kvstore record

    :param auth_code: User-entered authorization code to be returned to Spacebridge
    :param user: User provided by rest handler
    :param body: Parsed JSON body of the incoming POST request
    :param kvstore_unconfirmed: Access object for the temporary registration kvstore
    :param system_authtoken: System-level access token for writing to the kvstore
    :return: Success message
    """

    # Authenticates the supplied user name
    kvstore_temp = KvStore(constants.UNCONFIRMED_DEVICES_COLLECTION_NAME,
                           system_authtoken,
                           owner=user)
    encryption_context = SplunkEncryptionContext(
        system_authtoken, constants.SPACEBRIDGE_APP_NAME)

    LOGGER.info(
        'Received new registration confirmation request by user={}'.format(
            user))

    # Retrieves temporary record from the kvstore
    temp_key = extract_parameter(body, KVSTORE_TEMPORARY_ID_LABEL, BODY_LABEL)
    r, temp_record = kvstore_temp.get_item_by_key(temp_key)
    temp_record = json.loads(temp_record)

    device_id = temp_record[DEVICE_ID_LABEL]
    device_id_raw = base64.b64decode(device_id)

    device_registration = {
        constants.KEY: py23.urlsafe_b64encode_to_str(device_id_raw)
    }
    device_public_keys = {
        constants.KEY: py23.urlsafe_b64encode_to_str(device_id_raw)
    }

    for k in temp_record.keys():
        if k in DEVICE_REGISTRATION_ATTRS:
            device_registration[k] = temp_record[k]
        if k in DEVICE_PUBLIC_KEYS_ATTRS:
            device_public_keys[k] = temp_record[k]

    # Checks if app_type has been disabled since registration
    app_name = temp_record[DEVICE_TYPE_LABEL]

    device_encryption_info = DeviceInfo(
        base64.b64decode(temp_record['encrypt_public_key']),
        base64.b64decode(temp_record['sign_public_key']),
        base64.b64decode(temp_record['device_id']),
        "NA",
        app_id=temp_record['app_id'],
        app_name=temp_record['device_type'])

    deployment_friendly_name = get_deployment_friendly_name(system_authtoken)

    valid_request = is_valid_session_token(user, session_token)
    if valid_request:
        try:
            credentials = SplunkJWTCredentials(user)
            credentials.load_jwt_token(SplunkAuthHeader(system_authtoken))
            LOGGER.info(
                "Successfully fetched jwt token for SAML auth user with username={}"
                .format(user))
        except Exception as e:
            LOGGER.info(
                "Failed to fetch jwt token for user={} with message={}".format(
                    user, e.message))
            jwt_error_message = 'Registration Error: Failed to fetch jwt token for user={}'.format(
                user)
            return {
                'payload': {
                    'message': jwt_error_message,
                    'app_name': app_name,
                },
                'status': 422,
            }

        pair_device(auth_code,
                    credentials,
                    device_encryption_info,
                    encryption_context,
                    server_name=deployment_friendly_name,
                    config=config,
                    server_app_id=constants.SPLAPP_APP_ID)

        # Creates a new permanent record for the device in the kvstore
        kvstore_user = KvStore(constants.REGISTERED_DEVICES_COLLECTION_NAME,
                               system_authtoken,
                               owner=user)
        kvstore_user.insert_single_item(device_registration)

        # Adds the user to the list of users with registered devices, if not already there
        kvstore_users = KvStore(constants.REGISTERED_USERS_COLLECTION_NAME,
                                system_authtoken)
        kvstore_users.insert_or_update_item_containing_key(
            {constants.KEY: user})

        kvstore_nobody = KvStore(constants.DEVICE_PUBLIC_KEYS_COLLECTION_NAME,
                                 system_authtoken)
        kvstore_nobody.insert_single_item(device_public_keys)

        # Deletes the temporary kvstore record
        kvstore_temp.delete_item_by_key(temp_key)

        LOGGER.info(
            'Device registration confirmed. Device with device_name=\"%s\" was recorded in the kvstore.'
            % temp_record[DEVICE_NAME_LABEL])
    else:
        LOGGER.info("Error: Mismatched user={} and session token".format(user))
        jwt_error_message = 'Registration Error: Failed to fetch jwt token for user={}'.format(
            user)
        return {
            'payload': {
                'message': jwt_error_message,
                'app_name': app_name,
            },
            'status': 422,
        }

    return {
        'payload': 'Device registration successful',
        'status': 201,
    }