1
1
import os
2
2
import uuid
3
3
from xml .etree import ElementTree
4
+ import xml .dom .minidom as minidom
5
+ from urllib .parse import urlparse
6
+
7
+ from datetime import datetime , timezone , timedelta
8
+
4
9
5
10
import requests
6
11
import requests .utils
@@ -106,40 +111,35 @@ def get_last_error(self):
106
111
107
112
def acquire_service_token_from_adfs (self , adfs_url , username , password ):
108
113
logger = self .logger (self .acquire_service_token_from_adfs .__name__ )
114
+
115
+ now = datetime .now (tz = timezone .utc )
116
+ created = now .astimezone (timezone .utc ).isoformat ('T' )[:- 9 ]+ 'Z'
117
+ expires = (now + timedelta (minutes = 10 )).astimezone (timezone .utc ).isoformat ('T' )[:- 9 ]+ 'Z'
118
+
109
119
payload = self ._prepare_request_from_template ('FederatedSAML.xml' , {
110
120
'auth_url' : adfs_url ,
121
+ 'message_id' : str (uuid .uuid4 ()),
111
122
'username' : username ,
112
123
'password' : password ,
113
- 'message_id' : str (uuid .uuid4 ()),
114
- 'created' : self .__sts_profile .created ,
115
- 'expires' : self .__sts_profile .expires ,
124
+ 'created' : created ,
125
+ 'expires' : expires ,
116
126
'issuer' : self .__sts_profile .federationTokenIssuer
117
127
})
128
+
118
129
response = requests .post (adfs_url , data = payload ,
119
130
headers = {'Content-Type' : 'application/soap+xml; charset=utf-8' })
131
+ dom = minidom .parseString (response .content .decode ())
132
+ assertion_node = dom .getElementsByTagNameNS ("urn:oasis:names:tc:SAML:1.0:assertion" , 'Assertion' )[0 ].toxml ()
133
+
120
134
try :
121
- xml = ElementTree .fromstring (response .content )
122
- # 1.find assertion
123
- assertion_node = xml .find (
124
- '{0}Body/{1}RequestSecurityTokenResponse/{1}RequestedSecurityToken/{2}Assertion' .format (
125
- self .__ns_prefixes ['s' ], self .__ns_prefixes ['wst' ], self .__ns_prefixes ['saml' ]))
126
- if assertion_node is None :
127
- self .error = 'Cannot get security assertion for user {0} from {1}' .format (username , adfs_url )
128
- logger .error (self .error )
129
- return None
130
- # 2. prepare & submit token request
131
- self .__sts_profile .signInPage = '_vti_bin/idcrl.svc/'
132
- self .__sts_profile .securityTokenServicePath = 'rst2.srf'
133
- template = self ._prepare_request_from_template ('RST2.xml' , {
134
- 'auth_url' : self .__sts_profile .authorityUrl ,
135
- 'serviceTokenUrl' : self .__sts_profile .security_token_service_url
135
+ self .tenant = urlparse (self .__sts_profile .authorityUrl ).netloc
136
+
137
+ payload = self ._prepare_request_from_template ('RST2.xml' , {
138
+ 'auth_url' : self .tenant ,
139
+ 'serviceTokenUrl' : self .__sts_profile .security_token_service_url ,
140
+ 'assertion_node' : assertion_node
136
141
})
137
- template_xml = ElementTree .fromstring (template )
138
- security_node = template_xml .find (
139
- '{0}Header/{1}Security' .format (self .__ns_prefixes ['s' ], self .__ns_prefixes ['wsse' ]))
140
142
141
- security_node .insert (1 , assertion_node )
142
- payload = ElementTree .tostring (template_xml ).decode ()
143
143
# 3. get token
144
144
response = requests .post (self .__sts_profile .security_token_service_url , data = payload ,
145
145
headers = {'Content-Type' : 'application/soap+xml' })
@@ -212,6 +212,7 @@ def _acquire_authentication_cookie(self, security_token, federated=False):
212
212
:type security_token: str
213
213
"""
214
214
logger = self .logger (self ._acquire_authentication_cookie .__name__ )
215
+
215
216
session = requests .session ()
216
217
logger .debug_secrets ("session: %s\n session.post(%s, data=%s)" , session , self .__sts_profile .signin_page_url ,
217
218
security_token )
@@ -222,7 +223,8 @@ def _acquire_authentication_cookie(self, security_token, federated=False):
222
223
headers = {'Content-Type' : 'application/x-www-form-urlencoded' })
223
224
else :
224
225
self ._auth_cookies ['SPOIDCRL' ] = None
225
- session .get (self .__sts_profile .signin_page_url ,
226
+ idcrlEndpoint = "https://{}/_vti_bin/idcrl.svc/" .format (self .tenant )
227
+ session .get (idcrlEndpoint ,
226
228
headers = {
227
229
'User-Agent' : 'Office365 Python Client' ,
228
230
'X-IDCRL_ACCEPTED' : 't' ,
0 commit comments