summaryrefslogtreecommitdiffabout
authorMichael Krelin <hacker@klever.net>2008-03-04 21:30:28 (UTC)
committer Michael Krelin <hacker@klever.net>2008-03-04 21:34:13 (UTC)
commit748a2a29a5667f372bf355ed737208a952ff79f0 (patch) (unidiff)
tree1739374b0cb82ad2758af8feddbef1b6a6bf5eee
parent1e3ed01c149aaeed5a64aacff218a5486128fc92 (diff)
downloadlibopkele-748a2a29a5667f372bf355ed737208a952ff79f0.zip
libopkele-748a2a29a5667f372bf355ed737208a952ff79f0.tar.gz
libopkele-748a2a29a5667f372bf355ed737208a952ff79f0.tar.bz2
comitting perliminary oauth consumer api
* added the said consumer api and test consumer * added trivial map-based opkele::fields_t container * added UUID flags to libopkele.la build * fixed query_append so that it doesn't append '?' in absence of query parameters * added basic_fields::from_query() Signed-off-by: Michael Krelin <hacker@klever.net>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/Makefile.am1
-rw-r--r--include/opkele/oauth.h22
-rw-r--r--include/opkele/oauth/consumer.h124
-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.cc240
-rw-r--r--test/.gitignore1
-rw-r--r--test/Makefile.am17
-rw-r--r--test/test-oauth-consumer.cc83
10 files changed, 559 insertions, 15 deletions
diff --git a/include/Makefile.am b/include/Makefile.am
index f842bb9..b41e6cc 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -20,6 +20,7 @@ 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 \
23 ${NODIST_HEADERS_} 24 ${NODIST_HEADERS_}
24 25
25noinst_HEADERS = \ 26noinst_HEADERS = \
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..1e2784c
--- a/dev/null
+++ b/include/opkele/oauth/consumer.h
@@ -0,0 +1,124 @@
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
8namespace opkele {
9 namespace oauth {
10 using std::string;
11
12 enum oauth_method_t {
13 oauth_auth_header, oauth_post_body, oauth_url_query
14 };
15
16 struct service_endpoint_t {
17 string url;
18 string signature_method;
19 oauth_method_t oauth_method;
20
21 service_endpoint_t(const string& u,const string& sm,oauth_method_t om)
22 : url(u), signature_method(sm), oauth_method(om) { }
23 };
24
25 class basic_provider_endpoints {
26 public:
27
28 virtual ~basic_provider_endpoints() { }
29
30 virtual const service_endpoint_t& get_request_token_endpoint() const = 0;
31 virtual const service_endpoint_t& get_authorize_user_endpoint() const = 0;
32 virtual const service_endpoint_t& get_access_token_endpoint() const = 0;
33
34 virtual service_endpoint_t& get_url_endpoint(service_endpoint_t& sep,
35 const string& url) const = 0;
36 };
37
38 struct http_request_t {
39 string authorize_header;
40 string method;
41 string url;
42 string body;
43
44 http_request_t(const string& m,const string& u)
45 : method(m), url(u) { }
46 };
47
48 class basic_consumer {
49 public:
50 token_t consumer_token;
51
52 basic_consumer(const token_t& ct)
53 : consumer_token(ct) { }
54 virtual ~basic_consumer() { }
55
56 virtual const basic_provider_endpoints& get_endpoints() const = 0;
57 virtual const string allocate_nonce(time_t ts) = 0;
58
59 token_t get_request_token();
60 const string get_authorize_url(const token_t& rt,const string& callback="");
61 token_t get_access_token(const token_t& rt);
62
63 void prepare_request(
64 http_request_t& req,
65 const basic_fields& qf,const basic_fields& pf,
66 oauth_method_t om,const string& sm,
67 const token_t *t=0,const string& realm="");
68 void prepare_request(
69 http_request_t& req,
70 const basic_fields& qf,const basic_fields& pf,
71 const service_endpoint_t& sep,
72 const token_t *t=0,const string& realm="");
73
74 const string signature(
75 const string& method,
76 const string& url,
77 const basic_fields& fields,
78 const token_t* rt=0);
79
80 token_t acquire_token(
81 const service_endpoint_t& sep,
82 const token_t* rt=0);
83 };
84
85 class simple_provider_endpoints : public basic_provider_endpoints {
86 public:
87 service_endpoint_t sep_request_token;
88 service_endpoint_t sep_authorize_user;
89 service_endpoint_t sep_access_token;
90 service_endpoint_t sep_generic;
91
92 simple_provider_endpoints(
93 const string& rt,const string& au,const string& at,
94 const string& sm,
95 oauth_method_t ams=oauth_post_body,
96 oauth_method_t amr=oauth_auth_header )
97 : sep_request_token(rt,sm,ams),
98 sep_authorize_user(au,sm,oauth_url_query),
99 sep_access_token(at,sm,ams),
100 sep_generic("",sm,amr) { }
101
102 const service_endpoint_t& get_request_token_endpoint() const;
103 const service_endpoint_t& get_authorize_user_endpoint() const;
104 const service_endpoint_t& get_access_token_endpoint() const;
105 service_endpoint_t& get_url_endpoint(service_endpoint_t& sep,
106 const string& url) const;
107 };
108
109 class simple_consumer : public basic_consumer {
110 public:
111 simple_provider_endpoints peps;
112
113 simple_consumer(const simple_provider_endpoints& eps,
114 const token_t& ct)
115 : basic_consumer(ct), peps(eps) { }
116
117 const basic_provider_endpoints& get_endpoints() const;
118 const string allocate_nonce(time_t ts);
119 };
120
121 }
122}
123
124#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..d717ed3
--- a/dev/null
+++ b/lib/oauth-consumer.cc
@@ -0,0 +1,240 @@
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 void 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 }
213
214 void basic_consumer::prepare_request(
215 http_request_t& req,
216 const basic_fields& qf,const basic_fields& pf,
217 const service_endpoint_t& sep,
218 const token_t *t,const string& realm) {
219 prepare_request(
220 req, qf, pf,
221 sep.oauth_method,sep.signature_method,
222 t,realm);
223 }
224
225
226 const basic_provider_endpoints& simple_consumer::get_endpoints() const {
227 return peps; }
228
229 const string simple_consumer::allocate_nonce(time_t ts) {
230# ifndef HAVE_LIBUUID
231 throw opkele::not_implemented(OPKELE_CP_
232 "not implemented consumer's allocate_nonce()");
233# else /* HAVE_LIBUUID */
234 uuid_t uuid; uuid_generate(uuid);
235 return util::encode_base64(uuid,sizeof(uuid));
236# endif /* HAVE_LIBUUID */
237 }
238
239 }
240}
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..f0c0ea8 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,4 +1,4 @@
1noinst_PROGRAMS = test idiscover RP.cgi OP.cgi 1noinst_PROGRAMS = test idiscover RP.cgi OP.cgi test-oauth-consumer
2 2
3AM_CPPFLAGS=${CPPFLAGS_DEBUG} 3AM_CPPFLAGS=${CPPFLAGS_DEBUG}
4DEFAULT_INCLUDES = -I${top_builddir} 4DEFAULT_INCLUDES = -I${top_builddir}
@@ -14,15 +14,18 @@ EXTRA_DIST= \
14idiscover_SOURCES = idiscover.cc 14idiscover_SOURCES = idiscover.cc
15idiscover_LDADD = ${top_builddir}/lib/libopkele.la 15idiscover_LDADD = ${top_builddir}/lib/libopkele.la
16 16
17test_oauth_consumer_SOURCES = test-oauth-consumer.cc
18test_oauth_consumer_LDADD = ${top_builddir}/lib/libopkele.la
19
17if HAVE_SQLITE3 20if HAVE_SQLITE3
18if HAVE_KINGATE 21if HAVE_UUID
19if HAVE_UUID 22if HAVE_KINGATE
20 23
21RP_cgi_SOURCES = RP.cc 24RP_cgi_SOURCES = RP.cc
22nodist_RP_cgi_SOURCES = RP-db.cc 25nodist_RP_cgi_SOURCES = RP-db.cc
23RP_cgi_LDADD = ${top_builddir}/lib/libopkele.la \ 26RP_cgi_LDADD = ${top_builddir}/lib/libopkele.la \
24 ${SQLITE3_LIBS} ${KINGATE_LIBS} ${UUID_LIBS} 27 ${SQLITE3_LIBS} ${KINGATE_LIBS}
25RP_cgi_CFLAGS = ${SQLITE3_CFLAGS} ${KINGATE_CFLAGS} ${UUID_CFLAGS} 28RP_cgi_CFLAGS = ${SQLITE3_CFLAGS} ${KINGATE_CFLAGS}
26 29
27RP-db.cc: RP-db.sql 30RP-db.cc: RP-db.sql
28 ( \ 31 ( \
@@ -46,6 +49,6 @@ OP-db.cc: OP-db.sql
46clean-local: 49clean-local:
47 rm -f RP-db.cc OP-db.cc 50 rm -f RP-db.cc OP-db.cc
48 51
49endif #HAVE_UUID 52endif #HAVE_KINGATE
50endif #HAVE_KINGATE 53endif #HAVE_UUID
51endif #HAVE_SQLITE3 54endif #HAVE_SQLITE3
diff --git a/test/test-oauth-consumer.cc b/test/test-oauth-consumer.cc
new file mode 100644
index 0000000..3b3ca70
--- a/dev/null
+++ b/test/test-oauth-consumer.cc
@@ -0,0 +1,83 @@
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 sc.prepare_request(hr,
42 opkele::fields_t(),test,
43 opkele::oauth::oauth_auth_header,"HMAC-SHA1",
44 &at,"realm");
45 DOUT_("url: " << hr.url << endl
46 << "body: " << hr.body << endl
47 << "header: " << hr.authorize_header);
48 opkele::util::curl_slist_t rh;
49 rh.append("Authorization: "+hr.authorize_header);
50 CURLcode r;
51 (r=curl.misc_sets())
52 || (r=curl.set_write())
53 || (r=curl.easy_setopt(CURLOPT_HTTPHEADER,rh) )
54 || (r=curl.easy_setopt(CURLOPT_URL,hr.url.c_str()))
55 || (r=curl.easy_setopt(CURLOPT_POST,1))
56 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,hr.body.c_str()))
57 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,hr.body.size()));
58 if(r)
59 throw opkele::exception_curl(OPKELE_CP_ "failed to set curly options",r);
60 if( (r=curl.easy_perform()) )
61 throw opkele::exception_curl(OPKELE_CP_ "failed to perform curly request",r);
62 DOUT_("Response: " << endl << curl.response);
63
64#ifdef OPKELE_HAVE_KONFORKA
65 }catch(konforka::exception& e) {
66 cerr
67 << "oops, caught " << opkele::util::abi_demangle(typeid(e).name()) << endl
68 << " what: " << e.what() << endl
69 << " where: " << e.where() << endl;
70 if(!e._seen.empty()) {
71 cerr << " seen:" << endl;
72 for(list<konforka::code_point>::const_iterator
73 i=e._seen.begin();i!=e._seen.end();++i) {
74 cerr << " " << i->c_str() << endl;
75 }
76 }
77#endif
78 }catch(std::exception& e){
79 cerr
80 << "oops, caught " << opkele::util::abi_demangle(typeid(e).name()) << endl
81 << " what: " << e.what() << endl;
82 }
83}