Skip to content
This repository was archived by the owner on Jun 11, 2025. It is now read-only.

Commit 6961846

Browse files
committed
Switch to SOAP-based auth provider
1 parent 047084f commit 6961846

File tree

1 file changed

+86
-1
lines changed

1 file changed

+86
-1
lines changed

skpy/conn.py

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import hashlib
88
import base64
99
from pprint import pformat
10+
from xml.etree import ElementTree
1011

1112
from bs4 import BeautifulSoup
1213
import requests
@@ -124,6 +125,7 @@ def externalCall(cls, method, url, codes=(200, 201, 204, 207), **kwargs):
124125

125126
API_LOGIN = "https://login.skype.com/login"
126127
API_MSACC = "https://login.live.com"
128+
API_EDGE = "https://edge.skype.com/rps/v1/rps/skypetoken"
127129
API_USER = "https://api.skype.com"
128130
API_PROFILE = "https://profile.skype.com/profile/v1"
129131
API_OPTIONS = "https://options.skype.com/options/v1/users/self/options"
@@ -363,7 +365,7 @@ def liveLogin(self, user, pwd):
363365
.SkypeAuthException: if the login request is rejected
364366
.SkypeApiException: if the login form can't be processed
365367
"""
366-
self.tokens["skype"], self.tokenExpiry["skype"] = SkypeLiveAuthProvider(self).auth(user, pwd)
368+
self.tokens["skype"], self.tokenExpiry["skype"] = SkypeSOAPAuthProvider(self).auth(user, pwd)
367369
self.getUserId()
368370
self.getRegToken()
369371

@@ -592,6 +594,89 @@ def getToken(self, t):
592594
return (token, expiry)
593595

594596

597+
class SkypeSOAPAuthProvider(SkypeAuthProvider):
598+
599+
template = """
600+
<Envelope xmlns='http://schemas.xmlsoap.org/soap/envelope/'
601+
xmlns:wsse='http://schemas.xmlsoap.org/ws/2003/06/secext'
602+
xmlns:wsp='http://schemas.xmlsoap.org/ws/2002/12/policy'
603+
xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/03/addressing'
604+
xmlns:wst='http://schemas.xmlsoap.org/ws/2004/04/trust'
605+
xmlns:ps='http://schemas.microsoft.com/Passport/SoapServices/PPCRL'>
606+
<Header>
607+
<wsse:Security>
608+
<wsse:UsernameToken Id='user'>
609+
<wsse:Username>{}</wsse:Username>
610+
<wsse:Password>{}</wsse:Password>
611+
</wsse:UsernameToken>
612+
</wsse:Security>
613+
</Header>
614+
<Body>
615+
<ps:RequestMultipleSecurityTokens Id='RSTS'>
616+
<wst:RequestSecurityToken Id='RST0'>
617+
<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>
618+
<wsp:AppliesTo>
619+
<wsa:EndpointReference>
620+
<wsa:Address>wl.skype.com</wsa:Address>
621+
</wsa:EndpointReference>
622+
</wsp:AppliesTo>
623+
<wsse:PolicyReference URI='MBI_SSL'></wsse:PolicyReference>
624+
</wst:RequestSecurityToken>
625+
</ps:RequestMultipleSecurityTokens>
626+
</Body>
627+
</Envelope>
628+
"""
629+
630+
@staticmethod
631+
def encode(value):
632+
return value.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
633+
634+
def getSecToken(self, user, pwd):
635+
loginResp = self.conn("POST", "{0}/RST.srf".format(SkypeConnection.API_MSACC),
636+
data=self.template.format(self.encode(user), self.encode(pwd)))
637+
loginData = ElementTree.fromstring(loginResp.text)
638+
token = None
639+
for node in loginData.iter():
640+
tag = node.tag.split("}", 1)[-1]
641+
if tag == "Fault":
642+
code = msg = None
643+
for fnode in node:
644+
ftag = fnode.tag.split("}", 1)[-1]
645+
if ftag == "faultcode":
646+
code = fnode.text
647+
elif ftag == "faultstring":
648+
msg = fnode.text
649+
raise SkypeAuthException("{} - {}".format(code, msg), loginResp)
650+
elif tag == "BinarySecurityToken":
651+
token = node.text
652+
if not token:
653+
raise SkypeAuthException("Couldn't retrieve security token from login response", loginResp)
654+
return token
655+
656+
def exchangeToken(self, token):
657+
edgeResp = self.conn("POST", SkypeConnection.API_EDGE,
658+
data={"partner": 999, "access_token": token, "scopes": "client"})
659+
try:
660+
edgeData = edgeResp.json()
661+
except ValueError:
662+
raise SkypeAuthException("Couldn't parse edge response body", edgeResp)
663+
if "skypetoken" in edgeData:
664+
token = edgeData["skypetoken"]
665+
expiry = None
666+
if "expiresIn" in edgeData:
667+
expiry = datetime.fromtimestamp(int(time.time()) + int(edgeData["expiresIn"]))
668+
return (token, expiry)
669+
elif "status" in edgeData:
670+
status = edgeData["status"]
671+
raise SkypeAuthException("{} - {}".format(status.get("code"), status.get("text")), edgeResp)
672+
else:
673+
raise SkypeAuthException("Couldn't retrieve token from edge response", edgeResp)
674+
675+
def auth(self, user, pwd):
676+
token = self.getSecToken(user, pwd)
677+
return self.exchangeToken(token)
678+
679+
595680
class SkypeGuestAuthProvider(SkypeAuthProvider):
596681
"""
597682
An authentication provider that connects and joins a public conversation via a join URL.

0 commit comments

Comments
 (0)