Having problems with your account or logging in?
A lot of changes are happening in the community right now. Some may affect you. READ MORE HERE
Highlighted
Absent Member.. SteveDavis Absent Member..
Absent Member..
4601 views

Using WebInspect Enterprise Rest Api to create a scan template

I am trying to use the REST API in WIE 16.20 to create a scan template and then run a scan with a scheduled job. To create a new scan template there needs to be a uploaded scan settings file. I am having difficulty getting this setting file setup properly. There seems to be two API command that need to work according to the Swagger UI doc to post the scan setting file so the scan template can be created:

POST /api/v1/tempFile

POST /api/v1/tempFile/{id}/fileData

I see an entry in the database in the scanSettingsTempFile table after the first post, but the data column is null and the FileID is always a string of zeros. I do not anyway to change or reference this file in creating a scan template.

Anyone got this to work?

0 Likes
7 Replies
Regular Contributor.. shooking_sap Regular Contributor..
Regular Contributor..

Re: Using WebInspect Enterprise Rest Api to create a scan template

I am also interested in this.

We are trying to do this in 18.10 release.

If you look at the API you can see there is a little more info now:

    • POST /api/v1/tempFile
      • Saves a file temporarily so that it can be incorporated into a scan or a scan template

      Implementation Notes

      Temporary files such as a login macro or workflow macro, webform values file, wsdl file for web service scan or a URL list file for a list driven scan.
      The file ID should be a GUID which the user specifies. It uniquely identifies a specific tempFile object. The session ID should be a GUID which the user specifies. The session ID allows several tempFile objects to be related and incorporated into a single scan. The process to upload a temp file requires 2 steps. First, create a new tempFile object: POST http://wiehost:port/WIE/REST/api/v1/tempFile { "sessionID": "CAB0FF81-3F74-4BC1-AA53-8EB5DA42F2E2", "fileID": "CAB0FF81-3F74-4BC1-AA53-8EB5DA42F2E2", "filename": "scanSettings2.xml", "fileType": 5 }

      Next the data from the file is uploaded using the session ID that was created:

      POST https://wiehost:port/WIE/REST/api/tempFile/CAB0FF81-3F74-4BC1-AA53-8EB5DA42F2E2/fileData

      This endpoint expect a form-data upload where the data type is file instead of text.

      Now the tempFile can be used by an endpoint that expects a fileID or sessionID (scan creation, macro creation, scan template creation, etc).

      And there is a doc I found that hints but doesnt quite work at how to achieve this

      "WIE REST Scan Creation" - I found it on the forum somewhere - but again it doest make things clear.

      As the new API suggested the ID has to be a GUID - we worked this out by trial and error.

      But i cannot get the right command/syntax of the POST to upload the settings file correctly. If one already exists I can handle this. But not one I created earlier that I want to upload!!

      Any help would be appreciated.

      Happy to share my code so far.

      Regards
      Steve Hookings

      SAP Security Expert

       

0 Likes
Regular Contributor.. shooking_sap Regular Contributor..
Regular Contributor..

Re: Using WebInspect Enterprise Rest Api to create a scan template

Here;s the PDF version of the helpful guide by Julie.

Alas I need a bit more explicit help regarding programmtically setting these IDs etc

https://softwaresupport.softwaregrp.com/group/softwaresupport/search-result/-/facetsearch/attachment/KM03084009?fileName=[WIE]%20How%20do%20I%20use%20the%20REST%20API%20to%20start%20a%20scan.pdf

I see in the new docs that I think fileType=5 is likely now fileType="none".

But I cannot work out what the meaning of the set post to data etc means.

A programming example would be good - for example my code looks like:

 

def upload_settings_file(session, auth_token, sID, fName):
    url = system_url + '/WIE/REST/api/v1/tempFile?api_key=session'
    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'FortifyToken={}'.format(auth_token)
    }
#    print url
# recall needs to be escaped ... for the moment assume good people do this
#        "filename": "D:\\WIE_APPS\\ScanSettings_bodgeit_guided.xml",
    paramsdata = {
        "sessionID": sID,
        "fileID": sID,
        "filename": fName,
        "fileType": 5
    }
 
    response = session.post(url, headers=header, data=json.dumps(paramsdata), verify=False)
# sometimes this returns 201 ... do we handle this?
    if not response.status_code == requests.codes.ok:
        print response
        sys.exit('Failed upload_settings_file with status {}'.format(response.status_code))
#    return response.json()['data']
 url = system_url + '/WIE/REST/api/v1/tempFile/{}/fileData?api_key=session'.format(sID)
    header = {
        'Content-Type': 'multipart/form-data',
        'Accept': 'text/html',
        'Authorization': 'FortifyToken={}'.format(auth_token)
    }

    response = session.post(url, headers=header, data=json.dumps(paramsdata), verify=False)
# sometimes this returns 201 ... do we handle this?
    if not response.status_code == requests.codes.ok:
        print response
        sys.exit('Failed upload_settings_file_2 with status {}'.format(response.status_code))
    return response.json()['data']

 

which I called like

sID = "RANDOM_AUSTRIAN_PANTS"

fName = "D:\\WIE_APPS\\ScanSettings_bodgeit_guided.xml"
theData = upload_settings_file(session=session , auth_token=auth_token, sID=sID , fName=fName)

Now, I can see now my sID needs to be a GUID - but when I change it to such it still doesnt work.

I am misinterpreting the steps of the doc somehow.

But if I already have a settings file on the system I can find this with API call, check it is in the right securityOrg/group and use this one to start my scan no problems!

So my issue is some concrete programming examples on how to upload a file ... any psuedo code welcome.

 

0 Likes
Regular Contributor.. shooking_sap Regular Contributor..
Regular Contributor..

Re: Using WebInspect Enterprise Rest Api to create a scan template

OK so I got a lot further today ONCE I started to look on the DB.

The API suggests 2 steps

1 - create a session and file ID

2 - upload the content as data.

this simply doesnt bloody work!!! Until you look at the DB.

I took their canonical GUID and modified the session and file IDs to end in C3P0 and R2D2 respectively - that way you can see what is happening.

Step 1 works ... here's the POST

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{  \ 
 "sessionID": "CAB0FF81-3F74-4BC1-AA53-8EB5DA42C3P0", \ 
  "fileID": "CAB0FF81-3F74-4BC1-AA53-8EB5DA42R2D2", \ 
  "filename": "scanSettings3.xml", \ 
  "fileType": 5 }' 'https://mysitep/WIE/REST/api/v1/tempFile'

and I get a 201 and 200 back

Response body:
{
  "responseCode": 201,
  "message": null
}

Response Code:
200

Next I take a scan settings file from bodgeit I created earlier.
And I load this to the end point -- fails.

curl -X POST --header 'Content-Type: multipart/form-data' --header 'Accept: application/json' {"type":"formData"} 'https://mysite/WIE/REST/api/v1/tempFile/CAB0FF81-3F74-4BC1-AA53-8EB5DA42R2D2/fileData'

2018-08-31 16:16:33,883 ERROR [303] GlobalExceptionLogger.Log - Unhandled exception
2018-08-31 16:16:33,883 ERROR [303] GlobalExceptionLogger.Log -
System.FormatException: Unrecognized Guid format.
   at System.Guid.GuidResult.SetFailure(ParseFailureKind failure, String failureMessageID, Object failureMessageFormatArgument, String failureArgumentName, Exce
ption innerException)
   at System.Guid.TryParseGuid(String g, GuidStyles flags, GuidResult& result)
   at System.Guid..ctor(String g)
   at WIE.Rest.Controllers.TokenController.Post()
   at lambda_method(Closure , Object , Object[] )
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)

   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken
 cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at WIE.Rest.Filters.WIEAuthenticationAttribute.AuthCookieInjector.<ExecuteActionFilterAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.AuthenticationFilterResult.<ExecuteAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()

So I looked on the DB and imagine my surprise ...

ID          FileID    FileName            FileType              Data              UploadTime

00000000-0000-0000-0000-000000000000         00000000-0000-0000-0000-000000000000             scanSettings3.xml              5 NULL               2018-08-31 14:45:31.910

Notice how the GUID is infact effectively NULL. Not sure how to get better "feedback" and would be really swell if the real GUID can be nailed down. Even if I use the system supplied GUID I get this empty ID - the stacktrace in the REST log seems to imply this is "expected" given some error.

What if I post to this "empty" GUID?


curl -X POST --header 'Content-Type: multipart/form-data' --header 'Accept: application/json' {"type":"formData"} 'https://mysite/WIE/REST/api/v1/tempFile/00000000-0000-0000-0000-000000000000/fileData'
 

ID          FileID    FileName            FileType              Data              UploadTime

00000000-0000-0000-0000-000000000000         00000000-0000-0000-0000-000000000000             scanSettings3.xml              5 0x3C3F786D6C2076657273696F6E3D22312...616              2018-08-31 14:45:31.910

It works! And the data size (in bytes) is same as my file

Can I make use of this file?

Yup

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ \ 
  "name": "MY_PANTS_ARE_ON_FIRE_IN_DEV_FAKE_TEMPLATE", \ 
  "priority": 3,  \ 
  "projectVersion": { \ 
     "siteId": "XXXXXX" \ 
   },  \ 
   "policy": {"id": "cb72a7c2-9207-4ee7-94d0-edd14a47c15c"}, \ 
   "sensor": {"id": "YYYY"},  \ 
   "fileID": "00000000-0000-0000-0000-000000000000" \ 
 }' 'https://mysite/WIE/REST/api/v1/scans'
And on the system I indeed see the scan is now running using the constraints of this uploaded file

TO DO

1 - work out why the FILE ID / SITE ID are being set a nulls
2 - debug my Python to automate this part - I sent the curls etc from the Swagger UI - no need for the complication of the postman description - but hopefully I can fake up the Python to do what cURL has done.

 

0 Likes
mlacasse Super Contributor.
Super Contributor.

Re: Using WebInspect Enterprise Rest Api to create a scan template

Just a quick observation on your post commands.  I don't see an auth token being passed in.

I just ran a similar test after creating an auth token:

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ "sessionID": "CAB0FF81-3F74-4BC1-AA53-8EB5DA42F2E1", "fileID": "CAB0FF81-3F74-4BC1-AA53-8EB5DA42F2E1", "filename": "scanSettings2.xml", "fileType": 5 }' 'https://tao.acme.local/WIE/REST/api/v1/tempFile?api_key=FORTIFYTOKEN%20MTY3MTdiN2MtNmExYy00ZjcwLTg0MDQtM2M3ZjRhZmNhM2Vj'

Response Body

{
  "responseCode": 201,
  "message": null
}

Response Code

200

 

Then upload xml

curl -X POST --header 'Content-Type: multipart/form-data' --header 'Accept: application/json' {"type":"formData"} 'https://tao.acme.local/WIE/REST/api/v1/tempFile/CAB0FF81-3F74-4BC1-AA53-8EB5DA42F2E1/fileData?api_key=FORTIFYTOKEN%20MTY3MTdiN2MtNmExYy00ZjcwLTg0MDQtM2M3ZjRhZmNhM2Vj'

Response Body

{
  "data": null,
  "responseCode": 200,
  "message": null
}

Response Code

200

 

Database entries:

ID FileID FileName FileType Data UploadTime
CAB0FF81-3F74-4BC1-AA53-8EB5DA42F2E1, CAB0FF81-3F74-4BC1-AA53-8EB5DA42F2E1, scanSettings2.xml, 5, <long list of hex>, 2018-08-31 16:31:28.623

 

 

-mark

 

 

 

 

 

0 Likes
Regular Contributor.. shooking_sap Regular Contributor..
Regular Contributor..

Re: Using WebInspect Enterprise Rest Api to create a scan template

Hi Mark.

Excellent points - except I was using "session" from Python API - so once I associate the Fortify Token I am good (until the session expires).

For me the two issues were

1 - What should the FILEID be?

In 18.10 docs this is described as a GUID. But what variant? I have a support ticket with WIE asking them to be more clear about this.

In general the API returns 200 regardless of the type of GUID (or random chars) - only returning 500 if there is a pre-existing DB entry.

In the REST API log of WIE you can see there was an error! And in the DB you can find a series of 0's.

What I did as a hack was use MS-SQL Server to generate a GUID then export this to my program via a literal.

 

2 - The semantics of the formData was not clear to me

Fortunately I found a Python API that solves this mystery. And now I can take a settings file, get the API to load it, and then execute the scan.

I would much prefer a "script" example rather than a lot of Postman pictures.

I will post a python program later in the week - incase anyone is interesting an an example - note the code is not meant to be production ready :-) Just a hack to demonstrate some of the API usage in Python at least. And since Python is something I use via the magic of stackoflow dont expect it to be pretty!

 

0 Likes
Regular Contributor.. shooking_sap Regular Contributor..
Regular Contributor..

Re: Using WebInspect Enterprise Rest Api to create a scan template

OK as promised this is how I hacked the python to load a previously stored settings file and execute a scan.

You can see I include other functions to allow simple scan and scan given a template file.

I have commented out the template scan, but the idea is you find a suitable template you already stored in WIE then grab the policyID (in this case standard), sensor ID, sec group etc from your pre-configured WIE project/version/scan.

Code is Python 2.7.15

 

import datetime
import sys
import argparse
import requests
import json
import os
from requests.utils import quote
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
import uuid

reload(sys)
sys.setdefaultencoding('utf8')


programName="wie_get_projects_and_scan_settings.py"

class Arguments:
    def __init__(self):
        self.parser = argparse.ArgumentParser(programName)
        self.parser._action_groups.pop()
        self.required = self.parser.add_argument_group('required arguments')
        self.optional = self.parser.add_argument_group('optional arguments')
        self.define_script_arguments()
    def define_script_arguments(self):
        # Required Arguments
        self.required.add_argument('--host', dest='theHost',
                                   nargs=1, help='Hostname')
        self.required.add_argument('--user', dest='user_name',
                                   nargs=1, help='Username')
        self.required.add_argument('--password', dest='user_password',
                                   nargs=1, help='Password')
        self.required.add_argument('--project', dest='theProjectHost',
                                   nargs=1, help='which project to store scan under')
        self.required.add_argument('--fname', dest='theFilename',
                                   nargs=1, help='which settings file to load')
    def get_arguments(self):
        args = Arguments.unpack_argument_lists(self.parser.parse_args())
        Arguments.validate_arguments(args)
        return args
    @staticmethod
    def unpack_argument_lists(args):
        args.user_name = next(iter(args.user_name or []), None)
        args.user_password = next(iter(args.user_password or []), None)
        return args
    @staticmethod
    def validate_arguments(args):
        # Fast Exit if there are not all required params provided
        if args.user_name is None:
            sys.exit('ERROR: --user is a mandatory parameter')
        if args.user_password is None:
            sys.exit('ERROR: --password is a mandatory parameter')
        if args.theHost is None:
            sys.exit('ERROR: --host is a mandatory parameter')
        if args.theProjectHost is None:
            sys.exit('ERROR: --project to store scan under is a mandatory parameter')
        if args.theFilename is None:
            sys.exit('ERROR: --fname setting file to load')
 
        print 'Build Variables'
        print 'HOST            : {}'.format(args.theHost[0])
        print 'User            : {}'.format(args.user_name)
        print 'Project         : {}'.format(args.theProjectHost[0])
        print 'SettingsFile    : {}'.format(args.theFilename[0])
        print '\n'


def get_auth_token(session):
    url = system_url + '/WIE/REST/api/v1/auth'
    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    }

    paramsdata = {
        'username': args.user_name,
        'password': args.user_password
    }
    response = session.post(url, headers=header, data=json.dumps(paramsdata), verify=False)
    if not response.status_code == requests.codes.ok:
        print response
        sys.exit('Failed login with status {}'.format(response.status_code))
    return response.json()['data']

def get_projects(session, auth_token):
    url = system_url + '/WIE/REST/api/v1/projects?limit=10000'
    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'FortifyToken={}'.format(auth_token)
    }

    response = session.get(url, headers=header, verify=False)
    if not response.status_code == requests.codes.ok:
        sys.exit('Failed get_projects with status {}'.format(response.status_code))
    return response.json()['data']

def get_projectVersions(session, auth_token):
    url = system_url + '/WIE/REST/api/v1/projectVersions?limit=10000'
    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'FortifyToken={}'.format(auth_token)
    }

    response = session.get(url, headers=header, verify=False)
    if not response.status_code == requests.codes.ok:
        sys.exit('Failed get_projectVersions with status {}'.format(response.status_code))
    return response.json()['data']

def get_policies_given_secgroup(session, auth_token, secgroup):
    url = system_url + '/WIE/REST/api/v1/securityGroups/{}/policies'.format(secgroup)
    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'FortifyToken={}'.format(auth_token)
    }

    response = session.get(url, headers=header, verify=False)
    if not response.status_code == requests.codes.ok:
        sys.exit('Failed get_policies_given_secgroup with status {}'.format(response.status_code))
    return response.json()['data']

def get_sensors_given_secgroup(session, auth_token, secgroup):
    url = system_url + '/WIE/REST/api/v1/securityGroups/{}/sensors'.format(secgroup)
    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'FortifyToken={}'.format(auth_token)
    }

    response = session.get(url, headers=header, verify=False)
    if not response.status_code == requests.codes.ok:
        sys.exit('Failed get_sensors_given_secgroup with status {}'.format(response.status_code))
    return response.json()['data']

def get_scan_template(session, auth_token):
    url = system_url + '/WIE/REST/api/v1/scanTemplates'
    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'FortifyToken={}'.format(auth_token)
    }

    response = session.get(url, headers=header, verify=False)
    if not response.status_code == requests.codes.ok:
        sys.exit('Failed get_scan_template with status {}'.format(response.status_code))
    return response.json()['data']

def upload_settings_file(session, auth_token, sID, fID, fName):

    url = system_url + '/WIE/REST/api/v1/tempFile'
    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'FortifyToken={}'.format(auth_token)
    }

    paramsdata = {
        "sessionID": sID,
        "fileID": fID,
        "filename": fName,
        "fileType": 5
    }

    response = session.post(url, headers=header, data=json.dumps(paramsdata), verify=False)
    if not response.status_code == requests.codes.ok:
        print response
        sys.exit('Failed upload_settings_file with status {}'.format(response.status_code))
    files = {'data' : open(fName, "rb")}

    url = system_url + '/WIE/REST/api/v1/tempFile/{}/fileData'.format(fID)
    response = session.post(url, files=files, verify=False)

    if not response.status_code == requests.codes.ok:
        print response
        sys.exit('Failed upload_settings_file_2 with status {}'.format(response.status_code))
    return response.json()

def create_simple_scan(session, auth_token, sName, si, sURL, polID, senID):
    url = system_url + '/WIE/REST/api/v1/scans'
    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'FortifyToken={}'.format(auth_token)
    }

    paramsdata = {
        "projectVersion": {
            "siteId": si
        },
        "startURI": sURL,
        "name": sName,
        "priority": 3,
        "policy": {
            "id": polID,
        },
        "sensor": {
            "id": senID,
        },
    }

    response = session.post(url, headers=header, data=json.dumps(paramsdata), verify=False)
    if not response.status_code == requests.codes.ok:
        sys.exit('Failed create_simple_scan with status {}'.format(response.status_code))
    return response.json()['data']

def create_settings_scan(session, auth_token, sName, sID, fID, si, polID, senID):
    url = system_url + '/WIE/REST/api/v1/scans'
    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'FortifyToken={}'.format(auth_token)
    }

    paramsdata = {
        "projectVersion": {
            "siteId": si
        },
        "fileID": fID,
        "name": sName,
        "priority": 3,
        "policy": {
            "id": polID,
        },
        "sensor": {
            "id": senID,
        },
    }

    response = session.post(url, headers=header, data=json.dumps(paramsdata), verify=False)
    if not response.status_code == requests.codes.ok:
        sys.exit('Failed create_settings_scan with status {}'.format(response.status_code))
    return response.json()['data']

def create_scan_template_scan(session, auth_token, sName, sID, si, polID, senID):
    url = system_url + '/WIE/REST/api/v1/scans'
    header = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'FortifyToken={}'.format(auth_token)
    }

    paramsdata = {
        "projectVersion": {
            "siteId": si
        },
        "scanTemplateId": sID,
        "name": sName,
        "priority": 3,
        "policy": {
            "id": polID,
        },
        "sensor": {
            "id": senID,
        },
    }

    response = session.post(url, headers=header, data=json.dumps(paramsdata), verify=False)
    if not response.status_code == requests.codes.ok:
        sys.exit('Failed create_scan_template_scan with status {}'.format(response.status_code))
    return response.json()['data']

 

#############################################
# Initialization of Script Arguments
#############################################
script_arguments = Arguments()
args = script_arguments.get_arguments()
print args.theHost[0]
system_url = 'https://' + args.theHost[0]
os.environ['no_proxy'] = args.theHost[0]
# Variable Declarations
startTime = datetime.datetime.utcnow().isoformat()
# Start a new session
session = requests.session()

print('Fetch Auth Token: begin')
auth_token = get_auth_token(session=session)

print('Fetch Auth Token: end')

myProjID = -1

print('Getting projects: begin')
theProjects = get_projects(session=session, auth_token=auth_token)
print('Getting projects: end')

if theProjects is None:
    print "No matching project - exiting"
    sys.exit(1)

#
# Look for the supplied project container - if not found then exist
found = False
for pP in theProjects:
#    print "{}\t\t{}".format(pP['name'], pP['id'])
    if pP['name'] != args.theProjectHost[0]:
       continue

    found = True
#    print "{}\t\t{}".format(pP['name'], pP['id'])
    myProjID = pP['id']

if found == False:
    print "Did not find project " + args.theProjectHost[0]
    sys.exit(1)

print
print

print "Getting project versions"
print
print

thePolicies = []
theSensors  = []

# Now we look for a project-version that belongs to the project
# We get the first one - you may want to choose from a list

theProjectVersions = get_projectVersions(session=session, auth_token=auth_token)
if theProjectVersions is None:
    print "No matching project versions - exiting"
    sys.exit(1)

# Stop at first matching ProjectVersion given project id
for pPV in theProjectVersions:
    if pPV['project']['id'] != myProjID:
        continue
    theSiteID = pPV['siteId']
    print "ProjectVersion\t{}\t\tname\t{}\tID\t{}\tProject ID\t{}".format(pPV['name'], pPV['project']['name'], pPV['id'], pPV['project']['id'])
    print "SiteID\t{}".format(pPV['siteId'])
    print "SecurityGroup\t{}\tID\t{}".format(pPV['securityGroup']['name'], pPV['securityGroup']['id'])
    print "Organization\t{}\tID\t{}".format(pPV['organization']['name'], pPV['organization']['id'])

    thePolicies = get_policies_given_secgroup(session=session, auth_token=auth_token, secgroup=pPV['securityGroup']['id'])
    theSensors = get_sensors_given_secgroup(session=session, auth_token=auth_token, secgroup=pPV['securityGroup']['id'])
    break
   

polID = -1
for pPol in thePolicies:
    if pPol['name'] == 'Standard':
        polID = pPol['id']
        break

# find first available sensor from this SecurityGroup
sensID = -1
print "SENSOR"
if theSensors is None:
    print "No sensors are assigned to SecurityGroup " + pPV
    sys.exit(1)

scanTemplates = get_scan_template(session=session, auth_token=auth_token)

sID = "EMPTY"
"""
# set a scan template name if you want to look up available templates in WIE
foundST = False
for st in scanTemplates:
    if st['name'] == "WIE_ADMIN_CREATED_BODGEIT_TEMPLATE":
        foundST = True
        print st
        sID = st['id']
"""


# HACK whilst we wait for WIE call ticket to specify the type of the GUID
sID="d37cb4e5-04d2-4ae4-aac3-b7b25e4e09c0".upper()
print sID

"""
fName = "ScanSettings_bodgeit_guided_1914.xml"
"""

print "UPLOAD: begin"

theData = upload_settings_file(session=session , auth_token=auth_token, sID=sID, fID=sID , fName=args.theFilename[0])

print "UPLOAD: end"

myScanName = "SCAN_FROM_UPLOADED_FILE"

# Consider making this a parameter
print "Name: " + myScanName
print "ScanTemplateID: " + sID
print "SiteID: " + theSiteID
print "PolicyID: " + polID
print "Sensor: " + theSensors[0]['id']

 

css = create_settings_scan(session=session, auth_token=auth_token,
            sName=myScanName,
            sID = sID,
            fID = sID,
            si=theSiteID,
            polID=polID,
            senID=theSensors[0]['id'])
print css

 

 

Here's a typical usage: (I obscure some output - yours will be different anyhow)

c:\Python27\python.exe WIE_GET_PROJECTS_AND_SCAN_SETTINGS.py --host <your hostname> --user %MYUSER% --password %MYPASSWORD% --fname ScanSettings_bodgeit_guided_1914.xml --project WIEAPI
Build Variables
HOST            : <your hostname>
User            : <your user>
Project         : WIEAPI
SettingsFile    : ScanSettings_bodgeit_guided_1914.xml
Fetch Auth Token: begin
Fetch Auth Token: end
Getting projects: begin
Getting projects: end


Getting project versions


ProjectVersion  1               name    WIEAPI  ID      4       Project ID      1
SiteID  XXXXX
SecurityGroup   SGROUP  ID     YYYYYY
Organization    ORG   ID      ZZZZ
SENSOR
D37CB4E5-04D2-4AE4-AAC3-B7B25E4E09C0
UPLOAD: begin
UPLOAD: end
Name: SCAN_FROM_UPLOADED_FILE
ScanTemplateID: D37CB4E5-04D2-4AE4-AAC3-B7B25E4E09C0
SiteID: XXXXX
PolicyID: cb72a7c2-9207-4ee7-94d0-edd14a47c15c
Sensor: blahblah
{u'appType': u'WebInspect', u'creatorUserName': u'xxxx', u'scanRequestId': None, u'useAnySensor': False, u'publishedStateText': u'Unpublished', u'resultsState': None, u'parent': {u'id': u'PPPPPP', u'name': None}, u'scanState': 0, u'scanTemplateId': None, u'appVersion': None, u'id': u'VVVV', u'priority': 3, u'policy': {u'id': u'cb72a7c2-9207-4ee7-94d0-edd14a47c15c', u'name': u'Standard'}, u'sensor': {u'id': u'UUUUUU', u'name': u'XXXX'}, u'scanType': 0, u'childScanType': 0, u'productType': u'WebInspect', u'scanEndTime': None, u'publishedDate': None, u'blackoutMode': 0, u'scanStatistics': {u'bpCount': None, u'criticalCount': None, u'highCount': None, u'mediumCount': None, u'lowCount': None, u'infoCount': None}, u'scheduledScanId': None, u'appSubType': u'WIE Sensor', u'startURI': u'http://XXXXX/bodgeit', u'publishedState': 0, u'permissions': {u'PERM_SCAN_CHANGE_SITE': True, u'PERM_SCAN_VERIFY_VULNS': False, u'PERM_SCAN_VISUALIZABLE': False, u'PERM_SCAN_START': False, u'PERM_SCAN_CREATE_SCHEDULE': True, u'PERM_SCAN_EXPORT': False, u'PERM_SCAN_COPY': True, u'PERM_SCAN_PUBLISH': False, u'PERM_SCAN_EXPORTWI': False, u'PERM_SCAN_REPEAT': True, u'PERM_SCAN_RESUME': False, u'PERM_SCAN_SUSPEND': True, u'PERM_SCAN_CREATE_TEMPLATE': True, u'PERM_SCAN_CREATE_REPORT': False, u'PERM_SCAN_STOP': True, u'PERM_SCAN_DELETE': True, u'PERM_SCAN_EXPORT_SETTINGS': True, u'PERM_SCAN_RENAME': True}, u'name': u'SCAN_FROM_UPLOADED_FILE', u'scanStartTime': None, u'creationTime': u'2018-09-10T18:41:51.163', u'securityGroup': {u'id': u'XXXX', u'name': u'NAMENAME'}, u'project': {u'id': 1, u'name': u'WIEAPI'}, u'projectVersion': {u'siteId': u'XXXX', u'id': 4, u'name': u'1'}, u'scanStateText': u'Pending', u'organization': {u'id': u'YYYYY', u'name': u'PPPP'}, u'fileID': None}

 

NOTE: this program is provided without any form or warranty etc - it is just a hack to show one way to use the REST API to submit a scan file to create scans.

I put the pem certificates in the certifi cacerts file so that SSL connection can be made direct to our servers.

The idea is to look up an existing project on the WIE.

Once found, look for the siteID (essentially the application version id) of the first matching application associated with the project - clearly you can change this alg to suit you needs

Find the security group, the organzation

Upload the file - note the issue with GUID - I have a call ticket with WIE to get the documentation changed.

LIMITED ERROR CHECKING has been applied - of course you should refine the code - again the idea is to save you all a load of effort interpreting the poorly documented API ... you should be able to generalise the above to map to the other available API calls.

 

0 Likes
Regular Contributor.. shooking_sap Regular Contributor..
Regular Contributor..

Re: Using WebInspect Enterprise Rest Api to create a scan template

OK so I worked it out - the GUID.

What I did was realise the SQL Schema wants a 16 byte uniqueidentifier.

Of course a GUID is a 128bit quantity.

128 bits = 16 bytes x 8 bytes / bit

So the trick was to use the uuid from Python,

import uuid

...

ssID = str(uuid.uuid1()).upper()

 

and it works a charm.

CAVEATs ... of course here I am generating a UUID from my client.

When I send this to the WIE there is no guarantee that someone else will not have already taken this UUID. It is unlikely but the real solution would be for the WebInspect Enterprise to extend its API to

 

GET == SessionID

GET == FileIDGivenSessionID(sessionID)

It could check that the number is not already reserved.

0 Likes
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.