oauth.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. # GNU MediaGoblin -- federated, autonomous media hosting
  2. # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU Affero General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU Affero General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU Affero General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. import datetime
  17. from oauthlib.common import Request
  18. from oauthlib.oauth1 import RequestValidator
  19. from mediagoblin import oauth
  20. from mediagoblin.db.models import NonceTimestamp, Client, RequestToken, AccessToken
  21. class GMGRequestValidator(RequestValidator):
  22. enforce_ssl = False
  23. def __init__(self, data=None, *args, **kwargs):
  24. self.POST = data
  25. super(GMGRequestValidator, self).__init__(*args, **kwargs)
  26. def check_nonce(self, nonce):
  27. """
  28. This checks that the nonce given is a valid nonce
  29. RequestValidator.check_nonce checks that it's between a maximum and
  30. minimum length which, not only does pump.io not do this from what
  31. I can see but there is nothing in rfc5849 which suggests a maximum or
  32. minium length should be required so I'm removing that check
  33. """
  34. # Check the nonce only contains a subset of the safe characters.
  35. return set(nonce) <= self.safe_characters
  36. def save_request_token(self, token, request):
  37. """ Saves request token in db """
  38. client_id = self.POST[u"oauth_consumer_key"]
  39. request_token = RequestToken(
  40. token=token["oauth_token"],
  41. secret=token["oauth_token_secret"],
  42. )
  43. request_token.client = client_id
  44. if u"oauth_callback" in self.POST:
  45. request_token.callback = self.POST[u"oauth_callback"]
  46. request_token.save()
  47. def save_verifier(self, token, verifier, request):
  48. """ Saves the oauth request verifier """
  49. request_token = RequestToken.query.filter_by(token=token).first()
  50. request_token.verifier = verifier["oauth_verifier"]
  51. request_token.save()
  52. def save_access_token(self, token, request):
  53. """ Saves access token in db """
  54. access_token = AccessToken(
  55. token=token["oauth_token"],
  56. secret=token["oauth_token_secret"],
  57. )
  58. access_token.request_token = request.oauth_token
  59. request_token = RequestToken.query.filter_by(token=request.oauth_token).first()
  60. access_token.actor = request_token.actor
  61. access_token.save()
  62. def get_realms(*args, **kwargs):
  63. """ Currently a stub - called when making AccessTokens """
  64. return list()
  65. def validate_timestamp_and_nonce(self, client_key, timestamp,
  66. nonce, request, request_token=None,
  67. access_token=None):
  68. # RFC5849 (OAuth 1.0) section 3.3 says the timestamp is going
  69. # to be seconds after the epoch, we need to convert for postgres
  70. try:
  71. timestamp = datetime.datetime.fromtimestamp(float(timestamp))
  72. except ValueError:
  73. # Well, the client must have passed up something ridiculous
  74. return False
  75. nc = NonceTimestamp.query.filter_by(timestamp=timestamp, nonce=nonce)
  76. nc = nc.first()
  77. if nc is None:
  78. return True
  79. return False
  80. def validate_client_key(self, client_key, request):
  81. """ Verifies client exists with id of client_key """
  82. client_query = Client.query.filter(Client.id != oauth.DUMMY_CLIENT_ID)
  83. client = client_query.filter_by(id=client_key).first()
  84. if client is None:
  85. return False
  86. return True
  87. def validate_verifier(self, token, verifier):
  88. """ Verifies the verifier token is correct. """
  89. request_token = RequestToken.query.filter_by(token=token).first()
  90. if request_token is None:
  91. return False
  92. if request_token.verifier != verifier:
  93. return False
  94. return True
  95. def validate_access_token(self, client_key, token, request):
  96. """ Verifies token exists for client with id of client_key """
  97. # Get the client for the request
  98. client_query = Client.query.filter(Client.id != oauth.DUMMY_CLIENT_ID)
  99. client = client_query.filter_by(id=client_key).first()
  100. # If the client is invalid then it's invalid
  101. if client is None:
  102. return False
  103. # Look up the AccessToken
  104. access_token_query = AccessToken.query.filter(
  105. AccessToken.token != oauth.DUMMY_ACCESS_TOKEN
  106. )
  107. access_token = access_token_query.filter_by(token=token).first()
  108. # If there isn't one - we can't validate.
  109. if access_token is None:
  110. return False
  111. # Check that the client matches the on
  112. request_token_query = RequestToken.query.filter(
  113. RequestToken.token != oauth.DUMMY_REQUEST_TOKEN,
  114. RequestToken.token == access_token.request_token
  115. )
  116. request_token = request_token_query.first()
  117. if client.id != request_token.client:
  118. return False
  119. return True
  120. def validate_realms(self, *args, **kwargs):
  121. """ Would validate reals however not using these yet. """
  122. return True # implement when realms are implemented
  123. def get_client_secret(self, client_key, request):
  124. """ Retrives a client secret with from a client with an id of client_key """
  125. client = Client.query.filter_by(id=client_key).first()
  126. return client.secret
  127. def get_access_token_secret(self, client_key, token, request):
  128. access_token = AccessToken.query.filter_by(token=token).first()
  129. return access_token.secret
  130. @property
  131. def dummy_client(self):
  132. return oauth.DUMMY_CLIENT_ID
  133. @property
  134. def dummy_request_token(self):
  135. return oauth.DUMMY_REQUEST_TOKEN
  136. @property
  137. def dummy_access_token(self):
  138. return oauth.DUMMY_ACCESS_TOKEN
  139. class GMGRequest(Request):
  140. """
  141. Fills in data to produce a oauth.common.Request object from a
  142. werkzeug Request object
  143. """
  144. def __init__(self, request, *args, **kwargs):
  145. """
  146. :param request: werkzeug request object
  147. any extra params are passed to oauthlib.common.Request object
  148. """
  149. kwargs["uri"] = kwargs.get("uri", request.url)
  150. kwargs["http_method"] = kwargs.get("http_method", request.method)
  151. kwargs["body"] = kwargs.get("body", request.data)
  152. kwargs["headers"] = kwargs.get("headers", dict(request.headers))
  153. super(GMGRequest, self).__init__(*args, **kwargs)