1# -*- coding: utf-8 -*-
2"""
3oauthlib.oauth1.rfc5849.endpoints.authorization
4~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6This module is an implementation of various logic needed
7for signing and checking OAuth 1.0 RFC 5849 requests.
8"""
9from urllib.parse import urlencode
10
11from oauthlib.common import add_params_to_uri
12
13from .. import errors
14from .base import BaseEndpoint
15
16
17class AuthorizationEndpoint(BaseEndpoint):
18
19 """An endpoint responsible for letting authenticated users authorize access
20 to their protected resources to a client.
21
22 Typical use would be to have two views, one for displaying the authorization
23 form and one to process said form on submission.
24
25 The first view will want to utilize ``get_realms_and_credentials`` to fetch
26 requested realms and useful client credentials, such as name and
27 description, to be used when creating the authorization form.
28
29 During form processing you can use ``create_authorization_response`` to
30 validate the request, create a verifier as well as prepare the final
31 redirection URI used to send the user back to the client.
32
33 See :doc:`/oauth1/validator` for details on which validator methods to implement
34 for this endpoint.
35 """
36
37 def create_verifier(self, request, credentials):
38 """Create and save a new request token.
39
40 :param request: OAuthlib request.
41 :type request: oauthlib.common.Request
42 :param credentials: A dict of extra token credentials.
43 :returns: The verifier as a dict.
44 """
45 verifier = {
46 'oauth_token': request.resource_owner_key,
47 'oauth_verifier': self.token_generator(),
48 }
49 verifier.update(credentials)
50 self.request_validator.save_verifier(
51 request.resource_owner_key, verifier, request)
52 return verifier
53
54 def create_authorization_response(self, uri, http_method='GET', body=None,
55 headers=None, realms=None, credentials=None):
56 """Create an authorization response, with a new request token if valid.
57
58 :param uri: The full URI of the token request.
59 :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
60 :param body: The request body as a string.
61 :param headers: The request headers as a dict.
62 :param credentials: A list of credentials to include in the verifier.
63 :returns: A tuple of 3 elements.
64 1. A dict of headers to set on the response.
65 2. The response body as a string.
66 3. The response status code as an integer.
67
68 If the callback URI tied to the current token is "oob", a response with
69 a 200 status code will be returned. In this case, it may be desirable to
70 modify the response to better display the verifier to the client.
71
72 An example of an authorization request::
73
74 >>> from your_validator import your_validator
75 >>> from oauthlib.oauth1 import AuthorizationEndpoint
76 >>> endpoint = AuthorizationEndpoint(your_validator)
77 >>> h, b, s = endpoint.create_authorization_response(
78 ... 'https://your.provider/authorize?oauth_token=...',
79 ... credentials={
80 ... 'extra': 'argument',
81 ... })
82 >>> h
83 {'Location': 'https://the.client/callback?oauth_verifier=...&extra=argument'}
84 >>> b
85 None
86 >>> s
87 302
88
89 An example of a request with an "oob" callback::
90
91 >>> from your_validator import your_validator
92 >>> from oauthlib.oauth1 import AuthorizationEndpoint
93 >>> endpoint = AuthorizationEndpoint(your_validator)
94 >>> h, b, s = endpoint.create_authorization_response(
95 ... 'https://your.provider/authorize?foo=bar',
96 ... credentials={
97 ... 'extra': 'argument',
98 ... })
99 >>> h
100 {'Content-Type': 'application/x-www-form-urlencoded'}
101 >>> b
102 'oauth_verifier=...&extra=argument'
103 >>> s
104 200
105 """
106 request = self._create_request(uri, http_method=http_method, body=body,
107 headers=headers)
108
109 if not request.resource_owner_key:
110 raise errors.InvalidRequestError(
111 'Missing mandatory parameter oauth_token.')
112 if not self.request_validator.verify_request_token(
113 request.resource_owner_key, request):
114 raise errors.InvalidClientError()
115
116 request.realms = realms
117 if (request.realms and not self.request_validator.verify_realms(
118 request.resource_owner_key, request.realms, request)):
119 raise errors.InvalidRequestError(
120 description=('User granted access to realms outside of '
121 'what the client may request.'))
122
123 verifier = self.create_verifier(request, credentials or {})
124 redirect_uri = self.request_validator.get_redirect_uri(
125 request.resource_owner_key, request)
126 if redirect_uri == 'oob':
127 response_headers = {
128 'Content-Type': 'application/x-www-form-urlencoded'}
129 response_body = urlencode(verifier)
130 return response_headers, response_body, 200
131 else:
132 populated_redirect = add_params_to_uri(
133 redirect_uri, verifier.items())
134 return {'Location': populated_redirect}, None, 302
135
136 def get_realms_and_credentials(self, uri, http_method='GET', body=None,
137 headers=None):
138 """Fetch realms and credentials for the presented request token.
139
140 :param uri: The full URI of the token request.
141 :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
142 :param body: The request body as a string.
143 :param headers: The request headers as a dict.
144 :returns: A tuple of 2 elements.
145 1. A list of request realms.
146 2. A dict of credentials which may be useful in creating the
147 authorization form.
148 """
149 request = self._create_request(uri, http_method=http_method, body=body,
150 headers=headers)
151
152 if not self.request_validator.verify_request_token(
153 request.resource_owner_key, request):
154 raise errors.InvalidClientError()
155
156 realms = self.request_validator.get_realms(
157 request.resource_owner_key, request)
158 return realms, {'resource_owner_key': request.resource_owner_key}