@@ -37,53 +37,198 @@ namespace http
3737{
3838namespace client
3939{
40+ class http_client_config ;
41+ namespace experimental
42+ {
43+
44+
45+ // / <summary>
46+ // / Exception type for OAuth 2.0 errors.
47+ // / </summary>
48+ class oauth2_exception : public std ::exception
49+ {
50+ public:
51+ oauth2_exception (utility::string_t msg) : m_msg(utility::conversions::to_utf8string(std::move(msg))) {}
52+ ~oauth2_exception () _noexcept {}
53+ const char * what () const _noexcept { return m_msg.c_str (); }
54+
55+ private:
56+ std::string m_msg;
57+ };
4058
4159
4260// / <summary>
43- // / Oauth2 configuration.
61+ // / OAuth 2.0 configuration.
62+ // /
63+ // / Encapsulates functionality for:
64+ // / - Authenticating requests with an access token.
65+ // / - Performing the OAuth 2.0 authorization code grant authorization flow.
66+ // / See: http://tools.ietf.org/html/rfc6749#section-4.1
67+ // /
68+ // / Usage for authorization:
69+ // / 1. Set service and client/app parameters:
70+ // / - Client/app key & secret (as provided by the service).
71+ // / - The service authorization endpoint and token endpoint.
72+ // / - Your client/app redirect URI.
73+ // / - Set if bearer token is passed in query or header field (default: header).
74+ // / See: http://tools.ietf.org/html/rfc6750#section-2
75+ // / - If the service uses "non-standard" access token key, set it also (default: "access_token").
76+ // / 2. Open web browser with URI from build_authorization_uri().
77+ // / - The passed state string should be unique for this authorization session.
78+ // / 3. In the web browser, the resource owner clicks "Yes" to authorize your client/app.
79+ // / 4. To signal authorization, web browser is redirected to redirect_uri().
80+ // / 5. The redirect contains the authorization code and the state string.
81+ // / 6. Check the state string equals the one in step 2.
82+ // / 7. Pass the authorization code to fetch_token() to create a token fetch task.
83+ // /
84+ // / Usage for issuing authenticated requests:
85+ // / 1. Obtain token. (Perform authorization as above or get token otherwise.)
86+ // / 2. Use http_client_config::set_oauth2() to set configuration, and construct http_client using it.
87+ // / 3. All requests issued with that http_client will be OAuth 2.0 -authenticated.
88+ // /
4489// / </summary>
45- struct oauth2_config
90+ class oauth2_config
4691{
47- oauth2_config (utility::string_t token) : m_token(std::move(token)) {}
92+ public:
93+ oauth2_config (utility::string_t client_key, utility::string_t client_secret,
94+ utility::string_t auth_endpoint, utility::string_t token_endpoint,
95+ utility::string_t redirect_uri) :
96+ m_client_key (client_key),
97+ m_client_secret (client_secret),
98+ m_auth_endpoint (auth_endpoint),
99+ m_token_endpoint (token_endpoint),
100+ m_redirect_uri (redirect_uri),
101+ m_bearer_auth (true ),
102+ m_http_basic_auth (true ),
103+ m_access_token_key (_XPLATSTR(" access_token" ))
104+ {
105+ }
106+
107+ oauth2_config (utility::string_t token) :
108+ m_token (std::move(token)),
109+ m_bearer_auth (true ),
110+ m_http_basic_auth (true ),
111+ m_access_token_key (_XPLATSTR(" access_token" ))
112+ {
113+ }
114+
115+ // / <summary>
116+ // / Builds an authorization URI to be loaded in the web browser.
117+ // / The URI is built with auth_endpoint() as basis.
118+ // / </summary>
119+ _ASYNCRTIMP utility::string_t build_authorization_uri () const ;
120+
121+ // / <summary>
122+ // / Parses authorization code from the redirected URI when resource owner
123+ // / has accepted the authorization.
124+ // / Redirected URI must satisfy the following (otherwise an exception is thrown):
125+ // / - Must contain both 'code' and 'state' query parameters.
126+ // / - The 'state' parameter must be equal to state().
127+ // / </summary>
128+ _ASYNCRTIMP utility::string_t parse_code_from_redirected_uri (uri redirected_uri) const ;
129+
130+ // / <summary>
131+ // / Creates a task to fetch token from the token endpoint.
132+ // / The task creates a request to the token_endpoint() which is used exchange an authorization code to an access token.
133+ // / If successful, resulting token is set as active via set_token().
134+ // / </summary>
135+ // / <param name="authorization_code">Code received via redirect upon successful authorization.</param>
136+ _ASYNCRTIMP pplx::task<void > fetch_token (utility::string_t authorization_code);
137+
138+ bool is_enabled () const { return !m_token.empty (); }
139+
140+ const utility::string_t & client_key () const { return m_client_key; }
141+ void set_client_key (utility::string_t client_key) { m_client_key = std::move (client_key); }
142+
143+ const utility::string_t & client_secret () const { return m_client_secret; }
144+ void set_client_secret (utility::string_t client_secret) { m_client_secret = std::move (client_secret); }
145+
146+ const utility::string_t & auth_endpoint () const { return m_auth_endpoint; }
147+ void set_auth_endpoint (utility::string_t auth_endpoint) { m_auth_endpoint = std::move (auth_endpoint); }
148+
149+ const utility::string_t & token_endpoint () const { return m_token_endpoint; }
150+ void set_token_endpoint (utility::string_t token_endpoint) { m_token_endpoint = std::move (token_endpoint); }
151+
152+ const utility::string_t & redirect_uri () const { return m_redirect_uri; }
153+ void set_redirect_uri (utility::string_t redirect_uri) { m_redirect_uri = std::move (redirect_uri); }
154+
155+ const utility::string_t & scope () const { return m_scope; }
156+ void set_scope (utility::string_t scope) { m_scope = std::move (scope); }
157+
158+ const utility::string_t & state () const { return m_state; }
159+ // / <summary>
160+ // / State string should be unique for each authorization session.
161+ // / This state string should be returned by the authorization server on redirect
162+ // / </summary>
163+ void set_state (utility::string_t state) { m_state = std::move (state); }
48164
49165 const utility::string_t & token () const { return m_token; }
50166 void set_token (utility::string_t token) { m_token = std::move (token); }
51167
52- bool is_enabled () const { return !m_token.empty (); }
168+ bool bearer_auth () const { return m_bearer_auth; }
169+ // / <summary>
170+ // / Bearer token passing method. This must be selected based on what the service accepts.
171+ // / True means token is passed in the request header. (http://tools.ietf.org/html/rfc6750#section-2.1)
172+ // / False means token in passed in the query parameters. (http://tools.ietf.org/html/rfc6750#section-2.3)
173+ // / Default: True.
174+ // / </summary>
175+ void set_bearer_auth (bool enable) { m_bearer_auth = std::move (enable); }
176+
177+ bool http_basic_auth () const { return m_http_basic_auth; }
178+ // / <summary>
179+ // / Token endpoint authorization method. This must be selected based on what the service accepts.
180+ // / True means HTTP Basic is used for authentication.
181+ // / False means client key & secret are passed in the HTTP request body.
182+ // / Default: True.
183+ // / </summary>
184+ void set_http_basic_auth (bool enable) { m_http_basic_auth = std::move (enable); }
185+
186+ const utility::string_t & access_token_key () const { return m_access_token_key; }
187+ // / <summary>
188+ // / Set custom access token key field in the case service requires a "non-standard" key.
189+ // / Default access token key is "access_token".
190+ // / </summary>
191+ void set_access_token_key (utility::string_t access_token_key) { m_access_token_key = std::move (access_token_key); }
53192
54193private:
55- friend class http_client_config ;
194+ friend class web ::http::client:: http_client_config;
56195 oauth2_config () {}
57196
197+ utility::string_t m_client_key;
198+ utility::string_t m_client_secret;
199+ utility::string_t m_auth_endpoint;
200+ utility::string_t m_token_endpoint;
201+ utility::string_t m_redirect_uri;
202+ utility::string_t m_scope;
203+ utility::string_t m_state;
204+
205+ bool m_bearer_auth;
206+ bool m_http_basic_auth;
207+ utility::string_t m_access_token_key;
208+
58209 utility::string_t m_token;
59210};
60211
61212
62213// / <summary>
63- // / Oauth2 handler. Specialization of http_pipeline_stage.
214+ // / OAuth 2.0 handler.
215+ // / Specialization of http_pipeline_stage to perform OAuth 2.0 request authentication.
64216// / </summary>
65217class oauth2_handler : public http_pipeline_stage
66218{
67219public:
68- oauth2_handler (oauth2_config config ) : m_config(std::move(config )) {}
220+ oauth2_handler (oauth2_config cfg ) : m_config(std::move(cfg )) {}
69221
70- void set_config ( oauth2_config config) { m_config = std::move (config) ; }
71- const oauth2_config& get_config () const { return m_config; }
222+ const oauth2_config& config () const { return m_config ; }
223+ void set_config ( oauth2_config cfg) { m_config = std::move (cfg) ; }
72224
73- virtual pplx::task<http_response> propagate (http_request request) override
74- {
75- if (m_config.is_enabled ())
76- {
77- request.headers ().add (_XPLATSTR (" Authorization" ), _XPLATSTR (" Bearer " ) + m_config.token ());
78- }
79- return next_stage ()->propagate (request);
80- }
225+ _ASYNCRTIMP virtual pplx::task<http_response> propagate (http_request request) override ;
81226
82227private:
83228 oauth2_config m_config;
84229};
85230
86231
87- }}} // namespace web::http::client
232+ }}}} // namespace web::http::client::experimental
88233
89234#endif /* _CASA_OAUTH2_HANDLER_H */
0 commit comments