Skip to content
This repository has been archived by the owner on Jun 16, 2020. It is now read-only.

Commit

Permalink
Merge pull request #1 from steelman/master
Browse files Browse the repository at this point in the history
Use cURL for more advanced authentication schemes
  • Loading branch information
kautsig committed Mar 9, 2015
2 parents 8d0820c + 0072a9c commit b1c9907
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 17 deletions.
18 changes: 18 additions & 0 deletions README.org
Expand Up @@ -13,6 +13,24 @@ Change into the directory and create a config file:
: cp config.cfg.sample config.cfg
: emacs config.cfg

The only mandatory field of the configuration file is 'host', pointing
to your server. Other fields have somewhat sane values that should fit
your needs.

+ host - server name without protocol, e.g. your.exchange.host.org.
+ path - web-service path, defaults to e.g. /ews/Exchange.asmx.
+ username - user's name for HTTP authentications, may be omitted in
some situations (e.g. with GSSAPI).
+ password - password for HTTP authentications.
+ auth_type - One of: 'any', 'basic', 'digest', 'ntlm',
'negotiate'. 'any' makes the choice automatically and chooses any of
the mechanisms provided by a server except 'Basic. This one has enabled explicitly.
+ cainfo - file holding certificate used to sign server key.
+ timezone - Your time zone e.g. Europe/Vienna, defaults to UTC.
+ days_history - How old entries to fetch.
+ days_future - How long in the future to look for entries.
+ max_entries - How many entries to fetch.

The config.cfg is within the .gitignore file, so you don't publish it by accident.
Now, run the script:

Expand Down
4 changes: 3 additions & 1 deletion config.cfg.sample
Expand Up @@ -3,7 +3,9 @@ host=servername without protocol, e.g. your.exchange.host.org
path=webservice path, e.g. /ews/Exchange.asmx
username=username
password=password
auth_type=any
timezone=Europe/Vienna
days_history=7
days_future=30
max_entries=100
max_entries=100
cainfo=/path/to/root_ca.crt
76 changes: 60 additions & 16 deletions ews-fetch-calendar.py
Expand Up @@ -10,21 +10,34 @@
from datetime import date
from datetime import timedelta
from pytz import timezone
from StringIO import StringIO
import pytz
import httplib
import pycurl
import base64
import ConfigParser

# Read the config file
config = ConfigParser.RawConfigParser()
dir = os.path.realpath(__file__)[:-21]
config.read(dir + 'config.cfg')
timezoneLocation = os.getenv('TZ', 'UTC')
config = ConfigParser.RawConfigParser({
'path': '/ews/Exchange.asmx',
'username': '',
'password': '',
'auth_type': 'any',
'cainfo': '',
'timezone': timezoneLocation,
'days_history': 7,
'days_future': 30,
'max_entries': 100})
dir = os.path.dirname(os.path.realpath(__file__))
config.read(os.path.join(dir, 'config.cfg'))

# Exchange user and password
ewsHost = config.get('ews-orgmode', 'host')
ewsUrl = config.get('ews-orgmode', 'path')
ewsUser = config.get('ews-orgmode', 'username')
ewsPassword = config.get('ews-orgmode', 'password')
ewsAuthType = config.get('ews-orgmode', 'auth_type').lower()
ewsCAInfo = config.get('ews-orgmode', 'cainfo')
timezoneLocation = config.get('ews-orgmode', 'timezone')
daysHistory = config.getint('ews-orgmode', 'days_history')
daysFuture = config.getint('ews-orgmode', 'days_future')
Expand Down Expand Up @@ -95,21 +108,52 @@ def print_orgmode_entry(subject, start, end, location, response):
</FindItem>
</soap:Body>
</soap:Envelope>""".format(start, end, maxEntries)
request_len = len(request)
request = StringIO(request)
# Debug code
# print request.getvalue()
# exit(0)

h = []
h.append('Content-Type: text/xml; charset=UTF-8')
h.append('Content-Length: %d' % request_len);

# Build authentication string, remove newline for using it in a http header
auth = base64.encodestring("%s:%s" % (ewsUser, ewsPassword)).replace('\n', '')
conn = httplib.HTTPSConnection(ewsHost)
conn.request("POST", ewsUrl, body = request, headers = {
"Host": ewsHost,
"Content-Type": "text/xml; charset=UTF-8",
"Content-Length": len(request),
"Authorization" : "Basic %s" % auth
})
header = StringIO()
body = StringIO()

c = pycurl.Curl()
# Debug code
c.setopt(c.VERBOSE, 1)

c.setopt(c.URL, 'https://%s%s' % (ewsHost, ewsUrl))
c.setopt(c.POST, 1)
c.setopt(c.HTTPHEADER, h)

if ewsAuthType == 'digest':
c.setopt(c.HTTPAUTH, c.HTTPAUTH_DIGEST)
elif ewsAuthType == 'basic':
c.setopt(c.HTTPAUTH, c.HTTPAUTH_BASIC)
elif ewsAuthType == 'ntlm':
c.setopt(c.HTTPAUTH, c.HTTPAUTH_NTLM)
elif ewsAuthType == 'negotiate':
c.setopt(c.HTTPAUTH, c.HTTPAUTH_GSSNEGOTIATE)
elif ewsAuthType == 'any':
c.setopt(c.HTTPAUTH, c.HTTPAUTH_ANYSAFE)
c.setopt(c.USERPWD, '%s:%s' % (ewsUser, ewsPassword))

if len(ewsCAInfo) > 0:
c.setopt(c.CAINFO, ewsCAInfo)

# http://stackoverflow.com/questions/27808835/fail-to-assign-io-object-to-writedata-pycurl
c.setopt(c.WRITEFUNCTION, body.write)
c.setopt(c.HEADERFUNCTION, header.write)
c.setopt(c.READFUNCTION, request.read)

c.perform()
c.close()

# Read the webservice response
resp = conn.getresponse()
data = resp.read()
conn.close()
data = body.getvalue()

# Debug code
# print data
Expand Down

0 comments on commit b1c9907

Please sign in to comment.