Microsoft Office 365 Endpoints V1 (Python)

Tonight I’m having a brief look at Microsoft Office 365 Endpoints; https://support.office.com/en-us/article/managing-office-365-endpoints-99cab9d4-ef59-4207-9f2b-3728eb46bf9a?ui=en-US&rs=en-US&ad=US#ID0EACAAA=4._Web_service in my current favourite programming language – Python. My target is to be able to generate the various Endpoint details into an updating PAC or WPAD file. Then I will look at the same in PowerShell.

  • I’ve used the SMTP knowledge I got from my Pollen project
  • I would use Cron to schedule the program to run regularly

Microsoft very kindly already included a Python (and PowerShell) script on the above website; so all I’m doing is modifying it/altering it to do what I need – in this early version that is to output the various data into some files (CSV format for now) and e-mail me when updates are available.

#!/usr/bin/python3
# original source from https://support.office.com/en-us/article/managing-office-365-endpoints-99cab9d4-ef59-4207-9f2b-3728eb46bf9a?ui=en-US&rs=en-US&ad=US#ID0EACAAA=4._Web_service
# modified by geektechstuff

import json
import os
import urllib.request
import uuid
import smtplib

from email_settings import (
smtp_server,
port,
login_user,
login_pass,
from_address,
to_address
)

# helper to call the webservice and parse the response
def webApiGet(methodName, instanceName, clientRequestId):
    ws = "https://endpoints.office.com"
    requestPath = ws + '/' + methodName + '/' + instanceName + '?clientRequestId=' + clientRequestId
    request = urllib.request.Request(requestPath)
    with urllib.request.urlopen(request) as response:
        return json.loads(response.read().decode())


# path where client ID and latest version number will be stored
datapath = '/Users/gary/Downloads/' + '/endpoints_clientid_latestversion.txt'

# URL List for Proxy Server, outputs as CSV
url_list = '/Users/gary/Downloads/365_url_list.csv'

# IPv4 List for Firewall, outputs as CSV
ip_list = '/Users/gary/Downloads/365_ip_list.csv'

# fetch client ID and version if data exists; otherwise create new file
if os.path.exists(datapath):
    with open(datapath, 'r') as fin:
        clientRequestId = fin.readline().strip()
        latestVersion = fin.readline().strip()
else:
    clientRequestId = str(uuid.uuid4())
    latestVersion = '0000000000'
    with open(datapath, 'w') as fout:
        fout.write(clientRequestId + '\n' + latestVersion)

# call version method to check the latest version, and pull new data if version number is different
version = webApiGet('version', 'Worldwide', clientRequestId)
if version['latest'] > latestVersion:
    print('New version of Office 365 worldwide commercial service instance endpoints detected')

    # write the new version number to the data file
    with open(datapath, 'w') as fout:
        fout.write(clientRequestId + '\n' + version['latest'])

    # invoke endpoints method to get the new data
    endpointSets = webApiGet('endpoints', 'Worldwide', clientRequestId)

    # filter results for Allow and Optimize endpoints, and transform these into tuples with port and category
    flatUrls = []
    for endpointSet in endpointSets:
        if endpointSet['category'] in ('Optimize', 'Allow'):
            category = endpointSet['category']
            urls = endpointSet['urls'] if 'urls' in endpointSet else []
            tcpPorts = endpointSet['tcpPorts'] if 'tcpPorts' in endpointSet else ''
            udpPorts = endpointSet['udpPorts'] if 'udpPorts' in endpointSet else ''
            flatUrls.extend([(category, url, tcpPorts, udpPorts) for url in urls])

    flatIps = []
    for endpointSet in endpointSets:
        if endpointSet['category'] in ('Optimize', 'Allow'):
            ips = endpointSet['ips'] if 'ips' in endpointSet else []
            category = endpointSet['category']
            # IPv4 strings have dots while IPv6 strings have colons
            ip4s = [ip for ip in ips if '.' in ip]
            tcpPorts = endpointSet['tcpPorts'] if 'tcpPorts' in endpointSet else ''
            udpPorts = endpointSet['udpPorts'] if 'udpPorts' in endpointSet else ''
            flatIps.extend([(category, ip, tcpPorts, udpPorts) for ip in ip4s])

    print('IPv4 Firewall IP Address Ranges')
    print(','.join(sorted(set([ip for (category, ip, tcpPorts, udpPorts) in flatIps]))))
    # outputs the details to the ip_list variable
    with open(ip_list, 'w') as data_write:
        data_write.write(','.join(sorted(set([ip for (category, ip, tcpPorts, udpPorts) in flatIps]))))

    print('URLs for Proxy Server')
    print(','.join(sorted(set([url for (category, url, tcpPorts, udpPorts) in flatUrls]))))
    # outputs the details to the url_list variable
    with open(url_list, 'w') as data_write:
        data_write.write(','.join(sorted(set([ip for (category, ip, tcpPorts, udpPorts) in flatUrls]))))

    # smtp aka email settings
    smtpObj = smtplib.SMTP_SSL(smtp_server, port)
    smtpObj.login(login_user, login_pass)
    smtpObj.sendmail(from_address, to_address,
                     'From: geektechstuff@DOMAIN\nSubject: 365 EndPoints Updated\n\n')
    smtpObj.quit()

else:
    print('Office 365 worldwide commercial service, no updates detected.')

 

One response to “Microsoft Office 365 Endpoints V1 (Python)”

  1. Microsoft Office 365 Endpoints V2 (Python) – Geek Tech Stuff Avatar

    […] The Microsoft Office 365 Endpoints V1 program did a good job of outputting the endpoint data into CSV files, but what if you wanted the URLs outputted for use as a PAC file? A Proxy Auto Configuration file tells a proxy how to handle traffic depending on URL, host or IP. […]

    Like

Welcome to GeekTechStuff

my home away from home and where I will be sharing my adventures in the world of technology and all things geek.

The technology subjects have varied over the years from Python code to handle ciphers and Pig Latin, to IoT sensors in Azure and Python handling Bluetooth, to Ansible and Terraform and material around DevOps.

Let’s connect