Introduction
During digital transformation, every business uses a diverse set of technologies to build application to digitize non-digital processes and operations. The “Cloud Application Programming Model” (CAP) offered by SAP can be used to develop enterprise-grade cloud services or applications and deploy on the SAP Business Technology Platform (BTP). You can learn more about CAP by visiting this page.
In almost every application, one or more business documents are uploaded. These documents or files need to be check for virus or other malware. SAP provides a service called ‘SAP Malware Scanning Service’ on BTP to scan business documents for malware.
In this blog post, we’ll look at how to create a cap application that allows users to upload files and check them for malware using the SAP Malware Scanning Service.
Develop and Deploy application
Often project templates are used to generate the skeleton of a CAP application. But this time we shall see how we can create an application using command line. If you don’t want to follow step by step, you can find the complete project here.
- If you are using local set up instead of SAP Business Application Studio (BAS), then install cap development kit: npm install -g @sap/cds-dk
use cds –help command to verify installation is successful. Also install rimraf package which is used later using npm install -g rimraf
- Create a project using cds init cap-media-malware command where cap-media-malware is the project name. It creates the project layout with a project descriptor package.json, folder app for UI content, folder db for database related artifacts and folder srv for service related content. You can modify your project description in package.json descriptor file.
- Install the dependencies using npm install command
- Make sure you are on cap-media-malware folder in terminal. Then create a file using command touch db/schema.cds and fill with following content:
namespace cap.media.db; using {cuid} from '@sap/cds/common'; entity MediaFiles : cuid { @Core.MediaType : type content : LargeBinary; @Core.IsMediaType : true type : String; filename: String; }
Note-1, cuid aspect is used to add universally unique primary key to the entity.
Note-2, MediaFiles entity needs to be annotated with following annotations to indicate that a field contains media data.
@Core.MediaType: Indicates that the element contains media data
@Core.IsMediaType: Indicates that the element contains a MIME type - Create service definition file using touch srv/service.cds command and add following content
using { cap.media.db as db } from '../db/schema'; service MediaService { entity MediaFiles as projection on db.MediaFiles; }
- SAP Malware Scanning Service provides REST based apis to scan document for malware and api definition is described in OpenAPI Hence, we will use OpenAPI client generator feature of SAP Cloud SDK for Javascript to consume service apis. You can find more information about SAP Cloud SDK here.
- Go to SAP Malware Scanning Service on API Business Hub, download OpenAPI specification from here and save as MalwareScanAPI.json.
- Create folders to keep api specifications and api clients using following command
mkdir srv/resources
mkdir srv/resources/api-specs
mkdir srv/resources/api-clients
Copy MalwareScanAPI.json file downloaded in previous step into api-specs folder. - Install SAP Cloud SDK OpenAPI code generator dependencies using following commands:
npm install @sap-cloud-sdk/openapi-generator –save –D
npm install @sap-cloud-sdk/openapi –save - Generate api client for Malware Scanning Service based on the imported specification using below command:
npx openapi-generator -t -i srv/resources/api-specs/MalwareScanAPI.json -o srv/resources/api-clients - Now let’s add logic in service implementation to scan documents before it is updated in db.
Create service implementation using touch srv/service.js and copy following code:const cds = require("@sap/cds"); const apiMalwareScan = require("./resources/api-clients/MalwareScanAPI/default-api") const { PassThrough } = require('stream') module.exports = cds.service.impl(async function (srv) { const { MediaFiles } = this.entities; srv.on('PUT', MediaFiles, async (req, next) => { const url = req._.req.path, chunks = []; if (url.includes('content')) { let mediaMalwareScanner = function (req) { let malwarescan = new Promise(function (resolve, reject) { req.data.content.on('data', chunk => chunks.push(chunk)); req.data.content.on('end', async (req) => { let body = Buffer.concat(chunks).toString('binary'); let requestBuilder = await apiMalwareScan.DefaultApi.createScan(body); requestBuilder.addCustomHeaders({ 'Content-Type': 'application/octet-stream' }); requestBuilder.addCustomHeaders({ 'Accept': 'application/json' }); let response = await requestBuilder.skipCsrfTokenFetching().execute({ destinationName: 'cap-media-malwarescanner-dest' }); resolve(response.malwareDetected); }); }); return malwarescan; } let isMalwareDetected = await mediaMalwareScanner(req); if (isMalwareDetected) { req.error(500, 'Malware Detected'); } else { req.data.content = new PassThrough(); req.data.content.push(Buffer.concat(chunks)); req.data.content.push(null); next() } } else { return next(); } }); })
Note-1, mediaMalwareScanner function is used to call malware scanning service api and determine whether the document contains malware or not.
Note-2, SAP Cloud SDK requires destination service and xsuaa (SAP Authorization and Trust Management Service) service instance to execute api.
Note-3, cap-media-malwarescanner-dest destination is used for api call which can be created manually on SAP BTP cockpit or programmatically during deployment which is explained in later part of the blog.
- Now Let’s prepare the application to deploy it on SAP BTP using MTA (Multi-Target Application) deployment approach.
add mta deployment descriptor using command: cds add mta - Add Hana Cloud and XSUAA configuration to the project using following command:
cds add hana
cds add xsuaa
Install dependencies using npm install - Add destination service as a resource in deployment descriptor mta.yaml as shown below:
- name: cap-media-malware-destination type: org.cloudfoundry.managed-service parameters: service: destination service-name: cap-media-malware-destination service-plan: lite
- Also add destination service resource as a dependency in requires section of cap service module cap-media-malware-srv
- name: cap-media-malware-destination
- Add Malware Scanner Service as a resource to the deployment descriptor mta.yaml
- name: cap-media-malwarescanner type: org.cloudfoundry.managed-service parameters: service: malware-scanner service-name: cap-media-malwarescanner service-plan: clamav
- Add following module of type com.sap.application.content [Generic Application Content Deployment protocol (GACD)] to create the destination cap-media-malwarescanner-dest required to execute malware scanner api.
More information regarding GACD can be found at this page.- name: cap-media-destinations type: com.sap.application.content requires: - name: cap-media-malware-destination parameters: content-target: true - name: cap-media-malwarescanner parameters: service-key: name: malwarescanner-key parameters: content: subaccount: existing_destinations_policy: update destinations: - Name: cap-media-malwarescanner-dest ServiceInstanceName: cap-media-malwarescanner ServiceKeyName: malwarescanner-key build-parameters: no-source: true
- Add following scripts to project descriptor package.json:
“undeploy“: “cf undeploy cap-media-malware –delete-services –delete-service-keys“,
“build“: “rimraf resources mta_archives && mbt build –mtar archive“,
“deploy“: “cf deploy mta_archives/archive.mtar –retries 1“ - Before deployment of the application, make sure you have a multi-environment subaccount, hana cloud service is running and have entitlement of SAP Malware Scanning service
To verify these pre-requisites, you can follow below pages:
Getting Started with an Enterprise Account in the Cloud Foundry Environment
Managing Entitlements and Quotas Using the Cockpit - Build your project using command: npm run build
- Login to your multi-environment subaccount using following commands:
cf api <Cloud Foundry API Endpoint>
cf login - Deploy your project using command: npm run deploy
Note down the cap service url from terminal as shown below:
Test the Application
- Create 2 files test.txt and malware.test.txt under srv folder out of which malware.test.txt contains malware. You can also download these sample files from here.
- Copy the test file from here: test.http
- Read environment variables and update test.http file with with xsuaa information:copy environment variables: cf env cap-media-malware-srv > default-env.jsonupdate test.http file
@xsuaaHostname = <<credentials.url – field from xsuaa section of default-env.json>>
@xsuaaClient = <<credentials.clientid – field from xsuaa section of default-env.json>>
@xsuaaSecret = <<credentials.clientsecret – field from xsuaa section of default-env.json>>
@host = <<cap service url after deployment>>
- Now send requests sequentially from test.http file
- Upon sending Request-3 Update filw with Malware, service return error with message ‘Malware Detected’
- Note that, to upload document in cap application, 2 api calls are required. First a POST call to create an entry in Media Data entity and Second a PUT call to upload the actual document content.
Reference Blog:Stay Secure with SAP Malware Scanning on SAP BTP
Conclusion
Using CAP, you can develop business applications to upload documents and integrate SAP Malware Scanning Service to scan those documents for malware.
More information about cloud application programming model can be found here. You can follow my profile to get notification of the next blog post on CAP. Please feel free to provide any feedback you have in the comments section below and ask your questions about the topic in sap community using this link.