summaryrefslogtreecommitdiffabout
path: root/include/opkele/oauth/consumer.h
blob: 3ad18a2761aa7476393e7d1347dbfd2f03104aea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
#ifndef __OPKELE_OAUTH_CONSUMER_H
#define __OPKELE_OAUTH_CONSUMER_H

#include <string>
#include <opkele/types.h>
#include <opkele/oauth.h>
#include <opkele/curl.h>

namespace opkele {
    /**
     * @brief OAuth support namespace
     */
    namespace oauth {
	using std::string;

	/**
	 * oauth parameter passing method
	 */
	enum oauth_method_t {
	    /**
	     * via WWW-Authenticate header
	     */
	    oauth_auth_header,
	    /**
	     * via POST body
	     */
	    oauth_post_body,
	    /**
	     * via GET query string
	     */
	    oauth_url_query,
	    /**
	     * default method
	     */
	    oauth_method_default = oauth_auth_header
	};

	/**
	 * Service endpoint description
	 */
	struct service_endpoint_t {
	    /**
	     * endpoint URI
	     */
	    string url;
	    /**
	     * signature method
	     */
	    string signature_method;
	    /**
	     * OAuth parameter passing method
	     */
	    oauth_method_t oauth_method;

	    service_endpoint_t() : oauth_method(oauth_method_default) { }
	    /**
	     * @param u endpoint URI
	     * @param sm signature method
	     * @param om OAuth parameter passing method
	     */
	    service_endpoint_t(const string& u,const string& sm,oauth_method_t om=oauth_method_default)
		: url(u), signature_method(sm), oauth_method(om) { }
	};

	/**
	 * Base class for OAuth provider endpoints description
	 */
	class basic_provider_endpoints {
	    public:

		virtual ~basic_provider_endpoints() { }

		/**
		 * Retrieve endpoint for obtaining an unauthorized request token
		 * @return service endpoint description
		 */
		virtual const service_endpoint_t& get_request_token_endpoint() const = 0;
		/**
		 * Retrieve endpoint for user authorization
		 * @return service endpoint description
		 */
		virtual const service_endpoint_t& get_authorize_user_endpoint() const = 0;
		/**
		 * Retrieve endpoint for obtaining an access token from the
		 * authorized request token
		 * @return service endpoint description
		 */
		virtual const service_endpoint_t& get_access_token_endpoint() const = 0;

		/**
		 * Make up an endpoint description give an URI
		 * @param sep reference to the service endpoint description object to fill in
		 * @param url endpoint URL
		 * @return reference to sep
		 */
		virtual service_endpoint_t& get_url_endpoint(service_endpoint_t& sep,
			const string& url) const = 0;
	};

	/**
	 * HTTP request information
	 */
	struct http_request_t {
	    /**
	     * WWW-Authenticate header
	     */
	    string authorize_header;
	    /**
	     * HTTP method
	     */
	    string method;
	    /**
	     * Target URL
	     */
	    string url;
	    /**
	     * POST body
	     */
	    string body;

	    /**
	     * curl-ready headers
	     */
	    util::curl_slist_t _curl_headers_list;

	    /**
	     * @param m HTTP method
	     * @param u target URL
	     */
	    http_request_t(const string& m,const string& u)
		: method(m), url(u) { }

	    /**
	     * Set relevant curl handle options
	     */
	    void setup_curl(CURL *curl);
	};

	/**
	 * OAuth consumer base class
	 */
	class basic_consumer {
	    public:
		/**
		 * Consumer token
		 */
		token_t consumer_token;

		/**
		 * @param ct consumer token
		 */
		basic_consumer(const token_t& ct)
		    : consumer_token(ct) { }
		virtual ~basic_consumer() { }

		/**
		 * Retrieve reference to the provider endpoints description object
		 * @return reference to the provider endpoints description object
		 */
		virtual const basic_provider_endpoints& get_endpoints() const = 0;
		/**
		 * Allocate nonce
		 * @param ts request timestamp
		 * @return nonce string
		 */
		virtual const string allocate_nonce(time_t ts) = 0;

		/**
		 * Obtain an unauthorized request token
		 * @return request token
		 */
		token_t get_request_token();
		/**
		 * Retrieve the user authorization URL
		 * @param rt unauthorized request token
		 * @param callback callback URL to be passed to oauth provider
		 * to redirect user to upon authorization
		 * @return user authorization URL
		 */
		const string get_authorize_url(const token_t& rt,const string& callback="");
		/**
		 * Trade an authorized request token for an access token
		 * @param rt authorized request token
		 * @return access token
		 */
		token_t get_access_token(const token_t& rt);

		/**
		 * Prepare http request parameters
		 * @param req request description to fill in
		 * @param qf query string parameters
		 * @param pf post body parameters
		 * @param om OAuth method
		 * @param sm signature method
		 * @param t pointer to the token to use to sign request, if any.
		 * @param realm authorization realm
		 * @return reference to req
		 */
		http_request_t& prepare_request(
			http_request_t& req,
			const basic_fields& qf,const basic_fields& pf,
			oauth_method_t om,const string& sm,
			const token_t *t=0,const string& realm="");
		/**
		 * Prepare http request parameters
		 * @param req request description to fill in
		 * @param qf query string parameters
		 * @param pf post body parameters
		 * @param sep service endpoint description
		 * @param t pointer to the token to use to sign request, if any.
		 * @param realm authorization realm
		 * @return reference to req
		 */
		http_request_t& prepare_request(
			http_request_t& req,
			const basic_fields& qf,const basic_fields& pf,
			const service_endpoint_t& sep,
			const token_t *t=0,const string& realm="");
		/**
		 * Prepare http request parameters
		 * @param req request description to fill in
		 * @param qf query string parameters
		 * @param pf post body parameters
		 * @param t pointer to the token to use to sign request, if any.
		 * @param realm authorization realm
		 * @return reference to req
		 */
		http_request_t& prepare_request(
			http_request_t& req,
			const basic_fields& qf,const basic_fields& pf,
			const token_t *t=0,const string& realm="");

		/**
		 * Calculate request signature
		 * @param method http method
		 * @param url the url being invoked
		 * @param fields all request fields (query string, auth header,
		 * post body)
		 * @param rt pointer to the request token to be used for
		 * signing, if any.
		 */
		const string signature(
			const string& method,
			const string& url,
			const basic_fields& fields,
			const token_t* rt=0);

		/**
		 * Acquire token from an OAuth provider
		 * @param sep service endpoint description
		 * @param rt pointer to the request token to use for signing,
		 * if any
		 * @return the acquired token
		 */
		token_t acquire_token(
			const service_endpoint_t& sep,
			const token_t* rt=0);
	};

	class simple_provider_endpoints : public basic_provider_endpoints {
	    public:
		service_endpoint_t sep_request_token;
		service_endpoint_t sep_authorize_user;
		service_endpoint_t sep_access_token;
		service_endpoint_t sep_generic;

		/**
		 * @param rt request token endpoint URL
		 * @param au user authorization endpoint URL
		 * @param at access token endpoint URL
		 * @param sm signature method
		 * @param ams authentication method for service endpoints
		 * @param amr authentication method for resource access
		 */
		simple_provider_endpoints(
			const string& rt,const string& au,const string& at,
			const string& sm,
			oauth_method_t ams=oauth_post_body,
			oauth_method_t amr=oauth_auth_header )
		    : sep_request_token(rt,sm,ams),
		    sep_authorize_user(au,sm,oauth_url_query),
		    sep_access_token(at,sm,ams),
		    sep_generic("",sm,amr) { }

		const service_endpoint_t& get_request_token_endpoint() const;
		const service_endpoint_t& get_authorize_user_endpoint() const;
		const service_endpoint_t& get_access_token_endpoint() const;
		service_endpoint_t& get_url_endpoint(service_endpoint_t& sep,
			const string& url) const;
	};

	class simple_consumer : public basic_consumer {
	    public:
		simple_provider_endpoints peps;

		/**
		 * @param eps provider endpoints
		 * @param ct consumer token
		 * @see simple_provider_endpoints
		 * @see token_t
		 */
		simple_consumer(const simple_provider_endpoints& eps,
			const token_t& ct)
		    : basic_consumer(ct), peps(eps) { }

		const basic_provider_endpoints& get_endpoints() const;
		const string allocate_nonce(time_t ts);
	};

    }
}

#endif /* __OPKELE_OAUTH_CONSUMER_H */