This repository has been archived by the owner on Nov 16, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathconnectsample.py
163 lines (140 loc) · 6.14 KB
/
connectsample.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
# See LICENSE in the project root for license information.
"""Main program for Microsoft Graph API Connect demo."""
import json
import sys
import uuid
# un-comment these lines to suppress the HTTP status messages sent to the console
#import logging
#logging.getLogger('werkzeug').setLevel(logging.ERROR)
import requests
from flask import Flask, redirect, url_for, session, request, render_template
from flask_oauthlib.client import OAuth
# read private credentials from text file
client_id, client_secret, *_ = open('_PRIVATE.txt').read().split('\n')
if (client_id.startswith('*') and client_id.endswith('*')) or \
(client_secret.startswith('*') and client_secret.endswith('*')):
print('MISSING CONFIGURATION: the _PRIVATE.txt file needs to be edited ' + \
'to add client ID and secret.')
sys.exit(1)
app = Flask(__name__)
app.debug = True
app.secret_key = 'development'
oauth = OAuth(app)
# since this sample runs locally without HTTPS, disable InsecureRequestWarning
requests.packages.urllib3.disable_warnings()
msgraphapi = oauth.remote_app( \
'microsoft',
consumer_key=client_id,
consumer_secret=client_secret,
request_token_params={'scope': 'User.Read Mail.Send'},
base_url='https://graph.microsoft.com/v1.0/',
request_token_url=None,
access_token_method='POST',
access_token_url='https://login.microsoftonline.com/common/oauth2/v2.0/token',
authorize_url='https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
)
@app.route('/')
def index():
"""Handler for home page."""
return render_template('connect.html')
@app.route('/login')
def login():
"""Handler for login route."""
guid = uuid.uuid4() # guid used to only accept initiated logins
session['state'] = guid
return msgraphapi.authorize(callback=url_for('authorized', _external=True), state=guid)
@app.route('/logout')
def logout():
"""Handler for logout route."""
session.pop('microsoft_token', None)
session.pop('state', None)
return redirect(url_for('index'))
@app.route('/login/authorized')
def authorized():
"""Handler for login/authorized route."""
response = msgraphapi.authorized_response()
if response is None:
return "Access Denied: Reason={0}\nError={1}".format( \
request.args['error'], request.args['error_description'])
# Check response for state
if str(session['state']) != str(request.args['state']):
raise Exception('State has been messed with, end authentication')
session['state'] = '' # reset session state to prevent re-use
# Okay to store this in a local variable, encrypt if it's going to client
# machine or database. Treat as a password.
session['microsoft_token'] = (response['access_token'], '')
# Store the token in another session variable for easy access
session['access_token'] = response['access_token']
me_response = msgraphapi.get('me')
me_data = json.loads(json.dumps(me_response.data))
username = me_data['displayName']
email_address = me_data['userPrincipalName']
session['alias'] = username
session['userEmailAddress'] = email_address
return redirect('main')
@app.route('/main')
def main():
"""Handler for main route."""
if session['alias']:
username = session['alias']
email_address = session['userEmailAddress']
return render_template('main.html', name=username, emailAddress=email_address)
else:
return render_template('main.html')
@app.route('/send_mail')
def send_mail():
"""Handler for send_mail route."""
email_address = request.args.get('emailAddress') # get email address from the form
response = call_sendmail_endpoint(session['access_token'], session['alias'], email_address)
if response == 'SUCCESS':
show_success = 'true'
show_error = 'false'
else:
print(response)
show_success = 'false'
show_error = 'true'
session['pageRefresh'] = 'false'
return render_template('main.html', name=session['alias'],
emailAddress=email_address, showSuccess=show_success,
showError=show_error)
# If library is having trouble with refresh, uncomment below and implement
# refresh handler see https://github.com/lepture/flask-oauthlib/issues/160 for
# instructions on how to do this. Implements refresh token logic.
# @app.route('/refresh', methods=['POST'])
# def refresh():
@msgraphapi.tokengetter
def get_token():
"""Return the Oauth token."""
return session.get('microsoft_token')
def call_sendmail_endpoint(access_token, name, email_address):
"""Call the resource URL for the sendMail action."""
send_mail_url = 'https://graph.microsoft.com/v1.0/me/microsoft.graph.sendMail'
# set request headers
headers = {'User-Agent' : 'python_tutorial/1.0',
'Authorization' : 'Bearer {0}'.format(access_token),
'Accept' : 'application/json',
'Content-Type' : 'application/json'}
# Use these headers to instrument calls. Makes it easier to correlate
# requests and responses in case of problems and is a recommended best
# practice.
request_id = str(uuid.uuid4())
instrumentation = {'client-request-id' : request_id,
'return-client-request-id' : 'true'}
headers.update(instrumentation)
# Create the email that is to be sent via the Graph API
email = {'Message': {'Subject': 'Welcome to the Microsoft Graph Connect sample for Python',
'Body': {'ContentType': 'HTML',
'Content': render_template('email.html', name=name)},
'ToRecipients': [{'EmailAddress': {'Address': email_address}}]
},
'SaveToSentItems': 'true'}
response = requests.post(url=send_mail_url,
headers=headers,
data=json.dumps(email),
verify=False,
params=None)
if response.ok:
return 'SUCCESS'
else:
return '{0}: {1}'.format(response.status_code, response.text)