1+ import requests
2+ import base64
3+ import getpass # For secure password input (hides input from display)
4+ import json
5+ import csv
6+ import os
7+
8+ class Application :
9+ def __init__ (self , app_id , name ):
10+ self .app_id = app_id
11+ self .name = name
12+
13+ def read_creds_file (filename = "../.creds" ):
14+ """Read credentials from a .creds file"""
15+ creds = {}
16+ try :
17+ with open (filename , "r" ) as f :
18+ for line in f :
19+ line = line .strip () # Remove whitespace from beginning and end of line
20+ # Skip empty lines and comment lines that start with #
21+ if line and not line .startswith ("#" ):
22+ key , value = line .split ("=" , 1 ) # Split on first = only (in case value contains =)
23+ creds [key ] = value
24+ except FileNotFoundError :
25+ print (f"Warning: { filename } file not found. Please input values." )
26+ return creds
27+
28+ # Read credentials from .creds file
29+ creds = read_creds_file ()
30+
31+ # Set the default values for re-using within your organization from .creds file
32+ contrast_url = creds .get ("CONTRAST_URL" , "" ) # .get() returns empty string if key doesn't exist
33+ org_id = creds .get ("ORG_ID" , "" )
34+ username = creds .get ("USERNAME" , "" )
35+ api_key = creds .get ("API_KEY" , "" )
36+ service_key = creds .get ("SERVICE_KEY" , "" )
37+ app_id = creds .get ("APP_ID" , "" )
38+
39+ # Pre-encode credentials for Basic Authentication (done early to avoid repeating)
40+ auth_str = f"{ username } :{ service_key } "
41+ auth_b64 = base64 .b64encode (auth_str .encode ()).decode ()
42+
43+ # Set up HTTP headers for API requests
44+ headers = {
45+ "Accept" : "application/json" # Tell API we want JSON responses
46+ }
47+ # Set up query parameters to expand server data in responses
48+ params = {
49+ "expand" : ["apps" ]
50+ }
51+
52+ def getUsers (headers , params , org_id ):
53+ """Fetch all users from the Contrast API"""
54+ url = f"{ contrast_url } /api/ng/{ org_id } /users"
55+ response = requests .get (url , headers = headers , params = params )
56+ return response
57+
58+ def getServer (headers , params , org_id , server_id ):
59+ """Fetch individual server details including applications"""
60+ url = f"{ contrast_url } /api/ng/{ org_id } /servers/{ server_id } "
61+ response = requests .get (url , headers = headers , params = params )
62+ return response
63+
64+ def read_json_file (filename ):
65+ """Helper function to read JSON files"""
66+ with open (filename , "r" ) as f :
67+ return f .read ()
68+
69+ def main ():
70+ # Allow modification of global variables within this function
71+ global contrast_url , org_id , username , api_key , service_key
72+
73+ # Prompt user for Contrast URL, use default from .creds if blank
74+ msg = f"Enter your Contrast URL (blank will use default '{ contrast_url } '): "
75+ contrast_url_input = input (msg )
76+ if contrast_url_input .strip (): # .strip() removes whitespace, then check if anything remains
77+ contrast_url = contrast_url_input
78+ else :
79+ # Keep prompting if no default exists and user provides blank input
80+ while not contrast_url_input .strip () and not contrast_url .strip ():
81+ print ("Contrast URL cannot be blank." )
82+ contrast_url_input = input (msg )
83+ contrast_url = contrast_url_input
84+
85+ # Prompt user for Organization ID, use default from .creds if blank
86+ msg = f"Enter your Organization ID (blank will use default '{ org_id } '): "
87+ org_id_input = input (msg )
88+ if org_id_input .strip ():
89+ org_id = org_id_input
90+ else :
91+ # Keep prompting if no default exists and user provides blank input
92+ while not org_id_input .strip () and not org_id .strip ():
93+ print ("Organization ID cannot be blank." )
94+ org_id_input = input (msg )
95+ org_id = org_id_input
96+
97+ # Prompt user for username, use default from .creds if blank
98+ msg = f"Enter your username (blank will use default '{ username } '): "
99+ username_input = input (msg )
100+ if username_input .strip ():
101+ username = username_input
102+ else :
103+ # Keep prompting if no default exists and user provides blank input
104+ while not username_input .strip () and not username .strip ():
105+ print ("Username cannot be blank." )
106+ username_input = input (msg )
107+ username = username_input
108+
109+ # Prompt user for API key (hidden input), use default from .creds if blank
110+ msg = f"Enter your API key (blank will use default '****************************'): "
111+ api_key_input = getpass .getpass (msg ) # getpass hides the input from display for security
112+ if api_key_input .strip ():
113+ api_key = api_key_input
114+ else :
115+ # Keep prompting if no default exists and user provides blank input
116+ while not api_key_input .strip () and not api_key .strip ():
117+ print ("API key cannot be blank." )
118+ api_key_input = getpass .getpass (msg )
119+ api_key = api_key_input
120+
121+ # Prompt user for service key (hidden input), use default from .creds if blank
122+ msg = f"Enter your service key (blank will use default '************'): "
123+ service_key_input = getpass .getpass (msg ) # getpass hides the input from display for security
124+ if service_key_input .strip ():
125+ service_key = service_key_input
126+ else :
127+ # Keep prompting if no default exists and user provides blank input
128+ while not service_key_input .strip () and not service_key .strip ():
129+ print ("Service key cannot be blank." )
130+ service_key_input = getpass .getpass (msg )
131+ service_key = service_key_input
132+
133+ # List of specific servers to process (modify this list as needed for your environment)
134+ servers_list = [90926 , 90086 , 90001 ]
135+
136+ # Create Basic Authentication header with encoded credentials
137+ auth_str = f"{ username } :{ service_key } " # Format: username:servicekey
138+ auth_b64 = base64 .b64encode (auth_str .encode ()).decode () # Encode to base64 for Basic auth
139+ headers ["Authorization" ] = f"Basic { auth_b64 } " # Add Authorization header
140+ headers ["API-Key" ] = api_key # Add API key header required by Contrast
141+
142+ # Fetch all servers from the API
143+ response = getUsers (headers , params , org_id )
144+ if response .status_code == 200 : # HTTP 200 means success
145+ data = response .json () # Parse JSON response into Python dict
146+ # Save the full server response to JSON file for debugging/reference
147+ with open ("output.json" , "w" ) as f :
148+ json .dump (data , f , indent = 2 ) # indent=2 makes it human-readable
149+ os .system ('clear' ) # Clear the terminal screen (use 'cls' on Windows)
150+
151+ else :
152+ # Display error if API call failed (non-200 status code)
153+ print (f"Error: { response .status_code } - { response .text } " )
154+
155+ # Only run main() if this script is executed directly (not imported)
156+ if __name__ == "__main__" :
157+ main ()
0 commit comments