async def process_token_refresh_request(request_context, client_single_request,
                                        server_single_response,
                                        async_splunk_client,
                                        encryption_context):

    if not isinstance(request_context.auth_header, JWTAuthHeader):
        secured_session_token = encryption_context.secure_session_token(
            request_context.auth_header.session_token)
        server_single_response.tokenRefreshResponse.sessionToken = secured_session_token
        server_single_response.tokenRefreshResponse.tokenExpiresAt = 0
        server_single_response.tokenRefreshResponse.code = request_pb2.TokenRefreshResponse.SUCCESS
        return

    session_token = request_context.auth_header.token
    valid_request = await async_is_valid_session_token(
        request_context.current_user, session_token, async_splunk_client)

    if not valid_request:
        server_single_response.tokenRefreshResponse.code = request_pb2.TokenRefreshResponse.ERROR_TOKEN_INVALID
        return

    old_token_info = calculate_token_info(session_token)
    new_JWT = await async_splunk_client.async_create_new_JWT_token(
        request_context.current_user, request_context.auth_header)
    if new_JWT.code not in {HTTPStatus.CREATED, HTTPStatus.OK}:
        error = await new_JWT.text()
        LOGGER.warning(
            "Failed to create new token status_code={}, error={}".format(
                new_JWT.code, error))
        server_single_response.tokenRefreshResponse.code = request_pb2.TokenRefreshResponse.ERROR_CREATING_TOKEN
        return

    new_JWT_json = await new_JWT.json()
    new_jwt_credentials = SplunkJWTCredentials(request_context.current_user)
    new_jwt_credentials.token = new_JWT_json['entry'][0]['content']['token']

    # Get token expiry
    new_token_info = calculate_token_info(new_jwt_credentials.token)
    server_single_response.tokenRefreshResponse.tokenExpiresAt = new_token_info[
        'exp']

    # Encrypt this token
    new_session_token = new_jwt_credentials.get_credentials(
    ) if sys.version_info < (3, 0) else str.encode(
        new_jwt_credentials.get_credentials())
    encrypted_token = encryption_context.secure_session_token(
        new_session_token)
    server_single_response.tokenRefreshResponse.sessionToken = encrypted_token
    server_single_response.tokenRefreshResponse.code = request_pb2.TokenRefreshResponse.SUCCESS
    def sync(self):
        """
        Gets all registered users. Gets all tokens per user, sorted by expiry date. Deletes all tokens except the one
        with the most recent expiration date and any that are being used as subscription credentials.
        """

        all_registered_users = get_all_mobile_users(self.session_key)
        try:
            for user in all_registered_users:
                tokens = get_all_secure_gateway_tokens(self.session_key, user)
                current_time = get_current_timestamp()

                index_to_delete = min(3, len(tokens))
                for i in range(0, index_to_delete - 1):
                    if token[i]['content']['claims']['exp'] < current_time:
                        index_to_delete = i
                        break

                tokens_to_delete = tokens[index_to_delete:]

                kvstore_subscription_credentials = KvStore(
                    constants.SUBSCRIPTION_CREDENTIALS_COLLECTION_NAME,
                    self.session_key,
                    owner=user)
                response, credentials = kvstore_subscription_credentials.get_all_items(
                )
                credentials = json.loads(credentials)
                jwt_credential = [
                    c for c in credentials if 'session_type' in c
                    and c['session_type'] == constants.JWT_TOKEN_TYPE[0]
                ]
                if jwt_credential:
                    subscription_token_info = calculate_token_info(
                        jwt_credential['session_key'])
                else:
                    subscription_token_info = None

                for token in tokens_to_delete:
                    # if that token does not exist in subscription credentials
                    if not subscription_token_info or token[
                            'name'] != subscription_token_info['id']:
                        delete_token_by_id(self.session_key, user,
                                           token['name'])
        except:
            LOGGER.exception("Exception performing DeleteTokensSync")
示例#3
0
 def get_expiration(self):
     return calculate_token_info(self.token)['exp']
async def handle_mdm_authentication_request(mdm_auth_request_proto,
                                            encryption_context, server_context,
                                            logger, config, request_id):
    """
    Takes a MDM Auth Request proto, decrypts the encrypted credentials bundle, validates the credentials, persists
    device information to the server and sends cloudgateway a confirmation result message
    Args:
        mdm_auth_request_proto (MdmAuthenticationRequest proto): request from the client to perform MDM registration
        encryption_context (EncryptionContext):
        server_context (ServerContext): object which specifies how mdm registration should be validated and how
            credentials should be persisted to the server
        logger (Logger): logger class to handle logging

    Returns:

    """

    logger.info(
        "Parsing MDM Authentication Request, request_id={}".format(request_id))
    client_credentials = sb_common_pb2.MdmAuthenticationRequest.ClientCredentials(
    )
    client_credentials.ParseFromString(
        mdm_auth_request_proto.clientCredentials)
    mdm_signature = mdm_auth_request_proto.mdmSignature
    client_signature = mdm_auth_request_proto.clientSignature

    try:
        logger.debug(
            "Validating MDM signature MDM request message, request_id={}".
            format(request_id))
        mdm_signing_key = await server_context.get_mdm_signing_key()

        if not sign_verify(encryption_context.sodium_client, mdm_signing_key,
                           mdm_auth_request_proto.clientCredentials,
                           mdm_signature):
            raise CloudgatewayMdmRegistrationError(
                CloudgatewayMdmRegistrationError.errortype.unknown_error,
                "mdm signature validation failed")

        logger.debug(
            "Validating registration version={}, request_id={}".format(
                client_credentials.registrationVersion, request_id))
        if client_credentials.registrationVersion != MDM_REGISTRATION_VERSION:
            raise CloudgatewayMdmRegistrationError(
                CloudgatewayMdmRegistrationError.ErrorType.UNKNOWN_ERROR,
                "Incompatible Mdm Registration Version. Expected={}".format(
                    MDM_REGISTRATION_VERSION))

        encrypted_credentials_bundle = client_credentials.encryptedCredentialsBundle

        credentials_bundle = mdm.parse_mdm_encrypted_credentials_bundle(
            encrypted_credentials_bundle, encryption_context)
        client_id = credentials_bundle.registeringAppId
        username = credentials_bundle.username
        password = credentials_bundle.password
        encrypt_public_key = credentials_bundle.publicKeyForEncryption
        sign_public_key = credentials_bundle.publicKeyForSigning
        login_type = credentials_bundle.loginType
        user_session_token = credentials_bundle.sessionToken  # JWT session token sent by the client after MDM SAML
        friendly_name = credentials_bundle.registeringAppFriendlyName
        platform = credentials_bundle.registeringAppPlatform

        logger.debug(
            "Validating publicKey signature of MDM request message, request_id={}"
            .format(request_id))

        if not sign_verify(encryption_context.sodium_client, sign_public_key,
                           mdm_auth_request_proto.clientCredentials,
                           client_signature):
            raise CloudgatewayMdmRegistrationError(
                CloudgatewayMdmRegistrationError.ErrorType.UNKNOWN_ERROR,
                "client signature validation failed")

        device_info = DeviceInfo(encrypt_public_key,
                                 sign_public_key,
                                 device_id=make_device_id(
                                     encryption_context, sign_public_key),
                                 app_id=client_id,
                                 client_version="",
                                 app_name=friendly_name,
                                 platform=platform)

        if login_type == constants.SAML:
            encrypted_session_token = user_session_token
            raw_token = base64.b64decode(encrypted_session_token)
            decrypted_session_token = decrypt_session_token(
                encryption_context.sodium_client, raw_token,
                encryption_context.encrypt_public_key(),
                encryption_context.encrypt_private_key())
            session_jsn = json.loads(decrypted_session_token)
            token_type = http_pb2.TokenType.Value('JWT')
            token_expires_at = calculate_token_info(
                session_jsn['token'])['exp']
        else:
            await server_context.validate(username, password, device_info)

            logger.debug(
                "Server validated mdm registration request. request_id={}".
                format(request_id))

            session_token = await server_context.create_session_token(
                username, password)

            encrypted_session_token = encryption_context.secure_session_token(
                session_token)
            token_type = http_pb2.TokenType.Value('SESSION')
            token_expires_at = 0

        server_version = await server_context.get_server_version()

        logger.debug("Server returned server_version={}, request_id={}".format(
            server_version, request_id))

        deployment_name = await server_context.get_deployment_name()

        logger.debug(
            "Server returned deployment_name={}, request_id={}".format(
                deployment_name, request_id))

        server_type_id = await server_context.get_server_type()
        env_metadata = await server_context.get_environment_meta(
            device_info, username)

        pairing_info = mdm.build_pairing_info(encrypted_session_token,
                                              credentials_bundle.username,
                                              server_version,
                                              deployment_name,
                                              server_type_id,
                                              token_type,
                                              token_expires_at,
                                              env_metadata=env_metadata)
        confirmation_result = mdm.build_successful_confirmation_result(
            pairing_info)

        await server_context.persist_device_info(device_info, username)

        logger.info(
            "Successfully persisted device registration information, request_id={}"
            .format(request_id))

    except CloudgatewayMdmRegistrationError as e:
        logger.exception(
            "MDM registration error occurred={}, request_id={}".format(
                e, request_id))
        confirmation_result = mdm.build_error_confirmation_result(e.to_proto())
    except Exception as e:
        logger.exception(
            "Unexpected error occurred during MDM registration={}, request_id={}"
            .format(e, request_id))
        error = http_pb2.HttpError()
        error.code = http_pb2.HttpError.ERROR_UNKNOWN
        error.message = str(e)
        confirmation_result = mdm.build_error_confirmation_result(error)

    mdm_authentication_confirmation_request = mdm.build_mdm_authentication_confirmation_request(
        confirmation_result, encryption_context, device_info)

    r = await mdm.async_send_confirmation_result(
        mdm_authentication_confirmation_request, encryption_context,
        server_context.async_spacebridge_client)
    resp = await r.text()

    logger.info(
        "Completed MDM Authentication Request with response={}, code={}, request_id={}"
        .format(resp, r.code, request_id))

    return mdm_authentication_confirmation_request