#!/usr/bin/python
"""

Site24x7 Okta Logs Plugin

"""

from datetime import datetime, timedelta
import json
import os
import sys
import time
import traceback
import glob
import socket

PYTHON_MAJOR_VERSION = sys.version_info[0]
if PYTHON_MAJOR_VERSION == 3:
    import urllib
    import urllib.request as urlconnection
    from urllib.error import URLError, HTTPError
elif PYTHON_MAJOR_VERSION == 2:
    import urllib2 as urlconnection
    from urllib2 import HTTPError, URLError


OKTA_DOMAIN= 'yourOktaDomain'

OKTA_API_TOKEN= 'apiToken'

#if any impacting changes to this plugin kindly increment the plugin version here.
PLUGIN_VERSION = "1"

#Setting this to true will alert you when there is a communication problem while posting plugin data to server
HEARTBEAT="true"

AGENT_HOME = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0]))))

LOG_FILE_DIR = os.path.join(AGENT_HOME, 'temp', 'scriptout')

LOG_ROTATION_INTERVAL='HOUR'

LOG_API_END_POINT='https://'+OKTA_DOMAIN+'/api/v1/logs'


class LogCollector:
    
    def __init__(self):
        pass
    
    def collect_logs(self):
        data = {}
        data['plugin_version'] = PLUGIN_VERSION
        data['heartbeat_required']=HEARTBEAT
        try:
            headers = { 'Authorization': 'SSWS ' + OKTA_API_TOKEN }
            startTime = datetime.utcnow() - timedelta(0, 300)
            request_url = LOG_API_END_POINT+'?since='+ startTime.isoformat()[:-3] + 'Z'
            
            handle, error = self.readUrl(request_url, headers);
            if error is not None:
                data['msg'] = error
                data['status'] = 0
            else:
                okta_events = json.loads(handle.read().decode('utf-8'))
                if not os.path.exists(LOG_FILE_DIR):
                    os.makedirs(LOG_FILE_DIR)
                file_suffix = datetime.now().strftime("%Y-%m-%d-%H" if LOG_ROTATION_INTERVAL == 'HOUR' else "%Y-%m-%d")
                file_path = os.path.join(LOG_FILE_DIR, 'events-'+file_suffix+'.log')
                with open(file_path, 'a') as _file:
                    for okta_event in okta_events:
                        _file.write(json.dumps(okta_event))
                        _file.write("\n")
                        
                try:
                    link_headers = handle.getheader('link').split(',');
                    for link  in link_headers:
                        if 'next' in link:
                            handle, error = self.readUrl(link[2:link.index('>')], headers=headers)
                            if error is None:
                                okta_events = json.loads(handle.read().decode('utf-8'))
                                with open(file_path, 'a') as _file:
                                    for okta_event in okta_events:
                                        _file.write(json.dumps(okta_event))
                                        _file.write("\n")
                except Exception as e:
                    pass
                
                data['msg']= 'Success'
                data['status']=1
        except Exception as e:
            data['msg']= 'Failure : '+str(e)
            data['status']=0
            traceback.print_exc()
        return data
    
    def readUrl(self, url_end_point, headers):
        error=None
        try:
            req = urlconnection.Request(url_end_point, headers=headers)
            handle = urlconnection.urlopen(req, None)
            return handle, error
        except HTTPError as e:
            if(e.code==401):
                error="ERROR: Unauthorized user. Does not have permissions. %s" %(e)
            elif(e.code==403):
                error="ERROR: Forbidden, yours credentials are not correct. %s" %(e)
            else:
                error="ERROR: The server couldn\'t fulfill the request. %s" %(e)
        except URLError as e:
            error = 'ERROR: We failed to reach a server. Reason: %s' %(e.reason)    
        except socket.timeout as e:
            error = 'ERROR: Timeout error'
        except socket.error as e:
            error = "ERROR: Unable to connect with host "+self.host+":"+self.port
        except:
            traceback.print_exc(e)
            error = "ERROR: Unexpected error: %s"%(sys.exc_info()[0])
        return None,error
    
    def cleanup_logs(self):
        try:
            inode_size_map = {}
            stat_file_name = os.path.join(AGENT_HOME, 'statefiles', 'local.properties')
            with open(stat_file_name) as _file:
                lines = _file.readlines()
                for line in lines:
                    if '=' in line:
                        line = line.strip()
                        inode_size_map[line.split('=')[0].strip()] = line.split('=')[1].strip() 
            
            log_files = glob.glob(os.path.join(LOG_FILE_DIR, 'events-*.log'))
            sorted_files = sorted( log_files, key = lambda file: os.path.getmtime(file), reverse=True)
            for log_file in sorted_files[1:]:
                statusObj = os.stat(log_file)
                inode = str(statusObj.st_ino)
                lmtime = datetime.fromtimestamp(statusObj.st_mtime)
                time_delta = datetime.now() - lmtime 
                if (24 * time_delta.days + time_delta.seconds/3600) < 24:
                    file_size = statusObj.st_size
                    if inode in inode_size_map and file_size == int(inode_size_map[inode]):
                        os.remove(log_file)
                else:
                    os.remove(log_file)
        except Exception as e:
            traceback.print_exc(e)
            

if __name__ == "__main__":
    log_collector = LogCollector()
    result = log_collector.collect_logs()
    log_collector.cleanup_logs()
    print(json.dumps(result, indent=4, sort_keys=True))

#!/usr/bin/python
"""

Site24x7 Okta Logs Plugin

"""

from datetime import datetime, timedelta
import json
import os
import sys
import time
import traceback
import glob
import socket

PYTHON_MAJOR_VERSION = sys.version_info[0]
if PYTHON_MAJOR_VERSION == 3:
    import urllib
    import urllib.request as urlconnection
    from urllib.error import URLError, HTTPError
elif PYTHON_MAJOR_VERSION == 2:
    import urllib2 as urlconnection
    from urllib2 import HTTPError, URLError


OKTA_DOMAIN= 'yourOktaDomain'

OKTA_API_TOKEN= 'apiToken'

#if any impacting changes to this plugin kindly increment the plugin version here.
PLUGIN_VERSION = "1"

#Setting this to true will alert you when there is a communication problem while posting plugin data to server
HEARTBEAT="true"

AGENT_HOME = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0]))))

LOG_FILE_DIR = os.path.join(AGENT_HOME, 'temp', 'scriptout')

LOG_ROTATION_INTERVAL='HOUR'

LOG_API_END_POINT='https://'+OKTA_DOMAIN+'/api/v1/logs'


class LogCollector:
    
    def __init__(self):
        pass
    
    def collect_logs(self):
        data = {}
        data['plugin_version'] = PLUGIN_VERSION
        data['heartbeat_required']=HEARTBEAT
        try:
            headers = { 'Authorization': 'SSWS ' + OKTA_API_TOKEN }
            startTime = datetime.utcnow() - timedelta(0, 300)
            request_url = LOG_API_END_POINT+'?since='+ startTime.isoformat()[:-3] + 'Z'
            
            handle, error = self.readUrl(request_url, headers);
            if error is not None:
                data['msg'] = error
                data['status'] = 0
            else:
                okta_events = json.loads(handle.read().decode('utf-8'))
                if not os.path.exists(LOG_FILE_DIR):
                    os.makedirs(LOG_FILE_DIR)
                file_suffix = datetime.now().strftime("%Y-%m-%d-%H" if LOG_ROTATION_INTERVAL == 'HOUR' else "%Y-%m-%d")
                file_path = os.path.join(LOG_FILE_DIR, 'events-'+file_suffix+'.log')
                with open(file_path, 'a') as _file:
                    for okta_event in okta_events:
                        _file.write(json.dumps(okta_event))
                        _file.write("\n")
                        
                try:
                    link_headers = handle.getheader('link').split(',');
                    for link  in link_headers:
                        if 'next' in link:
                            handle, error = self.readUrl(link[2:link.index('>')], headers=headers)
                            if error is None:
                                okta_events = json.loads(handle.read().decode('utf-8'))
                                with open(file_path, 'a') as _file:
                                    for okta_event in okta_events:
                                        _file.write(json.dumps(okta_event))
                                        _file.write("\n")
                except Exception as e:
                    pass
                
                data['msg']= 'Success'
                data['status']=1
        except Exception as e:
            data['msg']= 'Failure : '+str(e)
            data['status']=0
            traceback.print_exc()
        return data
    
    def readUrl(self, url_end_point, headers):
        error=None
        try:
            req = urlconnection.Request(url_end_point, headers=headers)
            handle = urlconnection.urlopen(req, None)
            return handle, error
        except HTTPError as e:
            if(e.code==401):
                error="ERROR: Unauthorized user. Does not have permissions. %s" %(e)
            elif(e.code==403):
                error="ERROR: Forbidden, yours credentials are not correct. %s" %(e)
            else:
                error="ERROR: The server couldn\'t fulfill the request. %s" %(e)
        except URLError as e:
            error = 'ERROR: We failed to reach a server. Reason: %s' %(e.reason)    
        except socket.timeout as e:
            error = 'ERROR: Timeout error'
        except socket.error as e:
            error = "ERROR: Unable to connect with host "+self.host+":"+self.port
        except:
            traceback.print_exc(e)
            error = "ERROR: Unexpected error: %s"%(sys.exc_info()[0])
        return None,error
    
    def cleanup_logs(self):
        try:
            inode_size_map = {}
            stat_file_name = os.path.join(AGENT_HOME, 'statefiles', 'local.properties')
            with open(stat_file_name) as _file:
                lines = _file.readlines()
                for line in lines:
                    if '=' in line:
                        line = line.strip()
                        inode_size_map[line.split('=')[0].strip()] = line.split('=')[1].strip() 
            
            log_files = glob.glob(os.path.join(LOG_FILE_DIR, 'events-*.log'))
            sorted_files = sorted( log_files, key = lambda file: os.path.getmtime(file), reverse=True)
            for log_file in sorted_files[1:]:
                statusObj = os.stat(log_file)
                inode = str(statusObj.st_ino)
                lmtime = datetime.fromtimestamp(statusObj.st_mtime)
                time_delta = datetime.now() - lmtime 
                if (24 * time_delta.days + time_delta.seconds/3600) < 24:
                    file_size = statusObj.st_size
                    if inode in inode_size_map and file_size == int(inode_size_map[inode]):
                        os.remove(log_file)
                else:
                    os.remove(log_file)
        except Exception as e:
            traceback.print_exc(e)
            

if __name__ == "__main__":
    log_collector = LogCollector()
    result = log_collector.collect_logs()
    log_collector.cleanup_logs()
    print(json.dumps(result, indent=4, sort_keys=True))

#!/usr/bin/python Site24x7 Okta Logs Plugin #if any impacting changes to this plugin kindly increment the plugin version here. #Setting this to true will alert you when there is a communication problem while posting plugin data to server