summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/Makefile.am4
-rw-r--r--include/opkele/oauth.h22
-rw-r--r--include/opkele/oauth/consumer.h135
-rw-r--r--include/opkele/types.h18
-rw-r--r--lib/Makefile.am9
-rw-r--r--lib/fields.cc59
-rw-r--r--lib/oauth-consumer.cc280
-rw-r--r--test/.gitignore1
-rw-r--r--test/Makefile.am20
-rw-r--r--test/test-oauth-consumer.cc69
10 files changed, 601 insertions, 16 deletions
diff --git a/include/Makefile.am b/include/Makefile.am
index f842bb9..2ae510d 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -20,11 +20,13 @@ nobase_include_HEADERS = \
20 opkele/iterator.h \ 20 opkele/iterator.h \
21 opkele/basic_op.h opkele/verify_op.h \ 21 opkele/basic_op.h opkele/verify_op.h \
22 opkele/util.h \ 22 opkele/util.h \
23 opkele/oauth.h opkele/oauth/consumer.h \
24 opkele/curl.h \
23 ${NODIST_HEADERS_} 25 ${NODIST_HEADERS_}
24 26
25noinst_HEADERS = \ 27noinst_HEADERS = \
26 opkele/data.h \ 28 opkele/data.h \
27 opkele/curl.h opkele/expat.h opkele/tidy.h \ 29 opkele/expat.h opkele/tidy.h \
28 opkele/util-internal.h \ 30 opkele/util-internal.h \
29 opkele/debug.h \ 31 opkele/debug.h \
30 opkele/discovery.h 32 opkele/discovery.h
diff --git a/include/opkele/oauth.h b/include/opkele/oauth.h
new file mode 100644
index 0000000..14d0586
--- a/dev/null
+++ b/include/opkele/oauth.h
@@ -0,0 +1,22 @@
1#ifndef __OPKELE_OAUTH_H
2#define __OPKELE_OAUTH_H
3
4#include <string>
5
6namespace opkele {
7 namespace oauth {
8 using std::string;
9
10 struct token_t {
11 string key;
12 string secret;
13
14 token_t() { }
15 token_t(const string& k,const string& s)
16 : key(k), secret(s) { }
17 };
18
19 }
20}
21
22#endif /* __OPKELE_OAUTH_H */
diff --git a/include/opkele/oauth/consumer.h b/include/opkele/oauth/consumer.h
new file mode 100644
index 0000000..eb4f753
--- a/dev/null
+++ b/include/opkele/oauth/consumer.h
@@ -0,0 +1,135 @@
1#ifndef __OPKELE_OAUTH_CONSUMER_H
2#define __OPKELE_OAUTH_CONSUMER_H
3
4#include <string>
5#include <opkele/types.h>
6#include <opkele/oauth.h>
7#include <opkele/curl.h>
8
9namespace opkele {
10 namespace oauth {
11 using std::string;
12
13 enum oauth_method_t {
14 oauth_auth_header, oauth_post_body, oauth_url_query,
15 oauth_method_default = oauth_auth_header
16 };
17
18 struct service_endpoint_t {
19 string url;
20 string signature_method;
21 oauth_method_t oauth_method;
22
23 service_endpoint_t() : oauth_method(oauth_method_default) { }
24 service_endpoint_t(const string& u,const string& sm,oauth_method_t om=oauth_method_default)
25 : url(u), signature_method(sm), oauth_method(om) { }
26 };
27
28 class basic_provider_endpoints {
29 public:
30
31 virtual ~basic_provider_endpoints() { }
32
33 virtual const service_endpoint_t& get_request_token_endpoint() const = 0;
34 virtual const service_endpoint_t& get_authorize_user_endpoint() const = 0;
35 virtual const service_endpoint_t& get_access_token_endpoint() const = 0;
36
37 virtual service_endpoint_t& get_url_endpoint(service_endpoint_t& sep,
38 const string& url) const = 0;
39 };
40
41 struct http_request_t {
42 string authorize_header;
43 string method;
44 string url;
45 string body;
46
47 util::curl_slist_t _curl_headers_list;
48
49 http_request_t(const string& m,const string& u)
50 : method(m), url(u) { }
51
52 void setup_curl(CURL *curl);
53 };
54
55 class basic_consumer {
56 public:
57 token_t consumer_token;
58
59 basic_consumer(const token_t& ct)
60 : consumer_token(ct) { }
61 virtual ~basic_consumer() { }
62
63 virtual const basic_provider_endpoints& get_endpoints() const = 0;
64 virtual const string allocate_nonce(time_t ts) = 0;
65
66 token_t get_request_token();
67 const string get_authorize_url(const token_t& rt,const string& callback="");
68 token_t get_access_token(const token_t& rt);
69
70 http_request_t& prepare_request(
71 http_request_t& req,
72 const basic_fields& qf,const basic_fields& pf,
73 oauth_method_t om,const string& sm,
74 const token_t *t=0,const string& realm="");
75 http_request_t& prepare_request(
76 http_request_t& req,
77 const basic_fields& qf,const basic_fields& pf,
78 const service_endpoint_t& sep,
79 const token_t *t=0,const string& realm="");
80 http_request_t& prepare_request(
81 http_request_t& req,
82 const basic_fields& qf,const basic_fields& pf,
83 const token_t *t=0,const string& realm="");
84
85 const string signature(
86 const string& method,
87 const string& url,
88 const basic_fields& fields,
89 const token_t* rt=0);
90
91 token_t acquire_token(
92 const service_endpoint_t& sep,
93 const token_t* rt=0);
94 };
95
96 class simple_provider_endpoints : public basic_provider_endpoints {
97 public:
98 service_endpoint_t sep_request_token;
99 service_endpoint_t sep_authorize_user;
100 service_endpoint_t sep_access_token;
101 service_endpoint_t sep_generic;
102
103 simple_provider_endpoints(
104 const string& rt,const string& au,const string& at,
105 const string& sm,
106 oauth_method_t ams=oauth_post_body,
107 oauth_method_t amr=oauth_auth_header )
108 : sep_request_token(rt,sm,ams),
109 sep_authorize_user(au,sm,oauth_url_query),
110 sep_access_token(at,sm,ams),
111 sep_generic("",sm,amr) { }
112
113 const service_endpoint_t& get_request_token_endpoint() const;
114 const service_endpoint_t& get_authorize_user_endpoint() const;
115 const service_endpoint_t& get_access_token_endpoint() const;
116 service_endpoint_t& get_url_endpoint(service_endpoint_t& sep,
117 const string& url) const;
118 };
119
120 class simple_consumer : public basic_consumer {
121 public:
122 simple_provider_endpoints peps;
123
124 simple_consumer(const simple_provider_endpoints& eps,
125 const token_t& ct)
126 : basic_consumer(ct), peps(eps) { }
127
128 const basic_provider_endpoints& get_endpoints() const;
129 const string allocate_nonce(time_t ts);
130 };
131
132 }
133}
134
135#endif /* __OPKELE_OAUTH_CONSUMER_H */
diff --git a/include/opkele/types.h b/include/opkele/types.h
index f63bf5d..4471e6a 100644
--- a/include/opkele/types.h
+++ b/include/opkele/types.h
@@ -143,6 +143,24 @@ namespace opkele {
143 virtual void set_field(const string& n,const string& v); 143 virtual void set_field(const string& n,const string& v);
144 virtual void reset_field(const string& n); 144 virtual void reset_field(const string& n);
145 145
146 void from_query(const string& qs);
147 };
148
149 class fields_t : public basic_fields, public map<string,string> {
150 public:
151 fields_t() { }
152 fields_t(const basic_fields& x)
153 : basic_fields(x) { }
154
155 bool has_field(const string& n) const;
156 const string& get_field(const string& n) const;
157
158 virtual fields_iterator fields_begin() const;
159 virtual fields_iterator fields_end() const;
160
161 virtual void reset_fields();
162 virtual void set_field(const string& n,const string& v);
163 virtual void reset_field(const string& n);
146 }; 164 };
147 165
148 class basic_openid_message : public basic_fields { 166 class basic_openid_message : public basic_fields {
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 20d15b8..6b1fad6 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -7,12 +7,14 @@ INCLUDES = \
7 ${KONFORKA_CFLAGS} \ 7 ${KONFORKA_CFLAGS} \
8 ${OPENSSL_CFLAGS} \ 8 ${OPENSSL_CFLAGS} \
9 ${LIBCURL_CPPFLAGS} \ 9 ${LIBCURL_CPPFLAGS} \
10 ${PCRE_CFLAGS} ${EXPAT_CFLAGS} ${TIDY_CFLAGS} 10 ${PCRE_CFLAGS} ${EXPAT_CFLAGS} ${TIDY_CFLAGS} \
11 ${UUID_CFLAGS}
11libopkele_la_LIBADD = \ 12libopkele_la_LIBADD = \
12 ${LIBCURL} \ 13 ${LIBCURL} \
13 ${PCRE_LIBS} ${EXPAT_LIBS} \ 14 ${PCRE_LIBS} ${EXPAT_LIBS} \
14 ${OPENSSL_LIBS} \ 15 ${OPENSSL_LIBS} \
15 ${KONFORKA_LIBS} ${TIDY_LIBS} 16 ${KONFORKA_LIBS} ${TIDY_LIBS} \
17 ${UUID_LIBS}
16 18
17libopkele_la_SOURCES = \ 19libopkele_la_SOURCES = \
18 params.cc \ 20 params.cc \
@@ -29,6 +31,7 @@ libopkele_la_SOURCES = \
29 discovery.cc \ 31 discovery.cc \
30 basic_rp.cc prequeue_rp.cc \ 32 basic_rp.cc prequeue_rp.cc \
31 fields.cc message.cc \ 33 fields.cc message.cc \
32 basic_op.cc verify_op.cc 34 basic_op.cc verify_op.cc \
35 oauth-consumer.cc
33libopkele_la_LDFLAGS = \ 36libopkele_la_LDFLAGS = \
34 -version-info 2:0:0 37 -version-info 2:0:0
diff --git a/lib/fields.cc b/lib/fields.cc
index d494098..916b603 100644
--- a/lib/fields.cc
+++ b/lib/fields.cc
@@ -43,12 +43,16 @@ namespace opkele {
43 } 43 }
44 __om_query_builder(const char *p,string& r,const basic_fields& m,const string& u) 44 __om_query_builder(const char *p,string& r,const basic_fields& m,const string& u)
45 : om(m), first(true), rv(r), pfx(p) { 45 : om(m), first(true), rv(r), pfx(p) {
46 basic_fields::fields_iterator i=om.fields_begin(),
47 ie=om.fields_end();
46 rv = u; 48 rv = u;
47 if(rv.find('?')==string::npos) 49 if(i!=ie) {
48 rv += '?'; 50 if(rv.find('?')==string::npos)
49 else 51 rv += '?';
50 first = false; 52 else
51 for_each(om.fields_begin(),om.fields_end(),*this); 53 first = false;
54 for_each(i,ie,*this);
55 }
52 } 56 }
53 57
54 result_type operator()(argument_type f) { 58 result_type operator()(argument_type f) {
@@ -82,5 +86,50 @@ namespace opkele {
82 throw not_implemented(OPKELE_CP_ "reset_field() not implemented"); 86 throw not_implemented(OPKELE_CP_ "reset_field() not implemented");
83 } 87 }
84 88
89 void basic_fields::from_query(const string& qs) {
90 for(string::size_type p=0,np;;p=np+1) {
91 np = qs.find('&',p);
92 string::size_type eq = qs.find('=',p);
93 if(eq==string::npos) break;
94 if(np==string::npos) {
95 set_field(
96 util::url_decode(qs.substr(p,eq-p)),
97 util::url_decode(qs.substr(eq+1)) );
98 break;
99 }else if(eq<np) {
100 set_field(
101 util::url_decode(qs.substr(p,eq-p)),
102 util::url_decode(qs.substr(eq+1,np-eq-1)) );
103 }
104 }
105 }
106
107
108 bool fields_t::has_field(const string& n) const {
109 return find(n)!=end();
110 }
111 const string& fields_t::get_field(const string& n) const {
112 const_iterator i=find(n);
113 if(i==end())
114 throw failed_lookup(OPKELE_CP_ n+": no such field");
115 return i->second;
116 }
117
118 fields_t::fields_iterator fields_t::fields_begin() const {
119 return util::map_keys_iterator<const_iterator,string,const string&,const string*>(begin(),end());
120 }
121 fields_t::fields_iterator fields_t::fields_end() const {
122 return util::map_keys_iterator<const_iterator,string,const string&,const string*>(end(),end());
123 }
124
125 void fields_t::reset_fields() {
126 clear();
127 }
128 void fields_t::set_field(const string& n,const string& v) {
129 (*this)[n]=v;
130 }
131 void fields_t::reset_field(const string& n) {
132 erase(n);
133 }
85 134
86} 135}
diff --git a/lib/oauth-consumer.cc b/lib/oauth-consumer.cc
new file mode 100644
index 0000000..bb4e89b
--- a/dev/null
+++ b/lib/oauth-consumer.cc
@@ -0,0 +1,280 @@
1#include <openssl/sha.h>
2#include <openssl/evp.h>
3#include <openssl/hmac.h>
4#include <opkele/oauth/consumer.h>
5#include <opkele/exception.h>
6#include <opkele/util.h>
7#include <opkele/curl.h>
8#include <opkele/debug.h>
9
10#include "config.h"
11#ifdef HAVE_LIBUUID
12# include <uuid/uuid.h>
13#endif
14
15namespace opkele {
16 namespace oauth {
17
18 const service_endpoint_t&
19 simple_provider_endpoints::get_request_token_endpoint() const {
20 return sep_request_token; }
21 const service_endpoint_t&
22 simple_provider_endpoints::get_authorize_user_endpoint() const {
23 return sep_authorize_user; }
24 const service_endpoint_t&
25 simple_provider_endpoints::get_access_token_endpoint() const {
26 return sep_access_token; }
27 service_endpoint_t&
28 simple_provider_endpoints::get_url_endpoint(service_endpoint_t& sep,
29 const string& url) const {
30 sep = sep_generic;
31 sep.url = url;
32 return sep; }
33
34 token_t basic_consumer::get_request_token() {
35 return acquire_token(get_endpoints().get_request_token_endpoint());
36 }
37
38 const string basic_consumer::get_authorize_url(const token_t& rt,const string& callback) {
39 fields_t f;
40 f.set_field("oauth_token",rt.key);
41 if(!callback.empty())
42 f.set_field("oauth_callback",callback);
43 return f.append_query(
44 get_endpoints().get_authorize_user_endpoint().url );
45 }
46
47 token_t basic_consumer::get_access_token(const token_t& rt) {
48 return acquire_token(get_endpoints().get_access_token_endpoint(),&rt);
49 }
50
51 const string basic_consumer::signature(
52 const string& method, const string& url,
53 const basic_fields& fields,
54 const token_t* at) {
55 if(fields.get_field("oauth_signature_method")!="HMAC-SHA1")
56 throw opkele::not_implemented(OPKELE_CP_
57 "only HMAC-SHA1 signature is implemented");
58 string key = util::url_encode(consumer_token.secret);
59 key += '&';
60 if(at)
61 key += util::url_encode(at->secret);
62 /* TODO: do not build the whole subject */
63 string subject = method;
64 subject += '&';
65 string u = util::rfc_3986_normalize_uri(url);
66 string::size_type uco = u.find_first_of("#?");
67 if(uco!=string::npos) u.erase(uco);
68 subject += util::url_encode(u);
69 subject += '&';
70 subject += util::url_encode( fields.query_string() );
71 unsigned char md[SHA_DIGEST_LENGTH];
72 unsigned int md_len = 0;
73 HMAC( EVP_sha1(),
74 key.c_str(),key.size(),
75 (const unsigned char *)subject.c_str(),subject.size(),
76 md,&md_len );
77 assert(md_len==sizeof(md));
78 return util::encode_base64(md,md_len);
79 }
80
81 static void noquerize_url(string& url,const string& sepurl,basic_fields& f) {
82 string::size_type q = sepurl.find('?'),
83 p = sepurl.find('#');
84 if(q==string::npos) {
85 url = sepurl.substr(0,p);
86 }else{
87 fields_t tmp;
88 tmp.from_query(sepurl.substr(
89 q+1,
90 (p==string::npos)?string::npos:(p-q-q)));
91 tmp.append_to(f);
92 url = sepurl.substr(0,(p==string::npos)?q:min(p,q));
93 }
94 }
95
96 token_t basic_consumer::acquire_token(
97 const service_endpoint_t& sep,
98 const token_t* rt) {
99 util::curl_pick_t curl = util::curl_t::easy_init();
100 CURLcode r;
101 (r=curl.misc_sets())
102 || (r=curl.set_write());
103 if(r)
104 throw exception_curl(OPKELE_CP_ "failed to set basic curly options",r);
105 http_request_t hr(
106 (sep.oauth_method==oauth_post_body)?"POST":"GET",
107 "");
108 fields_t uq;
109 noquerize_url(hr.url,sep.url,uq);
110 prepare_request(hr,uq,fields_t(),sep,rt);
111 switch(sep.oauth_method) {
112 case oauth_auth_header:
113 throw opkele::not_implemented(OPKELE_CP_
114 "auth header for token acquisition isn't (yet?) supported");
115 break;
116 case oauth_post_body:
117 (r=curl.easy_setopt(CURLOPT_POST,1))
118 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,hr.body.c_str()))
119 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,hr.body.size()));
120 break;
121 case oauth_url_query:
122 break;
123 default:
124 throw opkele::exception(OPKELE_CP_ /* TODO: specialize */
125 "invalid oauth_method for request_token endpoint");
126 };
127 if(r)
128 throw exception_curl(OPKELE_CP_ "failed to set curly options",r);
129 if( (r=curl.easy_setopt(CURLOPT_URL,hr.url.c_str())) )
130 throw exception_curl(OPKELE_CP_ "failed to set curly urlie",r);
131 if( (r=curl.easy_perform()) )
132 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r);
133 token_t rv;
134 string::size_type p=0;
135 while(p!=string::npos) {
136 string::size_type np = curl.response.find('&',p);
137 string part;
138 if(np==string::npos) {
139 part.assign(curl.response.c_str()+p); p = string::npos;
140 }else{
141 part.assign(curl.response,p,np-p); p = np+1;
142 }
143 string::size_type eq = part.find('=');
144 if(eq==string::npos) continue;
145 string n(part,0,eq);
146 if(n=="oauth_token") {
147 if(!rv.key.empty()) /* TODO: specialize */
148 throw opkele::exception(OPKELE_CP_ "found oauth_token twice");
149 rv.key = util::url_decode(part.substr(eq+1));
150 }else if(n=="oauth_token_secret") {
151 if(!rv.secret.empty()) /* TODO: specialize */
152 throw opkele::exception(OPKELE_CP_ "found oauth_secret twice");
153 rv.secret = util::url_decode(part.substr(eq+1));
154 }
155 }
156 return rv;
157 }
158
159 http_request_t& basic_consumer::prepare_request(
160 http_request_t& req,
161 const basic_fields& qf,const basic_fields& pf,
162 oauth_method_t om,const string& sm,
163 const token_t *t,const string& realm) {
164 fields_t op;
165 op.set_field("oauth_consumer_key",consumer_token.key);
166 if(t) op.set_field("oauth_token",t->key);
167 op.set_field("oauth_signature_method",sm);
168 time_t now;
169 op.set_field("oauth_timestamp",
170 util::long_to_string(time(&now)));
171 op.set_field("oauth_nonce",allocate_nonce(now));
172 op.set_field("oauth_version","1.0");
173 /* TODO: normalize and strip down url */
174 {
175 fields_t af; /* TODO: optimize, I don't want it to be copied */
176 qf.copy_to(af); pf.append_to(af); op.append_to(af);
177 op.set_field("oauth_signature", signature(
178 req.method,req.url,af,t) );
179 }
180 req.authorize_header.clear();
181 if(om==oauth_auth_header) {
182 req.authorize_header = "OAuth ";
183 req.authorize_header += "realm=\"";
184 req.authorize_header += util::url_encode(realm);
185 req.authorize_header += '\"';
186 for(basic_fields::fields_iterator
187 i=op.fields_begin(),ie=op.fields_end();
188 i!=ie;++i) {
189 req.authorize_header += ", ";
190 req.authorize_header += *i;
191 req.authorize_header += "=\"";
192 req.authorize_header += util::url_encode(op.get_field(*i));
193 req.authorize_header += "\"";
194 }
195 req.url = qf.append_query(req.url);
196 req.body = pf.query_string();
197 }else if(om==oauth_post_body) {
198 assert(req.method=="POST");
199 /* TODO: optimize, don't copy it over and over */
200 fields_t p;
201 pf.append_to(p); op.append_to(p);
202 req.url = qf.append_query(req.url);
203 req.body = p.query_string();
204 }else if(om==oauth_url_query) {
205 fields_t q;
206 qf.append_to(q); op.append_to(q);
207 req.url = q.append_query(req.url);
208 req.body = pf.query_string();
209 }else
210 throw opkele::exception(OPKELE_CP_ /* TODO: specialize */
211 "Unknown oauth method");
212 return req;
213 }
214
215 http_request_t& basic_consumer::prepare_request(
216 http_request_t& req,
217 const basic_fields& qf,const basic_fields& pf,
218 const service_endpoint_t& sep,
219 const token_t *t,const string& realm) {
220 return prepare_request(
221 req, qf, pf,
222 sep.oauth_method,sep.signature_method,
223 t,realm);
224 }
225
226 http_request_t& basic_consumer::prepare_request(
227 http_request_t& req,
228 const basic_fields& qf,const basic_fields& pf,
229 const token_t *t,const string& realm) {
230 service_endpoint_t sep;
231 return prepare_request(
232 req, qf, pf,
233 get_endpoints().get_url_endpoint(sep,req.url),
234 t, realm );
235 }
236
237 void http_request_t::setup_curl(CURL *curl) {
238 CURLcode r;
239 r = curl_easy_setopt(curl,CURLOPT_URL,url.c_str());
240 if(r)
241 throw exception_curl(OPKELE_CP_ "failed to set curly urlie",r);
242 if(method=="POST") {
243 (r = curl_easy_setopt(curl,CURLOPT_POST,1))
244 || (r = curl_easy_setopt(curl,CURLOPT_POSTFIELDS,body.c_str()))
245 || (r = curl_easy_setopt(curl,CURLOPT_POSTFIELDSIZE,body.size()));
246 }else if(method=="GET") {
247 r = curl_easy_setopt(curl,CURLOPT_HTTPGET,1);
248 }else if(method=="HEAD") {
249 r = curl_easy_setopt(curl,CURLOPT_NOBODY,1);
250 }else /* TODO: specialize exception */
251 throw exception(OPKELE_CP_ "don't know how to handle http method");
252 if(r)
253 throw exception_curl(OPKELE_CP_ "failed to set curly options",r);
254 if(!authorize_header.empty()) {
255 r = curl_easy_setopt(curl,CURLOPT_HTTPHEADER,(curl_slist*)(
256 _curl_headers_list = curl_slist_append(
257 0,string("Authorization: "+authorize_header).c_str()
258 )
259 ) );
260 if(r)
261 throw exception_curl(OPKELE_CP_ "failed to setup curlie header");
262 }
263 }
264
265
266 const basic_provider_endpoints& simple_consumer::get_endpoints() const {
267 return peps; }
268
269 const string simple_consumer::allocate_nonce(time_t ts) {
270# ifndef HAVE_LIBUUID
271 throw opkele::not_implemented(OPKELE_CP_
272 "not implemented consumer's allocate_nonce()");
273# else /* HAVE_LIBUUID */
274 uuid_t uuid; uuid_generate(uuid);
275 return util::encode_base64(uuid,sizeof(uuid));
276# endif /* HAVE_LIBUUID */
277 }
278
279 }
280}
diff --git a/test/.gitignore b/test/.gitignore
index 3d88495..7b234bd 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -7,3 +7,4 @@
7/RP-db.cc 7/RP-db.cc
8/OP.cgi 8/OP.cgi
9/OP-db.cc 9/OP-db.cc
10/test-oauth-consumer
diff --git a/test/Makefile.am b/test/Makefile.am
index 8fedf48..7cfe3a4 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,4 +1,5 @@
1noinst_PROGRAMS = test idiscover RP.cgi OP.cgi 1noinst_PROGRAMS = test idiscover test-oauth-consumer \
2 ${_dependent_programs_}
2 3
3AM_CPPFLAGS=${CPPFLAGS_DEBUG} 4AM_CPPFLAGS=${CPPFLAGS_DEBUG}
4DEFAULT_INCLUDES = -I${top_builddir} 5DEFAULT_INCLUDES = -I${top_builddir}
@@ -14,15 +15,20 @@ EXTRA_DIST= \
14idiscover_SOURCES = idiscover.cc 15idiscover_SOURCES = idiscover.cc
15idiscover_LDADD = ${top_builddir}/lib/libopkele.la 16idiscover_LDADD = ${top_builddir}/lib/libopkele.la
16 17
18test_oauth_consumer_SOURCES = test-oauth-consumer.cc
19test_oauth_consumer_LDADD = ${top_builddir}/lib/libopkele.la
20
17if HAVE_SQLITE3 21if HAVE_SQLITE3
18if HAVE_KINGATE 22if HAVE_UUID
19if HAVE_UUID 23if HAVE_KINGATE
24
25_dependent_programs_ = RP.cgi OP.cgi
20 26
21RP_cgi_SOURCES = RP.cc 27RP_cgi_SOURCES = RP.cc
22nodist_RP_cgi_SOURCES = RP-db.cc 28nodist_RP_cgi_SOURCES = RP-db.cc
23RP_cgi_LDADD = ${top_builddir}/lib/libopkele.la \ 29RP_cgi_LDADD = ${top_builddir}/lib/libopkele.la \
24 ${SQLITE3_LIBS} ${KINGATE_LIBS} ${UUID_LIBS} 30 ${SQLITE3_LIBS} ${KINGATE_LIBS}
25RP_cgi_CFLAGS = ${SQLITE3_CFLAGS} ${KINGATE_CFLAGS} ${UUID_CFLAGS} 31RP_cgi_CFLAGS = ${SQLITE3_CFLAGS} ${KINGATE_CFLAGS}
26 32
27RP-db.cc: RP-db.sql 33RP-db.cc: RP-db.sql
28 ( \ 34 ( \
@@ -46,6 +52,6 @@ OP-db.cc: OP-db.sql
46clean-local: 52clean-local:
47 rm -f RP-db.cc OP-db.cc 53 rm -f RP-db.cc OP-db.cc
48 54
49endif #HAVE_UUID 55endif #HAVE_KINGATE
50endif #HAVE_KINGATE 56endif #HAVE_UUID
51endif #HAVE_SQLITE3 57endif #HAVE_SQLITE3
diff --git a/test/test-oauth-consumer.cc b/test/test-oauth-consumer.cc
new file mode 100644
index 0000000..b3ddef5
--- a/dev/null
+++ b/test/test-oauth-consumer.cc
@@ -0,0 +1,69 @@
1#include <iostream>
2#include <cassert>
3#include <stdexcept>
4using namespace std;
5#include <openssl/sha.h>
6#include <openssl/evp.h>
7#include <openssl/hmac.h>
8#include <opkele/exception.h>
9#include <opkele/debug.h>
10#include <opkele/util.h>
11#include <opkele/util-internal.h>
12#include <opkele/curl.h>
13#include <opkele/oauth/consumer.h>
14
15ostream& operator<<(ostream& o,const opkele::oauth::token_t& t) {
16 o << "{ key: \"" << t.key << "\", secret: \"" << t.secret <<"\" }";
17 return o;
18}
19
20int main(int,char**) {
21 try {
22 opkele::oauth::simple_consumer sc(
23 opkele::oauth::simple_provider_endpoints(
24 "http://term.ie/oauth/example/request_token.php",
25 "http://term.ie/oauth/example/user_authorization.php",
26 "http://term.ie/oauth/example/access_token.php",
27 "HMAC-SHA1", opkele::oauth::oauth_post_body,
28 opkele::oauth::oauth_auth_header),
29 opkele::oauth::token_t( "key","secret" ) );
30 opkele::oauth::token_t rt = sc.get_request_token();
31 cout << "Request token: " << rt << endl;
32 cout << "Authorize URL: " << sc.get_authorize_url(rt) << endl;
33 opkele::oauth::token_t at = sc.get_access_token(rt);
34 cout << "Access token: " << at << endl;
35
36 opkele::fields_t test;
37 test.set_field("foo","bar");
38 opkele::util::curl_pick_t curl = opkele::util::curl_t::easy_init();
39 opkele::oauth::http_request_t hr("POST",
40 "http://term.ie/oauth/example/echo_api.php");
41 CURLcode r = curl.misc_sets();
42 r || (r=curl.set_write());
43 if(r)
44 throw opkele::exception_curl(OPKELE_CP_ "failed to set curly options",r);
45 sc.prepare_request(hr,opkele::fields_t(),test,&at).setup_curl(curl);
46 if( (r=curl.easy_perform()) )
47 throw opkele::exception_curl(OPKELE_CP_ "failed to perform curly request",r);
48 cout << "Response: " << curl.response << endl;
49
50#ifdef OPKELE_HAVE_KONFORKA
51 }catch(konforka::exception& e) {
52 cerr
53 << "oops, caught " << opkele::util::abi_demangle(typeid(e).name()) << endl
54 << " what: " << e.what() << endl
55 << " where: " << e.where() << endl;
56 if(!e._seen.empty()) {
57 cerr << " seen:" << endl;
58 for(list<konforka::code_point>::const_iterator
59 i=e._seen.begin();i!=e._seen.end();++i) {
60 cerr << " " << i->c_str() << endl;
61 }
62 }
63#endif
64 }catch(std::exception& e){
65 cerr
66 << "oops, caught " << opkele::util::abi_demangle(typeid(e).name()) << endl
67 << " what: " << e.what() << endl;
68 }
69}