def _acquire_service_token(self, username, password, service_target=None, service_policy=None): """Retrieve service token""" logger = self.logger(self._acquire_service_token.__name__) payload = self._prepare_request_from_template( 'SAML.xml', { 'auth_url': self.__sts_profile.authorityUrl, 'username': username, 'password': password, 'message_id': str(uuid.uuid4()), 'created': self.__sts_profile.created, 'expires': self.__sts_profile.expires, 'issuer': self.__sts_profile.federationTokenIssuer }) logger.debug_secrets('options: %s', payload) response = requests.post( self.__sts_profile.security_token_service_url, data=payload, headers={'Content-Type': 'application/x-www-form-urlencoded'}) token = self._process_service_token_response(response) logger.debug_secrets('security token: %s', token) return token
def get_authentication_cookie(self): """Generate Auth Cookie""" logger = self.logger(self.get_authentication_cookie.__name__) logger.debug_secrets("self.FedAuth: %s\nself.rtFa: %s", self.FedAuth, self.rtFa) return 'FedAuth=' + self.FedAuth + '; rtFa=' + self.rtFa
def acquire_service_token(self, options): """Retrieve service token""" logger = self.logger(self.acquire_service_token.__name__) logger.debug_secrets('options: %s', options) request_body = self.prepare_security_token_request({ 'username': options['username'], 'password': options['password'], 'endpoint': self.url }) sts_url = 'https://' + options['sts']['host'] + options['sts']['path'] response = requests.post( sts_url, data=request_body, headers={'Content-Type': 'application/x-www-form-urlencoded'}) token = self.process_service_token_response(response) logger.debug_secrets('token: %s', token) if token: self.token = token return True return False
def get_authentication_cookie(self): """Build auth cookie""" logger = self.logger(self.get_authentication_cookie.__name__) logger.debug_secrets(self._auth_cookies) return "; ".join([ "=".join([key, str(val)]) for key, val in self._auth_cookies.items() ])
def acquire_service_token_from_adfs(self, adfs_url, username, password): logger = self.logger(self.acquire_service_token_from_adfs.__name__) payload = self._prepare_request_from_template( 'FederatedSAML.xml', { 'auth_url': adfs_url, 'username': username, 'password': password, 'message_id': str(uuid.uuid4()), 'created': self.__sts_profile.created, 'expires': self.__sts_profile.expires, 'issuer': self.__sts_profile.federationTokenIssuer }) response = requests.post( adfs_url, data=payload, headers={'Content-Type': 'application/soap+xml; charset=utf-8'}) try: xml = ElementTree.fromstring(response.content) # 1.find assertion assertion_node = xml.find( '{0}Body/{1}RequestSecurityTokenResponse/{1}RequestedSecurityToken/{2}Assertion' .format(self.__ns_prefixes['s'], self.__ns_prefixes['wst'], self.__ns_prefixes['saml'])) if assertion_node is None: self.error = 'Cannot get security assertion for user {0} from {1}'.format( self.__username, adfs_url) logger.error(self.error) return None # 2. prepare & submit token request self.__sts_profile.signInPage = '_vti_bin/idcrl.svc' self.__sts_profile.securityTokenServicePath = 'rst2.srf' template = self._prepare_request_from_template( 'RST2.xml', { 'auth_url': self.__sts_profile.authorityUrl, 'serviceTokenUrl': self.__sts_profile.security_token_service_url }) template_xml = ElementTree.fromstring(template) security_node = template_xml.find('{0}Header/{1}Security'.format( self.__ns_prefixes['s'], self.__ns_prefixes['wsse'])) security_node.insert(1, assertion_node) payload = ElementTree.tostring(template_xml).decode() # 3. get token response = requests.post( self.__sts_profile.security_token_service_url, data=payload, headers={'Content-Type': 'application/soap+xml'}) token = self._process_service_token_response(response) logger.debug_secrets('security token: %s', token) return token except ElementTree.ParseError as e: self.error = 'An error occurred while parsing the server response: {}'.format( e) logger.error(self.error) return None
def prepare_security_token_request(params): """Construct the request body to acquire security token from STS endpoint""" logger = SamlTokenProvider.logger(SamlTokenProvider.prepare_security_token_request.__name__) logger.debug_secrets('params: %s', params) f = open(os.path.join(os.path.dirname(__file__), 'SAML.xml')) data = f.read() for key in params: data = data.replace('[' + key + ']', params[key]) return data
def _prepare_request_from_template(template_name, params): """Construct the request body to acquire security token from STS endpoint""" logger = SamlTokenProvider.logger() logger.debug_secrets('params: %s', params) f = open(os.path.join(os.path.dirname(__file__), template_name)) try: data = f.read() for key in params: data = data.replace('{' + key + '}', str(params[key])) return data finally: f.close()
def authenticate_request(self, request): """ :param request: """ logger = self.logger(self.authenticate_request.__name__) self.ensure_authentication_cookie() logger.debug_secrets(self._cached_auth_cookies) cookie_header_value = "; ".join([ "=".join([key, str(val)]) for key, val in self._cached_auth_cookies.items() ]) request.set_header('Cookie', cookie_header_value)
def acquire_service_token_from_adfs(self, adfs_url, username, password): logger = self.logger(self.acquire_service_token_from_adfs.__name__) now = datetime.now(tz=timezone.utc) created = now.astimezone(timezone.utc).isoformat('T')[:-9] + 'Z' expires = (now + timedelta(minutes=10)).astimezone( timezone.utc).isoformat('T')[:-9] + 'Z' payload = self._prepare_request_from_template( 'FederatedSAML.xml', { 'auth_url': adfs_url, 'message_id': str(uuid.uuid4()), 'username': username, 'password': password, 'created': created, 'expires': expires, 'issuer': self.__sts_profile.federationTokenIssuer }) response = requests.post( adfs_url, data=payload, headers={'Content-Type': 'application/soap+xml; charset=utf-8'}) dom = minidom.parseString(response.content.decode()) assertion_node = dom.getElementsByTagNameNS( "urn:oasis:names:tc:SAML:1.0:assertion", 'Assertion')[0].toxml() try: self.tenant = urlparse(self.__sts_profile.authorityUrl).netloc payload = self._prepare_request_from_template( 'RST2.xml', { 'auth_url': self.tenant, 'serviceTokenUrl': self.__sts_profile.security_token_service_url, 'assertion_node': assertion_node }) # 3. get token response = requests.post( self.__sts_profile.security_token_service_url, data=payload, headers={'Content-Type': 'application/soap+xml'}) token = self._process_service_token_response(response) logger.debug_secrets('security token: %s', token) return token except ElementTree.ParseError as e: self.error = 'An error occurred while parsing the server response: {}'.format( e) logger.error(self.error) return None
def _acquire_service_token_from_adfs(self, adfs_url): logger = self.logger(self._acquire_service_token_from_adfs.__name__) payload = self._prepare_request_from_template( 'FederatedSAML.xml', { 'auth_url': adfs_url, 'message_id': str(uuid.uuid4()), 'username': self._username, 'password': self._password, 'created': self._sts_profile.created, 'expires': self._sts_profile.expires, 'issuer': self._sts_profile.tokenIssuer }) response = requests.post( adfs_url, data=payload, headers={'Content-Type': 'application/soap+xml; charset=utf-8'}) dom = minidom.parseString(response.content.decode()) assertion_node = dom.getElementsByTagNameNS( "urn:oasis:names:tc:SAML:1.0:assertion", 'Assertion')[0].toxml() try: payload = self._prepare_request_from_template( 'RST2.xml', { 'auth_url': self._sts_profile.tenant, 'serviceTokenUrl': self._sts_profile.security_token_service_url, 'assertion_node': assertion_node }) # 3. get security token response = requests.post( self._sts_profile.security_token_service_url, data=payload, headers={'Content-Type': 'application/soap+xml'}) token = self._process_service_token_response(response) logger.debug_secrets('security token: %s', token) return token except ElementTree.ParseError as e: self.error = 'An error occurred while parsing the server response: {}'.format( e) logger.error(self.error) return None
def process_service_token_response(self, response): logger = self.logger(self.process_service_token_response.__name__) logger.debug_secrets('response: %s\nresponse.content: %s', response, response.content) xml = ElementTree.fromstring(response.content) ns_prefixes = { 'S': '{http://www.w3.org/2003/05/soap-envelope}', 'psf': '{http://schemas.microsoft.com/Passport/SoapServices/SOAPFault}', 'wst': '{http://schemas.xmlsoap.org/ws/2005/02/trust}', 'wsse': '{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}' } logger.debug_secrets("ns_prefixes: %s", ns_prefixes) # check for errors if xml.find('{0}Body/{0}Fault'.format(ns_prefixes['S'])) is not None: error = xml.find( '{0}Body/{0}Fault/{0}Detail/{1}error/{1}internalerror/{1}text'. format(ns_prefixes['S'], ns_prefixes['psf'])) self.error = 'An error occurred while retrieving token: {0}'.format( error.text) logger.error(self.error) return None # extract token token = xml.find( '{0}Body/{1}RequestSecurityTokenResponse/{1}RequestedSecurityToken/{2}BinarySecurityToken' .format(ns_prefixes['S'], ns_prefixes['wst'], ns_prefixes['wsse'])) logger.debug_secrets("token: %s", token) return token.text
def _get_authentication_cookie(self, security_token, federated=False): """Retrieve auth cookie from STS :type federated: bool :type security_token: str """ logger = self.logger(self._get_authentication_cookie.__name__) session = requests.session() logger.debug_secrets("session: %s\nsession.post(%s, data=%s)", session, self._sts_profile.signin_page_url, security_token) if not federated: session.post( self._sts_profile.signin_page_url, data=security_token, headers={'Content-Type': 'application/x-www-form-urlencoded'}) else: idcrl_endpoint = "https://{}/_vti_bin/idcrl.svc/".format( self._sts_profile.tenant) session.get(idcrl_endpoint, headers={ 'User-Agent': 'Office365 Python Client', 'X-IDCRL_ACCEPTED': 't', 'Authorization': 'BPOSIDCRL {0}'.format(security_token) }) logger.debug_secrets("session.cookies: %s", session.cookies) cookies = requests.utils.dict_from_cookiejar(session.cookies) logger.debug_secrets("cookies: %s", cookies) if not is_valid_auth_cookies(cookies): self.error = "An error occurred while retrieving auth cookies from {0}".format( self._sts_profile.signin_page_url) logger.error(self.error) raise ValueError(self.error) return cookies
def _process_service_token_response(self, response): logger = self.logger(self._process_service_token_response.__name__) logger.debug_secrets('response: %s\nresponse.content: %s', response, response.content) try: xml = ElementTree.fromstring(response.content) except ElementTree.ParseError as e: self.error = 'An error occurred while parsing the server response: {}'.format( e) logger.error(self.error) return None # check for errors if xml.find('{0}Body/{0}Fault'.format( self.__ns_prefixes['s'])) is not None: error = xml.find( '{0}Body/{0}Fault/{0}Detail/{1}error/{1}internalerror/{1}text'. format(self.__ns_prefixes['s'], self.__ns_prefixes['psf'])) if error is None: self.error = 'An error occurred while retrieving token from XML response.' else: self.error = 'An error occurred while retrieving token from XML response: {0}'.format( error.text) logger.error(self.error) return None # extract token token = xml.find( '{0}Body/{1}RequestSecurityTokenResponse/{1}RequestedSecurityToken/{2}BinarySecurityToken' .format(self.__ns_prefixes['s'], self.__ns_prefixes['wst'], self.__ns_prefixes['wsse'])) if token is None: self.error = 'Cannot get binary security token for from {0}'.format( self.__sts_profile.security_token_service_url) logger.error(self.error) return None logger.debug_secrets("token: %s", token) return token.text
def acquire_authentication_cookie(self, options): """Retrieve SPO auth cookie""" logger = self.logger(self.acquire_authentication_cookie.__name__) url = options['endpoint'] session = requests.session() logger.debug_secrets("session: %s\nsession.post(%s, data=%s)", session, url, self.token) session.post(url, data=self.token, headers={'Content-Type': 'application/x-www-form-urlencoded'}) logger.debug_secrets("session.cookies: %s", session.cookies) cookies = requests.utils.dict_from_cookiejar(session.cookies) logger.debug_secrets("cookies: %s", cookies) if 'FedAuth' in cookies and 'rtFa' in cookies: self.FedAuth = cookies['FedAuth'] self.rtFa = cookies['rtFa'] return True self.error = "An error occurred while retrieving auth cookies" logger.error(self.error) return False
def _acquire_authentication_cookie(self, security_token, federated=False): """Retrieve auth cookie from STS""" logger = self.logger(self._acquire_authentication_cookie.__name__) session = requests.session() logger.debug_secrets("session: %s\nsession.post(%s, data=%s)", session, self.__sts_profile.signin_page_url, security_token) if not federated: self._auth_cookies['FedAuth'] = None self._auth_cookies['rtFa'] = None session.post( self.__sts_profile.signin_page_url, data=security_token, headers={'Content-Type': 'application/x-www-form-urlencoded'}) else: self._auth_cookies['SPOIDCRL'] = None session.head(self.__sts_profile.signin_page_url, headers={ 'User-Agent': 'Office365 Python Client', 'X-IDCRL_ACCEPTED': 't', 'Authorization': 'BPOSIDCRL {0}'.format(security_token), 'Content-Type': 'application/x-www-form-urlencoded' }) logger.debug_secrets("session.cookies: %s", session.cookies) cookies = requests.utils.dict_from_cookiejar(session.cookies) logger.debug_secrets("cookies: %s", cookies) if not cookies: self.error = "An error occurred while retrieving auth cookies from {0}".format( self.__sts_profile.signin_page_url) logger.error(self.error) return False for name in self._auth_cookies.keys(): self._auth_cookies[name] = cookies[name] return True