Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/oauthlib/oauth1/rfc5849/endpoints/resource.py: 17%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

42 statements  

1# -*- coding: utf-8 -*- 

2""" 

3oauthlib.oauth1.rfc5849.endpoints.resource 

4~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

5 

6This module is an implementation of the resource protection provider logic of 

7OAuth 1.0 RFC 5849. 

8""" 

9import logging 

10 

11from .. import errors 

12from .base import BaseEndpoint 

13 

14log = logging.getLogger(__name__) 

15 

16 

17class ResourceEndpoint(BaseEndpoint): 

18 

19 """An endpoint responsible for protecting resources. 

20 

21 Typical use is to instantiate with a request validator and invoke the 

22 ``validate_protected_resource_request`` in a decorator around a view 

23 function. If the request is valid, invoke and return the response of the 

24 view. If invalid create and return an error response directly from the 

25 decorator. 

26 

27 See :doc:`/oauth1/validator` for details on which validator methods to implement 

28 for this endpoint. 

29 

30 An example decorator:: 

31 

32 from functools import wraps 

33 from your_validator import your_validator 

34 from oauthlib.oauth1 import ResourceEndpoint 

35 endpoint = ResourceEndpoint(your_validator) 

36 

37 def require_oauth(realms=None): 

38 def decorator(f): 

39 @wraps(f) 

40 def wrapper(request, *args, **kwargs): 

41 v, r = provider.validate_protected_resource_request( 

42 request.url, 

43 http_method=request.method, 

44 body=request.data, 

45 headers=request.headers, 

46 realms=realms or []) 

47 if v: 

48 return f(*args, **kwargs) 

49 else: 

50 return abort(403) 

51 """ 

52 

53 def validate_protected_resource_request(self, uri, http_method='GET', 

54 body=None, headers=None, realms=None): 

55 """Create a request token response, with a new request token if valid. 

56 

57 :param uri: The full URI of the token request. 

58 :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc. 

59 :param body: The request body as a string. 

60 :param headers: The request headers as a dict. 

61 :param realms: A list of realms the resource is protected under. 

62 This will be supplied to the ``validate_realms`` 

63 method of the request validator. 

64 :returns: A tuple of 2 elements. 

65 1. True if valid, False otherwise. 

66 2. An oauthlib.common.Request object. 

67 """ 

68 try: 

69 request = self._create_request(uri, http_method, body, headers) 

70 except errors.OAuth1Error: 

71 return False, None 

72 

73 try: 

74 self._check_transport_security(request) 

75 self._check_mandatory_parameters(request) 

76 except errors.OAuth1Error: 

77 return False, request 

78 

79 if not request.resource_owner_key: 

80 return False, request 

81 

82 if not self.request_validator.check_access_token( 

83 request.resource_owner_key): 

84 return False, request 

85 

86 if not self.request_validator.validate_timestamp_and_nonce( 

87 request.client_key, request.timestamp, request.nonce, request, 

88 access_token=request.resource_owner_key): 

89 return False, request 

90 

91 # The server SHOULD return a 401 (Unauthorized) status code when 

92 # receiving a request with invalid client credentials. 

93 # Note: This is postponed in order to avoid timing attacks, instead 

94 # a dummy client is assigned and used to maintain near constant 

95 # time request verification. 

96 # 

97 # Note that early exit would enable client enumeration 

98 valid_client = self.request_validator.validate_client_key( 

99 request.client_key, request) 

100 if not valid_client: 

101 request.client_key = self.request_validator.dummy_client 

102 

103 # The server SHOULD return a 401 (Unauthorized) status code when 

104 # receiving a request with invalid or expired token. 

105 # Note: This is postponed in order to avoid timing attacks, instead 

106 # a dummy token is assigned and used to maintain near constant 

107 # time request verification. 

108 # 

109 # Note that early exit would enable resource owner enumeration 

110 valid_resource_owner = self.request_validator.validate_access_token( 

111 request.client_key, request.resource_owner_key, request) 

112 if not valid_resource_owner: 

113 request.resource_owner_key = self.request_validator.dummy_access_token 

114 

115 # Note that `realm`_ is only used in authorization headers and how 

116 # it should be interpreted is not included in the OAuth spec. 

117 # However they could be seen as a scope or realm to which the 

118 # client has access and as such every client should be checked 

119 # to ensure it is authorized access to that scope or realm. 

120 # .. _`realm`: https://tools.ietf.org/html/rfc2617#section-1.2 

121 # 

122 # Note that early exit would enable client realm access enumeration. 

123 # 

124 # The require_realm indicates this is the first step in the OAuth 

125 # workflow where a client requests access to a specific realm. 

126 # This first step (obtaining request token) need not require a realm 

127 # and can then be identified by checking the require_resource_owner 

128 # flag and absence of realm. 

129 # 

130 # Clients obtaining an access token will not supply a realm and it will 

131 # not be checked. Instead the previously requested realm should be 

132 # transferred from the request token to the access token. 

133 # 

134 # Access to protected resources will always validate the realm but note 

135 # that the realm is now tied to the access token and not provided by 

136 # the client. 

137 valid_realm = self.request_validator.validate_realms(request.client_key, 

138 request.resource_owner_key, request, uri=request.uri, 

139 realms=realms) 

140 

141 valid_signature = self._check_signature(request) 

142 

143 # log the results to the validator_log 

144 # this lets us handle internal reporting and analysis 

145 request.validator_log['client'] = valid_client 

146 request.validator_log['resource_owner'] = valid_resource_owner 

147 request.validator_log['realm'] = valid_realm 

148 request.validator_log['signature'] = valid_signature 

149 

150 # We delay checking validity until the very end, using dummy values for 

151 # calculations and fetching secrets/keys to ensure the flow of every 

152 # request remains almost identical regardless of whether valid values 

153 # have been supplied. This ensures near constant time execution and 

154 # prevents malicious users from guessing sensitive information 

155 v = all((valid_client, valid_resource_owner, valid_realm, 

156 valid_signature)) 

157 if not v: 

158 log.info("[Failure] request verification failed.") 

159 log.info("Valid client: %s", valid_client) 

160 log.info("Valid token: %s", valid_resource_owner) 

161 log.info("Valid realm: %s", valid_realm) 

162 log.info("Valid signature: %s", valid_signature) 

163 return v, request