-rw-r--r-- | acinclude.m4 | 17 | ||||
-rw-r--r-- | configure.ac | 83 | ||||
-rw-r--r-- | include/Makefile.am | 8 | ||||
-rw-r--r-- | include/opkele/.gitignore | 1 | ||||
-rw-r--r-- | include/opkele/consumer.h | 6 | ||||
-rw-r--r-- | include/opkele/curl.h | 24 | ||||
-rw-r--r-- | include/opkele/debug.h | 17 | ||||
-rw-r--r-- | include/opkele/discovery.h | 40 | ||||
-rw-r--r-- | include/opkele/exception.h | 95 | ||||
-rw-r--r-- | include/opkele/expat.h | 91 | ||||
-rw-r--r-- | include/opkele/server.h | 4 | ||||
-rw-r--r-- | include/opkele/tidy.h | 73 | ||||
-rw-r--r-- | include/opkele/tr1-mem.h.in | 10 | ||||
-rw-r--r-- | include/opkele/types.h | 92 | ||||
-rw-r--r-- | include/opkele/uris.h | 18 | ||||
-rw-r--r-- | lib/Makefile.am | 11 | ||||
-rw-r--r-- | lib/consumer.cc | 20 | ||||
-rw-r--r-- | lib/discovery.cc | 446 | ||||
-rw-r--r-- | lib/exception.cc | 22 | ||||
-rw-r--r-- | lib/expat.cc | 96 | ||||
-rw-r--r-- | lib/params.cc | 13 | ||||
-rw-r--r-- | lib/secret.cc | 12 | ||||
-rw-r--r-- | lib/sreg.cc | 2 | ||||
-rw-r--r-- | lib/util.cc | 55 | ||||
-rw-r--r-- | libopkele.pc.in | 4 | ||||
-rw-r--r-- | test/.gitignore | 1 | ||||
-rw-r--r-- | test/Makefile.am | 6 | ||||
-rw-r--r-- | test/idiscover.cc | 54 |
28 files changed, 1247 insertions, 74 deletions
diff --git a/acinclude.m4 b/acinclude.m4 index 80defc7..fbb4cdc 100644 --- a/acinclude.m4 +++ b/acinclude.m4 | |||
@@ -163,4 +163,21 @@ AC_DEFUN([AC_WITH_PCREPP],[ | |||
163 | fi | 163 | fi |
164 | ]) | 164 | ]) |
165 | 165 | ||
166 | dnl AC_CHECK_SHAREDPTR(NS,HEADER[,ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]) | ||
167 | AC_DEFUN([AC_CHECK_SHAREDPTR],[ | ||
168 | AC_LANG_PUSH([C++]) | ||
169 | AC_MSG_CHECKING([for $1::shared_ptr<> in $2]) | ||
170 | AC_COMPILE_IFELSE([ | ||
171 | #include <$2> | ||
172 | int main(int c,char**v) { $1::shared_ptr<int> spi(new int(0)); return *spi; } | ||
173 | ],[ | ||
174 | AC_MSG_RESULT([found]) | ||
175 | $3 | ||
176 | ],[ | ||
177 | AC_MSG_RESULT([not found]) | ||
178 | $4 | ||
179 | ]) | ||
180 | AC_LANG_POP([C++]) | ||
181 | ]) | ||
182 | |||
166 | m4_include([acinclude.d/libcurl.m4]) | 183 | m4_include([acinclude.d/libcurl.m4]) |
diff --git a/configure.ac b/configure.ac index 48a5efb..c28141c 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -26,6 +26,41 @@ AC_MSG_RESULT([$PACKAGE_SRC_VERSION]) | |||
26 | AC_SUBST([PACKAGE_SRC_VERSION]) | 26 | AC_SUBST([PACKAGE_SRC_VERSION]) |
27 | AC_DEFINE_UNQUOTED([PACKAGE_SRC_VERSION],["$PACKAGE_SRC_VERSION"],[more or less precise source tree version]) | 27 | AC_DEFINE_UNQUOTED([PACKAGE_SRC_VERSION],["$PACKAGE_SRC_VERSION"],[more or less precise source tree version]) |
28 | 28 | ||
29 | tr1_mem_std="false" | ||
30 | tr1_mem_boost="false" | ||
31 | AC_CHECK_SHAREDPTR(std::tr1,tr1/memory,[ tr1_mem_std=true ]) | ||
32 | AC_CHECK_SHAREDPTR(boost,boost/shared_ptr.hpp,[ tr1_mem_boost=true ]) | ||
33 | tr1_mem="" | ||
34 | AC_ARG_WITH([tr1-memory], | ||
35 | AC_HELP_STRING([--with-tr1-memory=<boost|std>],[select tr1/memory (shared_ptr<>) implementation to use]), | ||
36 | [ tr1_mem="$withval" ] | ||
37 | ) | ||
38 | AC_MSG_CHECKING([for tr1/memory implementation to use]) | ||
39 | test -z "$tr1_mem" && $tr1_mem_std && tr1_mem=std | ||
40 | test -z "$tr1_mem" && $tr1_mem_boost && tr1_mem=boost | ||
41 | if test -z "$tr1_mem" ; then | ||
42 | AC_MSG_RESULT([none found]) | ||
43 | else | ||
44 | AC_MSG_RESULT([$tr1_mem]) | ||
45 | fi | ||
46 | case "$tr1_mem" in | ||
47 | std) | ||
48 | $tr1_mem_std || AC_MSG_ERROR([std implementation requested, but not found]) | ||
49 | OPKELE_TR1_MEM_NS=std::tr1 | ||
50 | OPKELE_TR1_MEM_HEADER=tr1/memory | ||
51 | ;; | ||
52 | boost) | ||
53 | $tr1_mem_boost || AC_MSG_ERROR([boost implementation requested, but not found]) | ||
54 | OPKELE_TR1_MEM_NS=boost | ||
55 | OPKELE_TR1_MEM_HEADER=boost/shared_ptr.hpp | ||
56 | ;; | ||
57 | *) | ||
58 | AC_MSG_ERROR([no shared_ptr<> implementation found]) | ||
59 | ;; | ||
60 | esac | ||
61 | AC_SUBST([OPKELE_TR1_MEM_NS]) | ||
62 | AC_SUBST([OPKELE_TR1_MEM_HEADER]) | ||
63 | |||
29 | PKG_CHECK_MODULES([OPENSSL],[openssl],,[ | 64 | PKG_CHECK_MODULES([OPENSSL],[openssl],,[ |
30 | AC_MSG_ERROR([no openssl library found. get one from http://www.openssl.org/]) | 65 | AC_MSG_ERROR([no openssl library found. get one from http://www.openssl.org/]) |
31 | ]) | 66 | ]) |
@@ -66,6 +101,32 @@ LIBCURL_CHECK_CONFIG(,,,[ | |||
66 | AC_MSG_ERROR([no required libcurl library. get one from http://curl.haxx.se/]) | 101 | AC_MSG_ERROR([no required libcurl library. get one from http://curl.haxx.se/]) |
67 | ]) | 102 | ]) |
68 | 103 | ||
104 | AC_CHECK_HEADER([expat.h],[ | ||
105 | AC_CHECK_LIB([expat],[XML_ParserCreate],[ | ||
106 | EXPAT_LIBS=-lexpat | ||
107 | EXPAT_CFLAGS= | ||
108 | AC_SUBST([EXPAT_LIBS]) | ||
109 | AC_SUBST([EXPAT_CFLAGS]) | ||
110 | ],[ | ||
111 | AC_MSG_ERROR([no required expat library. get one from http://expat.sourceforge.net/]) | ||
112 | ]) | ||
113 | ],[ | ||
114 | AC_MSG_ERROR([no required expat library. get one from http://expat.sourceforge.net/]) | ||
115 | ]) | ||
116 | |||
117 | AC_CHECK_HEADER([tidy.h],[ | ||
118 | AC_CHECK_LIB([tidy],[tidyParseBuffer],[ | ||
119 | TIDY_LIBS=-ltidy | ||
120 | TIDY_CFLAGS= | ||
121 | AC_SUBST([TIDY_LIBS]) | ||
122 | AC_SUBST([TIDY_CFLAGS]) | ||
123 | ],[ | ||
124 | AC_MSG_ERROR([no required htmltidy library found. get one from http://tidy.sourceforge.net/]) | ||
125 | ]) | ||
126 | ],[ | ||
127 | AC_MSG_ERROR([no required htmltidy library found. get one from http://tidy.sourceforge.net/]) | ||
128 | ]) | ||
129 | |||
69 | if test -n "$PCRE_LIBS" -a -n "$PCRE_CFLAGS" ; then | 130 | if test -n "$PCRE_LIBS" -a -n "$PCRE_CFLAGS" ; then |
70 | AC_SUBST([PCRE_CFLAGS]) | 131 | AC_SUBST([PCRE_CFLAGS]) |
71 | AC_SUBST([PCRE_LIBS]) | 132 | AC_SUBST([PCRE_LIBS]) |
@@ -117,11 +178,33 @@ if $nitpick ; then | |||
117 | CXXFLAGS="$CXXFLAGS $CXX_NITPICK" | 178 | CXXFLAGS="$CXXFLAGS $CXX_NITPICK" |
118 | fi | 179 | fi |
119 | 180 | ||
181 | ndebug=true | ||
182 | AC_ARG_ENABLE([debug], | ||
183 | AC_HELP_STRING([--enable-debug],[enable debugging code]), | ||
184 | [ test "$enableval" = "no" || ndebug=false ] | ||
185 | ) | ||
186 | if $ndebug ; then | ||
187 | CPPFLAGS_DEBUG="-DNDEBUG" | ||
188 | else | ||
189 | CPPFLAGS_DEBUG="" | ||
190 | fi | ||
191 | AC_SUBST([CPPFLAGS_DEBUG]) | ||
192 | |||
193 | xri_proxy_url="http://beta.xri.net/" | ||
194 | AC_MSG_CHECKING([for XRI resolver proxy]) | ||
195 | AC_ARG_ENABLE([xri-proxy], | ||
196 | AC_HELP_STRING([--with-xri-proxy=url],[set xri proxy for use when resolving xri identities, default is http://xr_proxy_url]), | ||
197 | [ xri_proxy_url="$withval" ] | ||
198 | ) | ||
199 | AC_MSG_RESULT([$xri_proxy_url]) | ||
200 | AC_DEFINE_UNQUOTED([XRI_PROXY_URL],["$xri_proxy_url"],[XRI proxy resolver URL]) | ||
201 | |||
120 | AC_CONFIG_FILES([ | 202 | AC_CONFIG_FILES([ |
121 | Makefile | 203 | Makefile |
122 | libopkele.pc | 204 | libopkele.pc |
123 | Doxyfile | 205 | Doxyfile |
124 | include/Makefile | 206 | include/Makefile |
207 | include/opkele/tr1-mem.h | ||
125 | lib/Makefile | 208 | lib/Makefile |
126 | test/Makefile | 209 | test/Makefile |
127 | ]) | 210 | ]) |
diff --git a/include/Makefile.am b/include/Makefile.am index b31786d..51dcea1 100644 --- a/include/Makefile.am +++ b/include/Makefile.am | |||
@@ -10,8 +10,12 @@ nobase_include_HEADERS = \ | |||
10 | opkele/sreg.h \ | 10 | opkele/sreg.h \ |
11 | opkele/extension_chain.h \ | 11 | opkele/extension_chain.h \ |
12 | opkele/xconsumer.h \ | 12 | opkele/xconsumer.h \ |
13 | opkele/xserver.h | 13 | opkele/xserver.h \ |
14 | opkele/discovery.h \ | ||
15 | opkele/uris.h \ | ||
16 | opkele/tr1-mem.h | ||
14 | EXTRA_DIST = \ | 17 | EXTRA_DIST = \ |
15 | opkele/data.h \ | 18 | opkele/data.h \ |
19 | opkele/curl.h opkele/expat.h opkele/tidy.h \ | ||
16 | opkele/util.h \ | 20 | opkele/util.h \ |
17 | opkele/curl.h | 21 | opkele/debug.h |
diff --git a/include/opkele/.gitignore b/include/opkele/.gitignore index ffa24dc..dfc2d2c 100644 --- a/include/opkele/.gitignore +++ b/include/opkele/.gitignore | |||
@@ -1,2 +1,3 @@ | |||
1 | acconfig.h | 1 | acconfig.h |
2 | tr1-mem.h | ||
2 | stamp-h2 | 3 | stamp-h2 |
diff --git a/include/opkele/consumer.h b/include/opkele/consumer.h index c463787..3c1d318 100644 --- a/include/opkele/consumer.h +++ b/include/opkele/consumer.h | |||
@@ -31,7 +31,7 @@ namespace opkele { | |||
31 | * @param handle association handle | 31 | * @param handle association handle |
32 | * @param secret the secret associated with the server and handle | 32 | * @param secret the secret associated with the server and handle |
33 | * @param expires_in the number of seconds until the handle is expired | 33 | * @param expires_in the number of seconds until the handle is expired |
34 | * @return the auto_ptr<> for the newly allocated association_t object | 34 | * @return the assoc_t for the newly allocated association_t object |
35 | */ | 35 | */ |
36 | virtual assoc_t store_assoc(const string& server,const string& handle,const secret_t& secret,int expires_in) = 0; | 36 | virtual assoc_t store_assoc(const string& server,const string& handle,const secret_t& secret,int expires_in) = 0; |
37 | /** | 37 | /** |
@@ -73,7 +73,7 @@ namespace opkele { | |||
73 | * middle of negotiations. | 73 | * middle of negotiations. |
74 | * | 74 | * |
75 | * @param server the OpenID server | 75 | * @param server the OpenID server |
76 | * @return the auto_ptr<> for the newly allocated association_t object | 76 | * @return the assoc_t for the newly allocated association_t object |
77 | * @throw failed_lookup in case of absence of the handle | 77 | * @throw failed_lookup in case of absence of the handle |
78 | */ | 78 | */ |
79 | virtual assoc_t find_assoc(const string& server); | 79 | virtual assoc_t find_assoc(const string& server); |
@@ -93,7 +93,7 @@ namespace opkele { | |||
93 | /** | 93 | /** |
94 | * perform the associate request to OpenID server. | 94 | * perform the associate request to OpenID server. |
95 | * @param server the OpenID server | 95 | * @param server the OpenID server |
96 | * @return the auto_ptr<> for the newly allocated association_t | 96 | * @return the assoc_t for the newly allocated association_t |
97 | * object, representing established association | 97 | * object, representing established association |
98 | * @throw exception in case of error | 98 | * @throw exception in case of error |
99 | */ | 99 | */ |
diff --git a/include/opkele/curl.h b/include/opkele/curl.h index 8020b63..5cf8e48 100644 --- a/include/opkele/curl.h +++ b/include/opkele/curl.h | |||
@@ -2,9 +2,13 @@ | |||
2 | #define __OPKELE_CURL_H | 2 | #define __OPKELE_CURL_H |
3 | 3 | ||
4 | #include <cassert> | 4 | #include <cassert> |
5 | #include <string> | ||
6 | #include <algorithm> | ||
5 | #include <curl/curl.h> | 7 | #include <curl/curl.h> |
6 | 8 | ||
7 | namespace opkele { | 9 | namespace opkele { |
10 | using std::min; | ||
11 | using std::string; | ||
8 | 12 | ||
9 | namespace util { | 13 | namespace util { |
10 | 14 | ||
@@ -41,6 +45,26 @@ namespace opkele { | |||
41 | CURLcode set_header(); | 45 | CURLcode set_header(); |
42 | }; | 46 | }; |
43 | 47 | ||
48 | template<int lim> | ||
49 | class curl_fetch_string_t : public curl_t { | ||
50 | public: | ||
51 | curl_fetch_string_t(CURL *c) | ||
52 | : curl_t(c) { } | ||
53 | ~curl_fetch_string_t() throw() { } | ||
54 | |||
55 | string response; | ||
56 | |||
57 | size_t write(void *p,size_t size,size_t nmemb) { | ||
58 | size_t bytes = size*nmemb; | ||
59 | size_t get = min(lim-response.length(),bytes); | ||
60 | response.append((const char *)p,get); | ||
61 | return get; | ||
62 | } | ||
63 | }; | ||
64 | |||
65 | typedef curl_fetch_string_t<16384> curl_pick_t; | ||
66 | |||
67 | |||
44 | } | 68 | } |
45 | 69 | ||
46 | } | 70 | } |
diff --git a/include/opkele/debug.h b/include/opkele/debug.h new file mode 100644 index 0000000..a02f8d4 --- a/dev/null +++ b/include/opkele/debug.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef __OPKELE_DEBUG_H | ||
2 | #define __OPKELE_DEBUG_H | ||
3 | |||
4 | #ifdef NDEBUG | ||
5 | |||
6 | #define D_(x) ((void)0) | ||
7 | #define DOUT_(x)((void)0) | ||
8 | |||
9 | #else /* NDEBUG */ | ||
10 | |||
11 | #define D_(x) x | ||
12 | #include <iostream> | ||
13 | #define DOUT_(x)std::clog << x << std::endl | ||
14 | |||
15 | #endif /* NDEBUG */ | ||
16 | |||
17 | #endif /* __OPKELE_DEBUG_H */ | ||
diff --git a/include/opkele/discovery.h b/include/opkele/discovery.h new file mode 100644 index 0000000..af4aa29 --- a/dev/null +++ b/include/opkele/discovery.h | |||
@@ -0,0 +1,40 @@ | |||
1 | #ifndef __OPKELE_DISCOVERY_H | ||
2 | #define __OPKELE_DISCOVERY_H | ||
3 | |||
4 | #include <string> | ||
5 | #include <opkele/types.h> | ||
6 | |||
7 | namespace opkele { | ||
8 | using std::string; | ||
9 | |||
10 | struct idiscovery_t; | ||
11 | |||
12 | void idiscover(idiscovery_t& result,const string& identity); | ||
13 | |||
14 | struct idiscovery_t { | ||
15 | bool xri_identity; | ||
16 | string normalized_id; | ||
17 | string canonicalized_id; | ||
18 | xrd::XRD_t xrd; | ||
19 | |||
20 | idiscovery_t() { } | ||
21 | idiscovery_t(const string& i) { | ||
22 | idiscover(*this,i); | ||
23 | } | ||
24 | idiscovery_t(const char *i) { | ||
25 | idiscover(*this,i); | ||
26 | } | ||
27 | |||
28 | void clear() { | ||
29 | normalized_id.clear(); canonicalized_id.clear(); | ||
30 | xrd.clear(); | ||
31 | } | ||
32 | |||
33 | idiscovery_t& operator=(const string& i) { | ||
34 | idiscover(*this,i); return *this; } | ||
35 | idiscovery_t& operator=(const char *i) { | ||
36 | idiscover(*this,i); return *this; } | ||
37 | }; | ||
38 | } | ||
39 | |||
40 | #endif /* __OPKELE_DISCOVERY_H */ | ||
diff --git a/include/opkele/exception.h b/include/opkele/exception.h index 2ff44b7..a8c3339 100644 --- a/include/opkele/exception.h +++ b/include/opkele/exception.h | |||
@@ -24,9 +24,13 @@ | |||
24 | */ | 24 | */ |
25 | # define OPKELE_CP_ CODEPOINT, | 25 | # define OPKELE_CP_ CODEPOINT, |
26 | /** | 26 | /** |
27 | * open function-try-block | ||
28 | */ | ||
29 | # define OPKELE_FUNC_TRY try | ||
30 | /** | ||
27 | * the simple rethrow of konforka-based exception | 31 | * the simple rethrow of konforka-based exception |
28 | */ | 32 | */ |
29 | # define OPKELE_RETHROW catch(konforka::exception& e) { e.see(CODEPOINT); throw } | 33 | # define OPKELE_RETHROW catch(konforka::exception& e) { e.see(CODEPOINT); throw; } |
30 | #else /* OPKELE_HAVE_KONFORKA */ | 34 | #else /* OPKELE_HAVE_KONFORKA */ |
31 | # include <exception> | 35 | # include <exception> |
32 | # include <string> | 36 | # include <string> |
@@ -44,6 +48,10 @@ | |||
44 | */ | 48 | */ |
45 | # define OPKELE_CP_ | 49 | # define OPKELE_CP_ |
46 | /** | 50 | /** |
51 | * the dummy define for the opening function-try-block | ||
52 | */ | ||
53 | # define OPKELE_FUNC_TRY | ||
54 | /** | ||
47 | * the dummy define for the konforka-based rethrow of exception | 55 | * the dummy define for the konforka-based rethrow of exception |
48 | */ | 56 | */ |
49 | # define OPKELE_RETHROW | 57 | # define OPKELE_RETHROW |
@@ -69,13 +77,10 @@ namespace opkele { | |||
69 | public: | 77 | public: |
70 | # ifdef OPKELE_HAVE_KONFORKA | 78 | # ifdef OPKELE_HAVE_KONFORKA |
71 | explicit | 79 | explicit |
72 | exception(const string& fi,const string& fu,int l,const string& w) | 80 | exception(const string& fi,const string& fu,int l,const string& w); |
73 | : konforka::exception(fi,fu,l,w) { } | ||
74 | # else /* OPKELE_HAVE_KONFORKA */ | 81 | # else /* OPKELE_HAVE_KONFORKA */ |
75 | string _what; | 82 | string _what; |
76 | explicit | 83 | explicit exception(const string& w); |
77 | exception(const string& w) | ||
78 | : _what(w) { } | ||
79 | virtual ~exception() throw(); | 84 | virtual ~exception() throw(); |
80 | virtual const char * what() const throw(); | 85 | virtual const char * what() const throw(); |
81 | # endif /* OPKELE_HAVE_KONFORKA */ | 86 | # endif /* OPKELE_HAVE_KONFORKA */ |
@@ -156,7 +161,7 @@ namespace opkele { | |||
156 | class id_res_setup : public id_res_failed { | 161 | class id_res_setup : public id_res_failed { |
157 | public: | 162 | public: |
158 | string setup_url; | 163 | string setup_url; |
159 | id_res_setup(OPKELE_E_PARS,const string& su) | 164 | id_res_setup(OPKELE_E_PARS,const string& su="") |
160 | : id_res_failed(OPKELE_E_CONS), setup_url(su) { } | 165 | : id_res_failed(OPKELE_E_CONS), setup_url(su) { } |
161 | ~id_res_setup() throw() { } | 166 | ~id_res_setup() throw() { } |
162 | }; | 167 | }; |
@@ -179,6 +184,42 @@ namespace opkele { | |||
179 | }; | 184 | }; |
180 | 185 | ||
181 | /** | 186 | /** |
187 | * thown when the user cancelled authentication process. | ||
188 | */ | ||
189 | class id_res_cancel : public id_res_failed { | ||
190 | public: | ||
191 | id_res_cancel(OPKELE_E_PARS) | ||
192 | : id_res_failed(OPKELE_E_CONS) { } | ||
193 | }; | ||
194 | |||
195 | /** | ||
196 | * thrown in case of nonce reuse or otherwise imperfect nonce. | ||
197 | */ | ||
198 | class id_res_bad_nonce : public id_res_failed { | ||
199 | public: | ||
200 | id_res_bad_nonce(OPKELE_E_PARS) | ||
201 | : id_res_failed(OPKELE_E_CONS) { } | ||
202 | }; | ||
203 | |||
204 | /** | ||
205 | * thrown if return_to didn't pass verification | ||
206 | */ | ||
207 | class id_res_bad_return_to : public id_res_failed { | ||
208 | public: | ||
209 | id_res_bad_return_to(OPKELE_E_PARS) | ||
210 | : id_res_failed(OPKELE_E_CONS) { } | ||
211 | }; | ||
212 | |||
213 | /** | ||
214 | * thrown if OP isn't authorized to make an assertion | ||
215 | */ | ||
216 | class id_res_unauthorized : public id_res_failed { | ||
217 | public: | ||
218 | id_res_unauthorized(OPKELE_E_PARS) | ||
219 | : id_res_failed(OPKELE_E_CONS) { } | ||
220 | }; | ||
221 | |||
222 | /** | ||
182 | * openssl malfunction occured | 223 | * openssl malfunction occured |
183 | */ | 224 | */ |
184 | class exception_openssl : public exception { | 225 | class exception_openssl : public exception { |
@@ -212,6 +253,36 @@ namespace opkele { | |||
212 | }; | 253 | }; |
213 | 254 | ||
214 | /** | 255 | /** |
256 | * htmltidy related error occured | ||
257 | */ | ||
258 | class exception_tidy : public exception { | ||
259 | public: | ||
260 | int _rc; | ||
261 | exception_tidy(OPKELE_E_PARS); | ||
262 | exception_tidy(OPKELE_E_PARS,int r); | ||
263 | ~exception_tidy() throw() { } | ||
264 | }; | ||
265 | |||
266 | /** | ||
267 | * exception thrown in case of failed discovery | ||
268 | */ | ||
269 | class failed_discovery : public exception { | ||
270 | public: | ||
271 | failed_discovery(OPKELE_E_PARS) | ||
272 | : exception(OPKELE_E_CONS) { } | ||
273 | }; | ||
274 | |||
275 | /** | ||
276 | * unsuccessfull xri resolution | ||
277 | */ | ||
278 | class failed_xri_resolution : public failed_discovery { | ||
279 | public: | ||
280 | long _code; | ||
281 | failed_xri_resolution(OPKELE_E_PARS,long _c=-1) | ||
282 | : failed_discovery(OPKELE_E_CONS), _code(_c) { } | ||
283 | }; | ||
284 | |||
285 | /** | ||
215 | * not implemented (think pure virtual) member function executed, signfies | 286 | * not implemented (think pure virtual) member function executed, signfies |
216 | * programmer error | 287 | * programmer error |
217 | */ | 288 | */ |
@@ -230,6 +301,16 @@ namespace opkele { | |||
230 | : exception(OPKELE_E_CONS) { } | 301 | : exception(OPKELE_E_CONS) { } |
231 | }; | 302 | }; |
232 | 303 | ||
304 | /** | ||
305 | * thrown in case of unsupported parameter encountered (e.g. unsupported | ||
306 | * association type). | ||
307 | */ | ||
308 | class unsupported : public exception { | ||
309 | public: | ||
310 | unsupported(OPKELE_E_PARS) | ||
311 | : exception(OPKELE_E_CONS) { } | ||
312 | }; | ||
313 | |||
233 | } | 314 | } |
234 | 315 | ||
235 | #endif /* __OPKELE_EXCEPTION_H */ | 316 | #endif /* __OPKELE_EXCEPTION_H */ |
diff --git a/include/opkele/expat.h b/include/opkele/expat.h new file mode 100644 index 0000000..60c41ac --- a/dev/null +++ b/include/opkele/expat.h | |||
@@ -0,0 +1,91 @@ | |||
1 | #ifndef __OPKELE_EXPAT_H | ||
2 | #define __OPKELE_EXPAT_H | ||
3 | |||
4 | #include <cassert> | ||
5 | #include <expat.h> | ||
6 | |||
7 | namespace opkele { | ||
8 | |||
9 | namespace util { | ||
10 | |||
11 | class expat_t { | ||
12 | public: | ||
13 | XML_Parser _x; | ||
14 | |||
15 | expat_t() : _x(0) { } | ||
16 | expat_t(XML_Parser x) : _x(x) { } | ||
17 | virtual ~expat_t() throw(); | ||
18 | |||
19 | expat_t& operator=(XML_Parser x); | ||
20 | |||
21 | operator const XML_Parser(void) const { return _x; } | ||
22 | operator XML_Parser(void) { return _x; } | ||
23 | |||
24 | inline bool parse(const char *s,int len,bool final=false) { | ||
25 | assert(_x); | ||
26 | return XML_Parse(_x,s,len,final); | ||
27 | } | ||
28 | |||
29 | virtual void start_element(const XML_Char *n,const XML_Char **a) { } | ||
30 | virtual void end_element(const XML_Char *n) { } | ||
31 | void set_element_handler(); | ||
32 | |||
33 | virtual void character_data(const XML_Char *s,int l) { } | ||
34 | void set_character_data_handler(); | ||
35 | |||
36 | virtual void processing_instruction(const XML_Char *t,const XML_Char *d) { } | ||
37 | void set_processing_instruction_handler(); | ||
38 | |||
39 | virtual void comment(const XML_Char *d) { } | ||
40 | void set_comment_handler(); | ||
41 | |||
42 | virtual void start_cdata_section() { } | ||
43 | virtual void end_cdata_section() { } | ||
44 | void set_cdata_section_handler(); | ||
45 | |||
46 | virtual void default_handler(const XML_Char *s,int l) { } | ||
47 | void set_default_handler(); | ||
48 | void set_default_handler_expand(); | ||
49 | |||
50 | virtual void start_namespace_decl(const XML_Char *p,const XML_Char *u) { } | ||
51 | virtual void end_namespace_decl(const XML_Char *p) { } | ||
52 | void set_namespace_decl_handler(); | ||
53 | |||
54 | inline enum XML_Error get_error_code() { | ||
55 | assert(_x); return XML_GetErrorCode(_x); } | ||
56 | static inline const XML_LChar *error_string(XML_Error c) { | ||
57 | return XML_ErrorString(c); } | ||
58 | |||
59 | inline long get_current_byte_index() { | ||
60 | assert(_x); return XML_GetCurrentByteIndex(_x); } | ||
61 | inline int get_current_line_number() { | ||
62 | assert(_x); return XML_GetCurrentLineNumber(_x); } | ||
63 | inline int get_current_column_number() { | ||
64 | assert(_x); return XML_GetCurrentColumnNumber(_x); } | ||
65 | |||
66 | inline void set_user_data() { | ||
67 | assert(_x); XML_SetUserData(_x,this); } | ||
68 | |||
69 | inline bool set_base(const XML_Char *b) { | ||
70 | assert(_x); return XML_SetBase(_x,b); } | ||
71 | inline const XML_Char *get_base() { | ||
72 | assert(_x); return XML_GetBase(_x); } | ||
73 | |||
74 | inline int get_specified_attribute_count() { | ||
75 | assert(_x); return XML_GetSpecifiedAttributeCount(_x); } | ||
76 | |||
77 | inline bool set_param_entity_parsing(enum XML_ParamEntityParsing c) { | ||
78 | assert(_x); return XML_SetParamEntityParsing(_x,c); } | ||
79 | |||
80 | inline static XML_Parser parser_create(const XML_Char *e=0) { | ||
81 | return XML_ParserCreate(e); } | ||
82 | inline static XML_Parser parser_create_ns(const XML_Char *e=0,XML_Char s='\t') { | ||
83 | return XML_ParserCreateNS(e,s); } | ||
84 | |||
85 | }; | ||
86 | |||
87 | } | ||
88 | |||
89 | } | ||
90 | |||
91 | #endif /* __OPKELE_EXPAT_H */ | ||
diff --git a/include/opkele/server.h b/include/opkele/server.h index dd7fc41..3c25646 100644 --- a/include/opkele/server.h +++ b/include/opkele/server.h | |||
@@ -25,7 +25,7 @@ namespace opkele { | |||
25 | * store. | 25 | * store. |
26 | * @param mode the mode of request being processed to base the | 26 | * @param mode the mode of request being processed to base the |
27 | * statelessness of the association upon | 27 | * statelessness of the association upon |
28 | * @return the auto_ptr<> for the newly allocated association_t object | 28 | * @return the assoc_t for the newly allocated association_t object |
29 | */ | 29 | */ |
30 | virtual assoc_t alloc_assoc(mode_t mode) = 0; | 30 | virtual assoc_t alloc_assoc(mode_t mode) = 0; |
31 | /** | 31 | /** |
@@ -33,7 +33,7 @@ namespace opkele { | |||
33 | * the reqal implementation to provide persistent assocations | 33 | * the reqal implementation to provide persistent assocations |
34 | * store. | 34 | * store. |
35 | * @param h association handle | 35 | * @param h association handle |
36 | * @return the auto_ptr<> for the newly allocated association_t object | 36 | * @return the assoc_t for the newly allocated association_t object |
37 | * @throw failed_lookup in case of failure | 37 | * @throw failed_lookup in case of failure |
38 | */ | 38 | */ |
39 | virtual assoc_t retrieve_assoc(const string& h) = 0; | 39 | virtual assoc_t retrieve_assoc(const string& h) = 0; |
diff --git a/include/opkele/tidy.h b/include/opkele/tidy.h new file mode 100644 index 0000000..888e7d4 --- a/dev/null +++ b/include/opkele/tidy.h | |||
@@ -0,0 +1,73 @@ | |||
1 | #ifndef __OPKELE_TIDY_H | ||
2 | #define __OPKELE_TIDY_H | ||
3 | |||
4 | #include <cassert> | ||
5 | #include <tidy.h> | ||
6 | #include <buffio.h> | ||
7 | |||
8 | namespace opkele { | ||
9 | namespace util { | ||
10 | |||
11 | class tidy_buf_t { | ||
12 | public: | ||
13 | TidyBuffer _x; | ||
14 | |||
15 | tidy_buf_t() { tidyBufInit(&_x); } | ||
16 | virtual ~tidy_buf_t() throw() { | ||
17 | tidyBufFree(&_x); } | ||
18 | |||
19 | inline operator const TidyBuffer&(void) const { return _x; } | ||
20 | inline operator TidyBuffer&(void) { return _x; } | ||
21 | |||
22 | inline operator const char*(void) const { return (const char*)_x.bp; } | ||
23 | inline operator char*(void) { return (char*)_x.bp; } | ||
24 | |||
25 | inline const char *c_str() const { | ||
26 | return (const char*)_x.bp; } | ||
27 | inline size_t size() const { | ||
28 | return _x.size; } | ||
29 | }; | ||
30 | |||
31 | class tidy_doc_t { | ||
32 | public: | ||
33 | TidyDoc _x; | ||
34 | |||
35 | tidy_doc_t() : _x(0) { } | ||
36 | tidy_doc_t(TidyDoc x) : _x(x) { } | ||
37 | virtual ~tidy_doc_t() throw() { | ||
38 | if(_x) tidyRelease(_x); } | ||
39 | |||
40 | tidy_doc_t& operator=(TidyDoc x) { | ||
41 | if(_x) tidyRelease(_x); | ||
42 | _x = x; | ||
43 | return *this; | ||
44 | } | ||
45 | |||
46 | operator const TidyDoc(void) const { return _x; } | ||
47 | operator TidyDoc(void) { return _x; } | ||
48 | |||
49 | inline bool opt_set(TidyOptionId o,bool v) { | ||
50 | assert(_x); | ||
51 | return tidyOptSetBool(_x,o,v?yes:no); } | ||
52 | inline bool opt_set(TidyOptionId o,int v) { | ||
53 | assert(_x); | ||
54 | return tidyOptSetInt(_x,o,v); } | ||
55 | |||
56 | inline int parse_string(const string& s) { | ||
57 | assert(_x); | ||
58 | return tidyParseString(_x,s.c_str()); } | ||
59 | inline int clean_and_repair() { | ||
60 | assert(_x); | ||
61 | return tidyCleanAndRepair(_x); } | ||
62 | inline int save_buffer(TidyBuffer& ob) { | ||
63 | assert(_x); | ||
64 | return tidySaveBuffer(_x,&ob); } | ||
65 | |||
66 | static inline TidyDoc create() { | ||
67 | return tidyCreate(); } | ||
68 | }; | ||
69 | |||
70 | } | ||
71 | } | ||
72 | |||
73 | #endif /* __OPKELE_TIDY_H */ | ||
diff --git a/include/opkele/tr1-mem.h.in b/include/opkele/tr1-mem.h.in new file mode 100644 index 0000000..e9ccf0b --- a/dev/null +++ b/include/opkele/tr1-mem.h.in | |||
@@ -0,0 +1,10 @@ | |||
1 | #ifndef __OPKELE_TR1_MEM_H | ||
2 | #define __OPKELE_TR1_MEM_H | ||
3 | |||
4 | #include <@OPKELE_TR1_MEM_HEADER@> | ||
5 | |||
6 | namespace opkele { | ||
7 | namespace tr1mem = @OPKELE_TR1_MEM_NS@; | ||
8 | } | ||
9 | |||
10 | #endif /* __OPKELE_TR1_MEM_H */ | ||
diff --git a/include/opkele/types.h b/include/opkele/types.h index f732a1e..de44a5c 100644 --- a/include/opkele/types.h +++ b/include/opkele/types.h | |||
@@ -10,14 +10,16 @@ | |||
10 | #include <vector> | 10 | #include <vector> |
11 | #include <string> | 11 | #include <string> |
12 | #include <map> | 12 | #include <map> |
13 | #include <memory> | 13 | #include <set> |
14 | #include <opkele/tr1-mem.h> | ||
14 | 15 | ||
15 | namespace opkele { | 16 | namespace opkele { |
16 | using std::vector; | 17 | using std::vector; |
17 | using std::string; | 18 | using std::string; |
18 | using std::map; | 19 | using std::map; |
19 | using std::ostream; | 20 | using std::ostream; |
20 | using std::auto_ptr; | 21 | using std::multimap; |
22 | using std::set; | ||
21 | 23 | ||
22 | /** | 24 | /** |
23 | * the OpenID operation mode | 25 | * the OpenID operation mode |
@@ -37,16 +39,16 @@ namespace opkele { | |||
37 | 39 | ||
38 | /** | 40 | /** |
39 | * xor the secret and hmac together and encode, using base64 | 41 | * xor the secret and hmac together and encode, using base64 |
40 | * @param key_sha1 pointer to the sha1 digest | 42 | * @param key_d pointer to the message digest |
41 | * @param rv reference to the return value | 43 | * @param rv reference to the return value |
42 | */ | 44 | */ |
43 | void enxor_to_base64(const unsigned char *key_sha1,string& rv) const; | 45 | void enxor_to_base64(const unsigned char *key_d,string& rv) const; |
44 | /** | 46 | /** |
45 | * decode base64-encoded secret and xor it with the sha1 digest | 47 | * decode base64-encoded secret and xor it with the message digest |
46 | * @param key_sha1 pointer to the message digest | 48 | * @param key_d pointer to the message digest |
47 | * @param b64 base64-encoded secret value | 49 | * @param b64 base64-encoded secret value |
48 | */ | 50 | */ |
49 | void enxor_from_base64(const unsigned char *key_sha1,const string& b64); | 51 | void enxor_from_base64(const unsigned char *key_d,const string& b64); |
50 | /** | 52 | /** |
51 | * plainly encode to base64 representation | 53 | * plainly encode to base64 representation |
52 | * @param rv reference to the return value | 54 | * @param rv reference to the return value |
@@ -105,9 +107,9 @@ namespace opkele { | |||
105 | }; | 107 | }; |
106 | 108 | ||
107 | /** | 109 | /** |
108 | * the auto_ptr<> for association_t object type | 110 | * the shared_ptr<> for association_t object type |
109 | */ | 111 | */ |
110 | typedef auto_ptr<association_t> assoc_t; | 112 | typedef tr1mem::shared_ptr<association_t> assoc_t; |
111 | 113 | ||
112 | /** | 114 | /** |
113 | * request/response parameters map | 115 | * request/response parameters map |
@@ -158,6 +160,14 @@ namespace opkele { | |||
158 | * @return the ready-to-use location | 160 | * @return the ready-to-use location |
159 | */ | 161 | */ |
160 | string append_query(const string& url,const char *prefix = "openid.") const; | 162 | string append_query(const string& url,const char *prefix = "openid.") const; |
163 | |||
164 | /** | ||
165 | * make up a query string suitable for use in GET and POST | ||
166 | * requests. | ||
167 | * @param prefix string to prened to parameter names | ||
168 | * @return query string | ||
169 | */ | ||
170 | string query_string(const char *prefix = "openid.") const; | ||
161 | }; | 171 | }; |
162 | 172 | ||
163 | /** | 173 | /** |
@@ -167,6 +177,70 @@ namespace opkele { | |||
167 | */ | 177 | */ |
168 | ostream& operator << (ostream& o,const params_t& p); | 178 | ostream& operator << (ostream& o,const params_t& p); |
169 | 179 | ||
180 | namespace xrd { | ||
181 | |||
182 | struct priority_compare { | ||
183 | inline bool operator()(long a,long b) const { | ||
184 | return (a<0) ? false : (b<0) ? true : (a<b); | ||
185 | } | ||
186 | }; | ||
187 | |||
188 | template <typename _DT> | ||
189 | class priority_map : public multimap<long,_DT,priority_compare> { | ||
190 | typedef multimap<long,_DT,priority_compare> map_type; | ||
191 | public: | ||
192 | |||
193 | inline _DT& add(long priority,const _DT& d) { | ||
194 | return insert(typename map_type::value_type(priority,d))->second; | ||
195 | } | ||
196 | }; | ||
197 | |||
198 | typedef priority_map<string> canonical_ids_t; | ||
199 | typedef priority_map<string> local_ids_t; | ||
200 | typedef set<string> types_t; | ||
201 | typedef priority_map<string> uris_t; | ||
202 | |||
203 | class service_t { | ||
204 | public: | ||
205 | types_t types; | ||
206 | uris_t uris; | ||
207 | local_ids_t local_ids; | ||
208 | string provider_id; | ||
209 | |||
210 | void clear() { | ||
211 | types.clear(); | ||
212 | uris.clear(); local_ids.clear(); | ||
213 | provider_id.clear(); | ||
214 | } | ||
215 | }; | ||
216 | typedef priority_map<service_t> services_t; | ||
217 | |||
218 | class XRD_t { | ||
219 | public: | ||
220 | time_t expires; | ||
221 | |||
222 | canonical_ids_t canonical_ids; | ||
223 | local_ids_t local_ids; | ||
224 | services_t services; | ||
225 | string provider_id; | ||
226 | |||
227 | void clear() { | ||
228 | expires = 0; | ||
229 | canonical_ids.clear(); local_ids.clear(); | ||
230 | services.clear(); | ||
231 | provider_id.clear(); | ||
232 | } | ||
233 | bool empty() const { | ||
234 | return | ||
235 | canonical_ids.empty() | ||
236 | && local_ids.empty() | ||
237 | && services.empty(); | ||
238 | } | ||
239 | |||
240 | }; | ||
241 | |||
242 | } | ||
243 | |||
170 | } | 244 | } |
171 | 245 | ||
172 | #endif /* __OPKELE_TYPES_H */ | 246 | #endif /* __OPKELE_TYPES_H */ |
diff --git a/include/opkele/uris.h b/include/opkele/uris.h new file mode 100644 index 0000000..56c2d6d --- a/dev/null +++ b/include/opkele/uris.h | |||
@@ -0,0 +1,18 @@ | |||
1 | #ifndef __OPKELE_URIS_H | ||
2 | #define __OPKELE_URIS_H | ||
3 | |||
4 | #define NSURI_XRDS "xri://$xrds" | ||
5 | #define NSURI_XRD "xri://$xrd*($v*2.0)" | ||
6 | #define NSURI_OPENID10 "http://openid.net/xmlns/1.0" | ||
7 | |||
8 | #define OIURI_OPENID20 "http://specs.openid.net/auth/2.0" | ||
9 | #define OIURI_SREG11 "http://openid.net/extensions/sreg/1.1" | ||
10 | |||
11 | #define STURI_OPENID10 "http://openid.net/signon/1.0" | ||
12 | #define STURI_OPENID11 "http://openid.net/signon/1.1" | ||
13 | #define STURI_OPENID20 "http://specs.openid.net/auth/2.0/signon" | ||
14 | #define STURI_OPENID20_OP"http://specs.openid.net/auth/2.0/server" | ||
15 | |||
16 | #define IDURI_SELECT20 "http://specs.openid.net/auth/2.0/identifier_select" | ||
17 | |||
18 | #endif /* __OPKELE_URIS_H */ | ||
diff --git a/lib/Makefile.am b/lib/Makefile.am index 0fe705a..989de28 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am | |||
@@ -1,16 +1,18 @@ | |||
1 | lib_LTLIBRARIES = libopkele.la | 1 | lib_LTLIBRARIES = libopkele.la |
2 | 2 | ||
3 | AM_CPPFLAGS = ${CPPFLAGS_DEBUG} | ||
4 | DEFAULT_INCLUDES = -I${top_builddir} | ||
3 | INCLUDES = \ | 5 | INCLUDES = \ |
4 | -I${top_srcdir}/include/ \ | 6 | -I${top_srcdir}/include/ \ |
5 | ${KONFORKA_CFLAGS} \ | 7 | ${KONFORKA_CFLAGS} \ |
6 | ${OPENSSL_CFLAGS} \ | 8 | ${OPENSSL_CFLAGS} \ |
7 | ${LIBCURL_CPPFLAGS} \ | 9 | ${LIBCURL_CPPFLAGS} \ |
8 | ${PCRE_CFLAGS} | 10 | ${PCRE_CFLAGS} ${EXPAT_CFLAGS} ${TIDY_CFLAGS} |
9 | libopkele_la_LIBADD = \ | 11 | libopkele_la_LIBADD = \ |
10 | ${LIBCURL} \ | 12 | ${LIBCURL} \ |
11 | ${PCRE_LIBS} \ | 13 | ${PCRE_LIBS} ${EXPAT_LIBS} \ |
12 | ${OPENSSL_LIBS} \ | 14 | ${OPENSSL_LIBS} \ |
13 | ${KONFORKA_LIBS} | 15 | ${KONFORKA_LIBS} ${TIDY_LIBS} |
14 | 16 | ||
15 | libopkele_la_SOURCES = \ | 17 | libopkele_la_SOURCES = \ |
16 | params.cc \ | 18 | params.cc \ |
@@ -23,6 +25,7 @@ libopkele_la_SOURCES = \ | |||
23 | extension.cc \ | 25 | extension.cc \ |
24 | sreg.cc \ | 26 | sreg.cc \ |
25 | extension_chain.cc \ | 27 | extension_chain.cc \ |
26 | curl.cc | 28 | curl.cc expat.cc \ |
29 | discovery.cc | ||
27 | libopkele_la_LDFLAGS = \ | 30 | libopkele_la_LDFLAGS = \ |
28 | -version-info 2:0:0 | 31 | -version-info 2:0:0 |
diff --git a/lib/consumer.cc b/lib/consumer.cc index 9f7530f..3c3b4f8 100644 --- a/lib/consumer.cc +++ b/lib/consumer.cc | |||
@@ -17,25 +17,7 @@ | |||
17 | namespace opkele { | 17 | namespace opkele { |
18 | using namespace std; | 18 | using namespace std; |
19 | using util::curl_t; | 19 | using util::curl_t; |
20 | 20 | using util::curl_pick_t; | |
21 | template<int lim> | ||
22 | class curl_fetch_string_t : public curl_t { | ||
23 | public: | ||
24 | curl_fetch_string_t(CURL *c) | ||
25 | : curl_t(c) { } | ||
26 | ~curl_fetch_string_t() throw() { } | ||
27 | |||
28 | string response; | ||
29 | |||
30 | size_t write(void *p,size_t size,size_t nmemb) { | ||
31 | size_t bytes = size*nmemb; | ||
32 | size_t get = min(lim-response.length(),bytes); | ||
33 | response.append((const char *)p,get); | ||
34 | return get; | ||
35 | } | ||
36 | }; | ||
37 | |||
38 | typedef curl_fetch_string_t<16384> curl_pick_t; | ||
39 | 21 | ||
40 | class pcre_matches_t { | 22 | class pcre_matches_t { |
41 | public: | 23 | public: |
diff --git a/lib/discovery.cc b/lib/discovery.cc new file mode 100644 index 0000000..d868308 --- a/dev/null +++ b/lib/discovery.cc | |||
@@ -0,0 +1,446 @@ | |||
1 | #include <list> | ||
2 | #include <opkele/curl.h> | ||
3 | #include <opkele/expat.h> | ||
4 | #include <opkele/uris.h> | ||
5 | #include <opkele/discovery.h> | ||
6 | #include <opkele/exception.h> | ||
7 | #include <opkele/util.h> | ||
8 | #include <opkele/tidy.h> | ||
9 | #include <opkele/debug.h> | ||
10 | |||
11 | #include "config.h" | ||
12 | |||
13 | #define XRDS_HEADER "X-XRDS-Location" | ||
14 | #define CT_HEADER "Content-Type" | ||
15 | |||
16 | namespace opkele { | ||
17 | using std::list; | ||
18 | using xrd::XRD_t; | ||
19 | using xrd::service_t; | ||
20 | |||
21 | static const char *whitespace = " \t\r\n"; | ||
22 | static const char *i_leaders = "=@+$!("; | ||
23 | static const size_t max_html = 16384; | ||
24 | |||
25 | static inline bool is_qelement(const XML_Char *n,const char *qen) { | ||
26 | return !strcasecmp(n,qen); | ||
27 | } | ||
28 | static inline bool is_element(const XML_Char *n,const char *en) { | ||
29 | if(!strcasecmp(n,en)) return true; | ||
30 | int nl = strlen(n), enl = strlen(en); | ||
31 | if( (nl>=(enl+1)) && n[nl-enl-1]=='\t' | ||
32 | && !strcasecmp(&n[nl-enl],en) ) | ||
33 | return true; | ||
34 | return false; | ||
35 | } | ||
36 | |||
37 | static long element_priority(const XML_Char **a) { | ||
38 | for(;*a;++a) | ||
39 | if(!strcasecmp(*(a++),"priority")) { | ||
40 | long rv; | ||
41 | return (sscanf(*a,"%ld",&rv)==1)?rv:-1; | ||
42 | } | ||
43 | return -1; | ||
44 | } | ||
45 | |||
46 | class idigger_t : public util::curl_t, public util::expat_t { | ||
47 | public: | ||
48 | string xri_proxy; | ||
49 | |||
50 | enum { | ||
51 | xmode_html = 1, xmode_xrd = 2 | ||
52 | }; | ||
53 | int xmode; | ||
54 | |||
55 | string xrds_location; | ||
56 | string http_content_type; | ||
57 | service_t html_openid1; | ||
58 | service_t html_openid2; | ||
59 | string cdata_buf; | ||
60 | long status_code; | ||
61 | string status_string; | ||
62 | |||
63 | typedef list<string> pt_stack_t; | ||
64 | pt_stack_t pt_stack; | ||
65 | int skipping; | ||
66 | bool parser_choked; | ||
67 | string save_html; | ||
68 | |||
69 | XRD_t *xrd; | ||
70 | service_t *xrd_service; | ||
71 | string* cdata; | ||
72 | |||
73 | idigger_t() | ||
74 | : util::curl_t(easy_init()), | ||
75 | util::expat_t(0), | ||
76 | xri_proxy(XRI_PROXY_URL) { | ||
77 | CURLcode r; | ||
78 | (r=misc_sets()) | ||
79 | || (r=set_write()) | ||
80 | || (r=set_header()) | ||
81 | ; | ||
82 | if(r) | ||
83 | throw exception_curl(OPKELE_CP_ "failed to set curly options",r); | ||
84 | } | ||
85 | ~idigger_t() throw() { } | ||
86 | |||
87 | void discover(idiscovery_t& result,const string& identity) { | ||
88 | result.clear(); | ||
89 | string::size_type fsc = identity.find_first_not_of(whitespace); | ||
90 | if(fsc==string::npos) | ||
91 | throw bad_input(OPKELE_CP_ "whtiespace-only identity"); | ||
92 | string::size_type lsc = identity.find_last_not_of(whitespace); | ||
93 | assert(lsc!=string::npos); | ||
94 | if(!strncasecmp(identity.c_str()+fsc,"xri://",sizeof("xri://")-1)) | ||
95 | fsc += sizeof("xri://")-1; | ||
96 | if((fsc+1)>=lsc) | ||
97 | throw bad_input(OPKELE_CP_ "not a character of importance in identity"); | ||
98 | string id(identity,fsc,lsc-fsc+1); | ||
99 | if(strchr(i_leaders,id[0])) { | ||
100 | result.normalized_id = id; | ||
101 | result.xri_identity = true; | ||
102 | /* TODO: further canonicalize xri identity? Like folding case or whatever... */ | ||
103 | discover_at( | ||
104 | result, | ||
105 | xri_proxy + util::url_encode(id)+ | ||
106 | "?_xrd_r=application/xrd+xml;sep=false", xmode_xrd); | ||
107 | if(status_code!=100) | ||
108 | throw failed_xri_resolution(OPKELE_CP_ | ||
109 | "XRI resolution failed with '"+status_string+"' message",status_code); | ||
110 | if(result.xrd.canonical_ids.empty()) | ||
111 | throw opkele::failed_discovery(OPKELE_CP_ "No CanonicalID for XRI identity found"); | ||
112 | result.canonicalized_id = result.xrd.canonical_ids.begin()->second; | ||
113 | }else{ | ||
114 | result.xri_identity = false; | ||
115 | if(id.find("://")==string::npos) | ||
116 | id.insert(0,"http://"); | ||
117 | string::size_type fp = id.find('#'); | ||
118 | if(fp!=string::npos) { | ||
119 | string::size_type qp = id.find('?'); | ||
120 | if(qp==string::npos || qp<fp) | ||
121 | id.erase(fp); | ||
122 | else if(qp>fp) | ||
123 | id.erase(fp,qp-fp); | ||
124 | } | ||
125 | result.normalized_id = util::rfc_3986_normalize_uri(id); | ||
126 | discover_at(result,id,xmode_html|xmode_xrd); | ||
127 | const char * eu = 0; | ||
128 | CURLcode r = easy_getinfo(CURLINFO_EFFECTIVE_URL,&eu); | ||
129 | if(r) | ||
130 | throw exception_curl(OPKELE_CP_ "failed to get CURLINFO_EFFECTIVE_URL",r); | ||
131 | result.canonicalized_id = util::rfc_3986_normalize_uri(eu); /* XXX: strip fragment part? */ | ||
132 | if(xrds_location.empty()) { | ||
133 | html2xrd(result.xrd); | ||
134 | }else{ | ||
135 | discover_at(result,xrds_location,xmode_xrd); | ||
136 | if(result.xrd.empty()) | ||
137 | html2xrd(result.xrd); | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | |||
142 | void discover_at(idiscovery_t& result,const string& url,int xm) { | ||
143 | CURLcode r = easy_setopt(CURLOPT_URL,url.c_str()); | ||
144 | if(r) | ||
145 | throw exception_curl(OPKELE_CP_ "failed to set culry urlie",r); | ||
146 | |||
147 | http_content_type.clear(); | ||
148 | xmode = xm; | ||
149 | prepare_to_parse(); | ||
150 | if(xmode&xmode_html) { | ||
151 | xrds_location.clear(); | ||
152 | save_html.clear(); | ||
153 | save_html.reserve(max_html); | ||
154 | } | ||
155 | xrd = &result.xrd; | ||
156 | |||
157 | r = easy_perform(); | ||
158 | if(r && r!=CURLE_WRITE_ERROR) | ||
159 | throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); | ||
160 | |||
161 | if(!parser_choked) { | ||
162 | parse(0,0,true); | ||
163 | }else{ | ||
164 | /* TODO: do not bother if we've seen xml */ | ||
165 | try { | ||
166 | util::tidy_doc_t td = util::tidy_doc_t::create(); | ||
167 | if(!td) | ||
168 | throw exception_tidy(OPKELE_CP_ "failed to create htmltidy document"); | ||
169 | #ifndef NDEBUG | ||
170 | td.opt_set(TidyQuiet,false); | ||
171 | td.opt_set(TidyShowWarnings,false); | ||
172 | #endif /* NDEBUG */ | ||
173 | td.opt_set(TidyForceOutput,true); | ||
174 | td.opt_set(TidyXhtmlOut,true); | ||
175 | td.opt_set(TidyDoctypeMode,TidyDoctypeOmit); | ||
176 | td.opt_set(TidyMark,false); | ||
177 | if(td.parse_string(save_html)<=0) | ||
178 | throw exception_tidy(OPKELE_CP_ "tidy failed to parse document"); | ||
179 | if(td.clean_and_repair()<=0) | ||
180 | throw exception_tidy(OPKELE_CP_ "tidy failed to clean and repair"); | ||
181 | util::tidy_buf_t tide; | ||
182 | if(td.save_buffer(tide)<=0) | ||
183 | throw exception_tidy(OPKELE_CP_ "tidy failed to save buffer"); | ||
184 | prepare_to_parse(); | ||
185 | parse(tide.c_str(),tide.size(),true); | ||
186 | }catch(exception_tidy& et) { } | ||
187 | } | ||
188 | save_html.clear(); | ||
189 | } | ||
190 | |||
191 | void prepare_to_parse() { | ||
192 | (*(expat_t*)this) = parser_create_ns(); | ||
193 | set_user_data(); set_element_handler(); | ||
194 | set_character_data_handler(); | ||
195 | |||
196 | if(xmode&xmode_html) { | ||
197 | html_openid1.clear(); html_openid2.clear(); | ||
198 | parser_choked = false; | ||
199 | } | ||
200 | |||
201 | cdata = 0; xrd_service = 0; skipping = 0; | ||
202 | status_code = 100; status_string.clear(); | ||
203 | } | ||
204 | |||
205 | void html2xrd(XRD_t& x) { | ||
206 | if(!html_openid1.uris.empty()) { | ||
207 | html_openid1.types.insert(STURI_OPENID11); | ||
208 | x.services.add(-1,html_openid1); | ||
209 | } | ||
210 | if(!html_openid2.uris.empty()) { | ||
211 | html_openid2.types.insert(STURI_OPENID20); | ||
212 | x.services.add(-1,html_openid2); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | size_t write(void *p,size_t s,size_t nm) { | ||
217 | /* TODO: limit total size */ | ||
218 | size_t bytes = s*nm; | ||
219 | const char *inbuf = (const char*)p; | ||
220 | if(xmode&xmode_html) { | ||
221 | size_t mbts = save_html.capacity()-save_html.size(); | ||
222 | size_t bts = 0; | ||
223 | if(mbts>0) { | ||
224 | bts = (bytes>mbts)?mbts:bytes; | ||
225 | save_html.append(inbuf,bts); | ||
226 | } | ||
227 | if(skipping<0) return bts; | ||
228 | } | ||
229 | if(skipping<0) return 0; | ||
230 | bool rp = parse(inbuf,bytes,false); | ||
231 | if(!rp) { | ||
232 | parser_choked = true; | ||
233 | skipping = -1; | ||
234 | if(!(xmode&xmode_html)) | ||
235 | bytes = 0; | ||
236 | } | ||
237 | return bytes; | ||
238 | } | ||
239 | size_t header(void *p,size_t s,size_t nm) { | ||
240 | size_t bytes = s*nm; | ||
241 | const char *h = (const char*)p; | ||
242 | const char *colon = (const char*)memchr(p,':',bytes); | ||
243 | const char *space = (const char*)memchr(p,' ',bytes); | ||
244 | if(space && ( (!colon) || space<colon ) ) { | ||
245 | xrds_location.clear(); http_content_type.clear(); | ||
246 | }else if(colon) { | ||
247 | const char *hv = ++colon; | ||
248 | int hnl = colon-h; | ||
249 | int rb; | ||
250 | for(rb = bytes-hnl-1;rb>0 && isspace(*hv);++hv,--rb); | ||
251 | while(rb>0 && isspace(hv[rb-1])) --rb; | ||
252 | if(rb) { | ||
253 | if( (hnl>=sizeof(XRDS_HEADER)) | ||
254 | && !strncasecmp(h,XRDS_HEADER":", | ||
255 | sizeof(XRDS_HEADER)) ) { | ||
256 | xrds_location.assign(hv,rb); | ||
257 | }else if( (hnl>=sizeof(CT_HEADER)) | ||
258 | && !strncasecmp(h,CT_HEADER":", | ||
259 | sizeof(CT_HEADER)) ) { | ||
260 | const char *sc = (const char*)memchr( | ||
261 | hv,';',rb); | ||
262 | http_content_type.assign(hv,sc?(sc-hv):rb); | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | return curl_t::header(p,s,nm); | ||
267 | } | ||
268 | |||
269 | void start_element(const XML_Char *n,const XML_Char **a) { | ||
270 | if(skipping<0) return; | ||
271 | if(skipping) { | ||
272 | if(xmode&xmode_html) | ||
273 | html_start_element(n,a); | ||
274 | ++skipping; return; | ||
275 | } | ||
276 | if(pt_stack.empty()) { | ||
277 | if(is_qelement(n,NSURI_XRDS "\tXRDS")) | ||
278 | return; | ||
279 | if(is_qelement(n,NSURI_XRD "\tXRD")) { | ||
280 | assert(xrd); | ||
281 | xrd->clear(); | ||
282 | pt_stack.push_back(n); | ||
283 | }else if(xmode&xmode_html) { | ||
284 | html_start_element(n,a); | ||
285 | }else{ | ||
286 | skipping = -1; | ||
287 | } | ||
288 | }else{ | ||
289 | int pt_s = pt_stack.size(); | ||
290 | if(pt_s==1) { | ||
291 | if(is_qelement(n,NSURI_XRD "\tCanonicalID")) { | ||
292 | assert(xrd); | ||
293 | cdata = &(xrd->canonical_ids.add(element_priority(a),string())); | ||
294 | }else if(is_qelement(n,NSURI_XRD "\tLocalID")) { | ||
295 | assert(xrd); | ||
296 | cdata = &(xrd->local_ids.add(element_priority(a),string())); | ||
297 | }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { | ||
298 | assert(xrd); | ||
299 | cdata = &(xrd->provider_id); | ||
300 | }else if(is_qelement(n,NSURI_XRD "\tService")) { | ||
301 | assert(xrd); | ||
302 | xrd_service = &(xrd->services.add(element_priority(a), | ||
303 | service_t())); | ||
304 | pt_stack.push_back(n); | ||
305 | }else if(is_qelement(n,NSURI_XRD "\tStatus")) { | ||
306 | for(;*a;) { | ||
307 | if(!strcasecmp(*(a++),"code")) { | ||
308 | if(sscanf(*(a++),"%ld",&status_code)==1 && status_code!=100) { | ||
309 | cdata = &status_string; | ||
310 | pt_stack.push_back(n); | ||
311 | break; | ||
312 | } | ||
313 | } | ||
314 | } | ||
315 | }else if(is_qelement(n,NSURI_XRD "\tExpires")) { | ||
316 | assert(xrd); | ||
317 | cdata_buf.clear(); | ||
318 | cdata = &cdata_buf; | ||
319 | }else if(xmode&xmode_html) { | ||
320 | html_start_element(n,a); | ||
321 | }else{ | ||
322 | skipping = 1; | ||
323 | } | ||
324 | }else if(pt_s==2) { | ||
325 | if(is_qelement(pt_stack.back().c_str(), NSURI_XRD "\tService")) { | ||
326 | if(is_qelement(n,NSURI_XRD "\tType")) { | ||
327 | assert(xrd); assert(xrd_service); | ||
328 | cdata_buf.clear(); | ||
329 | cdata = &cdata_buf; | ||
330 | }else if(is_qelement(n,NSURI_XRD "\tURI")) { | ||
331 | assert(xrd); assert(xrd_service); | ||
332 | cdata = &(xrd_service->uris.add(element_priority(a),string())); | ||
333 | }else if(is_qelement(n,NSURI_XRD "\tLocalID") | ||
334 | || is_qelement(n,NSURI_OPENID10 "\tDelegate") ) { | ||
335 | assert(xrd); assert(xrd_service); | ||
336 | cdata = &(xrd_service->local_ids.add(element_priority(a),string())); | ||
337 | }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { | ||
338 | assert(xrd); assert(xrd_service); | ||
339 | cdata = &(xrd_service->provider_id); | ||
340 | }else{ | ||
341 | skipping = 1; | ||
342 | } | ||
343 | }else | ||
344 | skipping = 1; | ||
345 | }else if(xmode&xmode_html) { | ||
346 | html_start_element(n,a); | ||
347 | }else{ | ||
348 | skipping = 1; | ||
349 | } | ||
350 | } | ||
351 | } | ||
352 | void end_element(const XML_Char *n) { | ||
353 | if(skipping<0) return; | ||
354 | if(skipping) { | ||
355 | --skipping; return; | ||
356 | } | ||
357 | if(is_qelement(n,NSURI_XRD "\tType")) { | ||
358 | assert(xrd); assert(xrd_service); assert(cdata==&cdata_buf); | ||
359 | xrd_service->types.insert(cdata_buf); | ||
360 | }else if(is_qelement(n,NSURI_XRD "\tService")) { | ||
361 | assert(xrd); assert(xrd_service); | ||
362 | assert(!pt_stack.empty()); | ||
363 | assert(pt_stack.back()==(NSURI_XRD "\tService")); | ||
364 | pt_stack.pop_back(); | ||
365 | xrd_service = 0; | ||
366 | }else if(is_qelement(n,NSURI_XRD "\tStatus")) { | ||
367 | assert(xrd); | ||
368 | if(is_qelement(pt_stack.back().c_str(),n)) { | ||
369 | assert(cdata==&status_string); | ||
370 | pt_stack.pop_back(); | ||
371 | if(status_code!=100) | ||
372 | skipping = -1; | ||
373 | } | ||
374 | }else if(is_qelement(n,NSURI_XRD "\tExpires")) { | ||
375 | assert(xrd); | ||
376 | xrd->expires = util::w3c_to_time(cdata_buf); | ||
377 | }else if((xmode&xmode_html) && is_element(n,"head")) { | ||
378 | skipping = -1; | ||
379 | } | ||
380 | cdata = 0; | ||
381 | } | ||
382 | void character_data(const XML_Char *s,int l) { | ||
383 | if(skipping) return; | ||
384 | if(cdata) cdata->append(s,l); | ||
385 | } | ||
386 | |||
387 | void html_start_element(const XML_Char *n,const XML_Char **a) { | ||
388 | if(is_element(n,"meta")) { | ||
389 | bool heq = false; | ||
390 | string l; | ||
391 | for(;*a;a+=2) { | ||
392 | if(!( strcasecmp(a[0],"http-equiv") | ||
393 | || strcasecmp(a[1],XRDS_HEADER) )) | ||
394 | heq = true; | ||
395 | else if(!strcasecmp(a[0],"content")) | ||
396 | l.assign(a[1]); | ||
397 | } | ||
398 | if(heq) | ||
399 | xrds_location = l; | ||
400 | }else if(is_element(n,"link")) { | ||
401 | string rels; | ||
402 | string href; | ||
403 | for(;*a;a+=2) { | ||
404 | if( !strcasecmp(a[0],"rel") ) { | ||
405 | rels.assign(a[1]); | ||
406 | }else if( !strcasecmp(a[0],"href") ) { | ||
407 | const char *ns = a[1]; | ||
408 | for(;*ns && isspace(*ns);++ns); | ||
409 | href.assign(ns); | ||
410 | string::size_type lns=href.find_last_not_of(whitespace); | ||
411 | href.erase(lns+1); | ||
412 | } | ||
413 | } | ||
414 | for(string::size_type ns=rels.find_first_not_of(whitespace); | ||
415 | ns!=string::npos; ns=rels.find_first_not_of(whitespace,ns)) { | ||
416 | string::size_type s = rels.find_first_of(whitespace,ns); | ||
417 | string rel; | ||
418 | if(s==string::npos) { | ||
419 | rel.assign(rels,ns,string::npos); | ||
420 | ns = string::npos; | ||
421 | }else{ | ||
422 | rel.assign(rels,ns,s-ns); | ||
423 | ns = s; | ||
424 | } | ||
425 | if(rel=="openid.server") | ||
426 | html_openid1.uris.add(-1,href); | ||
427 | else if(rel=="openid.delegate") | ||
428 | html_openid1.local_ids.add(-1,href); | ||
429 | else if(rel=="openid2.provider") | ||
430 | html_openid2.uris.add(-1,href); | ||
431 | else if(rel=="openid2.local_id") | ||
432 | html_openid2.local_ids.add(-1,href); | ||
433 | } | ||
434 | }else if(is_element(n,"body")) { | ||
435 | skipping = -1; | ||
436 | } | ||
437 | } | ||
438 | |||
439 | }; | ||
440 | |||
441 | void idiscover(idiscovery_t& result,const string& identity) { | ||
442 | idigger_t idigger; | ||
443 | idigger.discover(result,identity); | ||
444 | } | ||
445 | |||
446 | } | ||
diff --git a/lib/exception.cc b/lib/exception.cc index 510982e..e32594b 100644 --- a/lib/exception.cc +++ b/lib/exception.cc | |||
@@ -1,17 +1,33 @@ | |||
1 | #include <openssl/err.h> | 1 | #include <openssl/err.h> |
2 | #include <curl/curl.h> | 2 | #include <curl/curl.h> |
3 | #include <opkele/exception.h> | 3 | #include <opkele/exception.h> |
4 | #include <opkele/debug.h> | ||
4 | 5 | ||
5 | namespace opkele { | 6 | namespace opkele { |
6 | 7 | ||
7 | # ifndef OPKELE_HAVE_KONFORKA | 8 | # ifndef OPKELE_HAVE_KONFORKA |
8 | 9 | ||
10 | exception::exception(const string& w) | ||
11 | : _what(w) | ||
12 | { | ||
13 | DOUT_("throwing exception(\""<<w<<"\")"); | ||
14 | } | ||
15 | |||
9 | exception::~exception() throw() { | 16 | exception::~exception() throw() { |
10 | } | 17 | } |
11 | const char *exception::what() const throw() { | 18 | const char *exception::what() const throw() { |
12 | return _what.c_str(); | 19 | return _what.c_str(); |
13 | } | 20 | } |
21 | |||
22 | # else | ||
14 | 23 | ||
24 | exception::exception(const string& fi,const string& fu,int l,const string& w) | ||
25 | : konforka::exception(fi,fu,l,w) | ||
26 | { | ||
27 | DOUT_("throwing exception(\""<<w<<"\")"); | ||
28 | DOUT_(" from "<<fi<<':'<<fu<<':'<<l); | ||
29 | } | ||
30 | |||
15 | # endif | 31 | # endif |
16 | 32 | ||
17 | exception_openssl::exception_openssl(OPKELE_E_PARS) | 33 | exception_openssl::exception_openssl(OPKELE_E_PARS) |
@@ -26,4 +42,10 @@ namespace opkele { | |||
26 | : exception_network(OPKELE_E_CONS_ w+" ["+curl_easy_strerror(e)+']'), | 42 | : exception_network(OPKELE_E_CONS_ w+" ["+curl_easy_strerror(e)+']'), |
27 | _error(e), _curl_string(curl_easy_strerror(e)) { } | 43 | _error(e), _curl_string(curl_easy_strerror(e)) { } |
28 | 44 | ||
45 | exception_tidy::exception_tidy(OPKELE_E_PARS) | ||
46 | : exception(OPKELE_E_CONS), _rc(0) { } | ||
47 | exception_tidy::exception_tidy(OPKELE_E_PARS,int r) | ||
48 | : exception(OPKELE_E_CONS), | ||
49 | _rc(r) { } | ||
50 | |||
29 | } | 51 | } |
diff --git a/lib/expat.cc b/lib/expat.cc new file mode 100644 index 0000000..fa6fdde --- a/dev/null +++ b/lib/expat.cc | |||
@@ -0,0 +1,96 @@ | |||
1 | #include <opkele/expat.h> | ||
2 | |||
3 | namespace opkele { | ||
4 | |||
5 | namespace util { | ||
6 | |||
7 | expat_t::~expat_t() throw() { | ||
8 | if(_x) | ||
9 | XML_ParserFree(_x); | ||
10 | } | ||
11 | |||
12 | expat_t& expat_t::operator=(XML_Parser x) { | ||
13 | if(_x) | ||
14 | XML_ParserFree(_x); | ||
15 | _x = x; | ||
16 | } | ||
17 | |||
18 | static void _start_element(void* ud,const XML_Char *n,const XML_Char **a) { | ||
19 | ((expat_t*)ud)->start_element(n,a); | ||
20 | } | ||
21 | static void _end_element(void *ud,const XML_Char *n) { | ||
22 | ((expat_t*)ud)->end_element(n); | ||
23 | } | ||
24 | |||
25 | void expat_t::set_element_handler() { | ||
26 | assert(_x); | ||
27 | XML_SetElementHandler(_x,_start_element,_end_element); | ||
28 | } | ||
29 | |||
30 | static void _character_data(void *ud,const XML_Char *s,int l) { | ||
31 | ((expat_t*)ud)->character_data(s,l); | ||
32 | } | ||
33 | |||
34 | void expat_t::set_character_data_handler() { | ||
35 | assert(_x); | ||
36 | XML_SetCharacterDataHandler(_x,_character_data); | ||
37 | } | ||
38 | |||
39 | static void _processing_instruction(void *ud,const XML_Char *t,const XML_Char *d) { | ||
40 | ((expat_t*)ud)->processing_instruction(t,d); | ||
41 | } | ||
42 | |||
43 | void expat_t::set_processing_instruction_handler() { | ||
44 | assert(_x); | ||
45 | XML_SetProcessingInstructionHandler(_x,_processing_instruction); | ||
46 | } | ||
47 | |||
48 | static void _comment(void *ud,const XML_Char *d) { | ||
49 | ((expat_t*)ud)->comment(d); | ||
50 | } | ||
51 | |||
52 | void expat_t::set_comment_handler() { | ||
53 | assert(_x); | ||
54 | XML_SetCommentHandler(_x,_comment); | ||
55 | } | ||
56 | |||
57 | static void _start_cdata_section(void *ud) { | ||
58 | ((expat_t*)ud)->start_cdata_section(); | ||
59 | } | ||
60 | static void _end_cdata_section(void *ud) { | ||
61 | ((expat_t*)ud)->end_cdata_section(); | ||
62 | } | ||
63 | |||
64 | void expat_t::set_cdata_section_handler() { | ||
65 | assert(_x); | ||
66 | XML_SetCdataSectionHandler(_x,_start_cdata_section,_end_cdata_section); | ||
67 | } | ||
68 | |||
69 | static void _default_handler(void *ud,const XML_Char *s,int l) { | ||
70 | ((expat_t*)ud)->default_handler(s,l); | ||
71 | } | ||
72 | |||
73 | void expat_t::set_default_handler() { | ||
74 | assert(_x); | ||
75 | XML_SetDefaultHandler(_x,_default_handler); | ||
76 | } | ||
77 | void expat_t::set_default_handler_expand() { | ||
78 | assert(_x); | ||
79 | XML_SetDefaultHandlerExpand(_x,_default_handler); | ||
80 | } | ||
81 | |||
82 | static void _start_namespace_decl(void *ud,const XML_Char *p,const XML_Char *u) { | ||
83 | ((expat_t*)ud)->start_namespace_decl(p,u); | ||
84 | } | ||
85 | static void _end_namespace_decl(void *ud,const XML_Char *p) { | ||
86 | ((expat_t*)ud)->end_namespace_decl(p); | ||
87 | } | ||
88 | |||
89 | void expat_t::set_namespace_decl_handler() { | ||
90 | assert(_x); | ||
91 | XML_SetNamespaceDeclHandler(_x,_start_namespace_decl,_end_namespace_decl); | ||
92 | } | ||
93 | |||
94 | } | ||
95 | |||
96 | } | ||
diff --git a/lib/params.cc b/lib/params.cc index ea86d3a..7a572c1 100644 --- a/lib/params.cc +++ b/lib/params.cc | |||
@@ -99,6 +99,19 @@ namespace opkele { | |||
99 | return rv; | 99 | return rv; |
100 | } | 100 | } |
101 | 101 | ||
102 | string params_t::query_string(const char *prefix) const { | ||
103 | string rv; | ||
104 | for(const_iterator i=begin();i!=end();++i) { | ||
105 | if(!rv.empty()) | ||
106 | rv += '&'; | ||
107 | rv += prefix; | ||
108 | rv += i->first; | ||
109 | rv += '='; | ||
110 | rv += util::url_encode(i->second); | ||
111 | } | ||
112 | return rv; | ||
113 | } | ||
114 | |||
102 | ostream& operator << (ostream& o,const params_t& p) { | 115 | ostream& operator << (ostream& o,const params_t& p) { |
103 | for(params_t::const_iterator i=p.begin();i!=p.end();++i) | 116 | for(params_t::const_iterator i=p.begin();i!=p.end();++i) |
104 | o << i->first << ':' << i->second << '\n'; | 117 | o << i->first << ':' << i->second << '\n'; |
diff --git a/lib/secret.cc b/lib/secret.cc index 632a2ca..d538890 100644 --- a/lib/secret.cc +++ b/lib/secret.cc | |||
@@ -14,31 +14,27 @@ namespace opkele { | |||
14 | } | 14 | } |
15 | }; | 15 | }; |
16 | 16 | ||
17 | void secret_t::enxor_to_base64(const unsigned char *key_sha1,string& rv) const { | 17 | void secret_t::enxor_to_base64(const unsigned char *key_d,string& rv) const { |
18 | if(size()!=20) | ||
19 | throw bad_input(OPKELE_CP_ "wrong secret size"); | ||
20 | vector<unsigned char> tmp; | 18 | vector<unsigned char> tmp; |
21 | transform( | 19 | transform( |
22 | begin(), end(), | 20 | begin(), end(), |
23 | key_sha1, | 21 | key_d, |
24 | back_insert_iterator<vector<unsigned char> >(tmp), | 22 | back_insert_iterator<vector<unsigned char> >(tmp), |
25 | bitwise_xor<unsigned char,unsigned char,unsigned char>() ); | 23 | bitwise_xor<unsigned char,unsigned char,unsigned char>() ); |
26 | rv = util::encode_base64(&(tmp.front()),tmp.size()); | 24 | rv = util::encode_base64(&(tmp.front()),tmp.size()); |
27 | } | 25 | } |
28 | 26 | ||
29 | void secret_t::enxor_from_base64(const unsigned char *key_sha1,const string& b64) { | 27 | void secret_t::enxor_from_base64(const unsigned char *key_d,const string& b64) { |
30 | clear(); | 28 | clear(); |
31 | util::decode_base64(b64,*this); | 29 | util::decode_base64(b64,*this); |
32 | transform( | 30 | transform( |
33 | begin(), end(), | 31 | begin(), end(), |
34 | key_sha1, | 32 | key_d, |
35 | begin(), | 33 | begin(), |
36 | bitwise_xor<unsigned char,unsigned char,unsigned char>() ); | 34 | bitwise_xor<unsigned char,unsigned char,unsigned char>() ); |
37 | } | 35 | } |
38 | 36 | ||
39 | void secret_t::to_base64(string& rv) const { | 37 | void secret_t::to_base64(string& rv) const { |
40 | if(size()!=20) | ||
41 | throw bad_input(OPKELE_CP_ "wrong secret size"); | ||
42 | rv = util::encode_base64(&(front()),size()); | 38 | rv = util::encode_base64(&(front()),size()); |
43 | } | 39 | } |
44 | 40 | ||
diff --git a/lib/sreg.cc b/lib/sreg.cc index 60dc691..03edf57 100644 --- a/lib/sreg.cc +++ b/lib/sreg.cc | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <opkele/exception.h> | 1 | #include <opkele/exception.h> |
2 | #include <opkele/sreg.h> | 2 | #include <opkele/sreg.h> |
3 | #include <opkele/uris.h> | ||
3 | #include <algorithm> | 4 | #include <algorithm> |
4 | 5 | ||
5 | namespace opkele { | 6 | namespace opkele { |
@@ -39,6 +40,7 @@ namespace opkele { | |||
39 | fo += f->fieldname; | 40 | fo += f->fieldname; |
40 | } | 41 | } |
41 | } | 42 | } |
43 | p["ns.sreg"] = OIURI_SREG11; | ||
42 | if(!fr.empty()) p["sreg.required"]=fr; | 44 | if(!fr.empty()) p["sreg.required"]=fr; |
43 | if(!fo.empty()) p["sreg.optional"]=fo; | 45 | if(!fo.empty()) p["sreg.optional"]=fo; |
44 | if(!policy_url.empty()) p["sreg.policy_url"]=policy_url; | 46 | if(!policy_url.empty()) p["sreg.policy_url"]=policy_url; |
diff --git a/lib/util.cc b/lib/util.cc index 416e2cc..a9b9bed 100644 --- a/lib/util.cc +++ b/lib/util.cc | |||
@@ -114,22 +114,32 @@ namespace opkele { | |||
114 | } | 114 | } |
115 | 115 | ||
116 | time_t w3c_to_time(const string& w) { | 116 | time_t w3c_to_time(const string& w) { |
117 | int fraction; | ||
117 | struct tm tm_t; | 118 | struct tm tm_t; |
118 | memset(&tm_t,0,sizeof(tm_t)); | 119 | memset(&tm_t,0,sizeof(tm_t)); |
119 | if( | 120 | if( ( |
121 | sscanf( | ||
122 | w.c_str(), | ||
123 | "%04d-%02d-%02dT%02d:%02d:%02dZ", | ||
124 | &tm_t.tm_year,&tm_t.tm_mon,&tm_t.tm_mday, | ||
125 | &tm_t.tm_hour,&tm_t.tm_min,&tm_t.tm_sec | ||
126 | ) != 6 | ||
127 | ) && ( | ||
120 | sscanf( | 128 | sscanf( |
121 | w.c_str(), | 129 | w.c_str(), |
122 | "%04d-%02d-%02dT%02d:%02d:%02dZ", | 130 | "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", |
123 | &tm_t.tm_year,&tm_t.tm_mon,&tm_t.tm_mday, | 131 | &tm_t.tm_year,&tm_t.tm_mon,&tm_t.tm_mday, |
124 | &tm_t.tm_hour,&tm_t.tm_min,&tm_t.tm_sec | 132 | &tm_t.tm_hour,&tm_t.tm_min,&tm_t.tm_sec, |
125 | ) != 6 ) | 133 | &fraction |
134 | ) != 7 | ||
135 | ) ) | ||
126 | throw failed_conversion(OPKELE_CP_ "failed to sscanf()"); | 136 | throw failed_conversion(OPKELE_CP_ "failed to sscanf()"); |
127 | tm_t.tm_mon--; | 137 | tm_t.tm_mon--; |
128 | tm_t.tm_year-=1900; | 138 | tm_t.tm_year-=1900; |
129 | time_t rv = mktime(&tm_t); | 139 | time_t rv = mktime(&tm_t); |
130 | if(rv==(time_t)-1) | 140 | if(rv==(time_t)-1) |
131 | throw failed_conversion(OPKELE_CP_ "failed to mktime()"); | 141 | throw failed_conversion(OPKELE_CP_ "failed to mktime()"); |
132 | return rv; | 142 | return rv-timezone; |
133 | } | 143 | } |
134 | 144 | ||
135 | /* | 145 | /* |
@@ -164,7 +174,7 @@ namespace opkele { | |||
164 | /* | 174 | /* |
165 | * Normalize URL according to the rules, described in rfc 3986, section 6 | 175 | * Normalize URL according to the rules, described in rfc 3986, section 6 |
166 | * | 176 | * |
167 | * - uppercase hext triplets (e.g. %ab -> %AB) | 177 | * - uppercase hex triplets (e.g. %ab -> %AB) |
168 | * - lowercase scheme and host | 178 | * - lowercase scheme and host |
169 | * - decode %-encoded characters, specified as unreserved in rfc 3986, section 2.3, | 179 | * - decode %-encoded characters, specified as unreserved in rfc 3986, section 2.3, |
170 | * that is - [:alpha:][:digit:]._~- | 180 | * that is - [:alpha:][:digit:]._~- |
@@ -173,30 +183,40 @@ namespace opkele { | |||
173 | * - if there's no path component, add '/' | 183 | * - if there's no path component, add '/' |
174 | */ | 184 | */ |
175 | string rfc_3986_normalize_uri(const string& uri) { | 185 | string rfc_3986_normalize_uri(const string& uri) { |
186 | static const char *whitespace = " \t\r\n"; | ||
176 | string rv; | 187 | string rv; |
177 | string::size_type colon = uri.find(':'); | 188 | string::size_type ns = uri.find_first_not_of(whitespace); |
189 | if(ns==string::npos) | ||
190 | throw bad_input(OPKELE_CP_ "Can't normalize empty URI"); | ||
191 | string::size_type colon = uri.find(':',ns); | ||
178 | if(colon==string::npos) | 192 | if(colon==string::npos) |
179 | throw bad_input(OPKELE_CP_ "No scheme specified in URI"); | 193 | throw bad_input(OPKELE_CP_ "No scheme specified in URI"); |
180 | transform( | 194 | transform( |
181 | uri.begin(), uri.begin()+colon+1, | 195 | uri.begin()+ns, uri.begin()+colon+1, |
182 | back_inserter(rv), ::tolower ); | 196 | back_inserter(rv), ::tolower ); |
183 | bool s; | 197 | bool s; |
184 | if(rv=="http:") | 198 | string::size_type ul = uri.find_last_not_of(whitespace)+1; |
185 | s = false; | ||
186 | else if(rv=="https:") | ||
187 | s = true; | ||
188 | else | ||
189 | throw not_implemented(OPKELE_CP_ "Only http(s) URIs can be normalized here"); | ||
190 | string::size_type ul = uri.length(); | ||
191 | if(ul <= (colon+3)) | 199 | if(ul <= (colon+3)) |
192 | throw bad_input(OPKELE_CP_ "Unexpected end of URI being normalized encountered"); | 200 | throw bad_input(OPKELE_CP_ "Unexpected end of URI being normalized encountered"); |
193 | if(uri[colon+1]!='/' || uri[colon+2]!='/') | 201 | if(uri[colon+1]!='/' || uri[colon+2]!='/') |
194 | throw bad_input(OPKELE_CP_ "Unexpected input in URI being normalized after scheme component"); | 202 | throw bad_input(OPKELE_CP_ "Unexpected input in URI being normalized after scheme component"); |
203 | if(rv=="http:") | ||
204 | s = false; | ||
205 | else if(rv=="https:") | ||
206 | s = true; | ||
207 | else{ | ||
208 | /* TODO: support more schemes. | ||
209 | * e.g. xri. How do we normalize | ||
210 | * xri? | ||
211 | */ | ||
212 | rv.append(uri,colon+1,ul-colon-1); | ||
213 | return rv; | ||
214 | } | ||
195 | rv += "//"; | 215 | rv += "//"; |
196 | string::size_type interesting = uri.find_first_of(":/#?",colon+3); | 216 | string::size_type interesting = uri.find_first_of(":/#?",colon+3); |
197 | if(interesting==string::npos) { | 217 | if(interesting==string::npos) { |
198 | transform( | 218 | transform( |
199 | uri.begin()+colon+3,uri.end(), | 219 | uri.begin()+colon+3,uri.begin()+ul, |
200 | back_inserter(rv), ::tolower ); | 220 | back_inserter(rv), ::tolower ); |
201 | rv += '/'; return rv; | 221 | rv += '/'; return rv; |
202 | } | 222 | } |
@@ -285,7 +305,8 @@ namespace opkele { | |||
285 | } | 305 | } |
286 | } | 306 | } |
287 | if(!pseg.empty()) { | 307 | if(!pseg.empty()) { |
288 | rv += '/'; rv += pseg; | 308 | if(!qf) rv += '/'; |
309 | rv += pseg; | ||
289 | } | 310 | } |
290 | return rv; | 311 | return rv; |
291 | } | 312 | } |
diff --git a/libopkele.pc.in b/libopkele.pc.in index bc67362..011f2fe 100644 --- a/libopkele.pc.in +++ b/libopkele.pc.in | |||
@@ -7,5 +7,5 @@ Name: libopkele | |||
7 | Description: C++ implementation of OpenID protocol | 7 | Description: C++ implementation of OpenID protocol |
8 | Version: @VERSION@ | 8 | Version: @VERSION@ |
9 | Requires: openssl libpcre @KONFORKA_KONFORKA@ | 9 | Requires: openssl libpcre @KONFORKA_KONFORKA@ |
10 | Cflags: -I${includedir} @LIBCURL_CPPFLAGS@ @PCRE_CFLAGS@ | 10 | Cflags: -I${includedir} @LIBCURL_CPPFLAGS@ @PCRE_CFLAGS@ @EXPAT_CFLAGS@ @TIDY_CFLAGS@ |
11 | Libs: -L${libdir} -lopkele @LIBCURL@ @PCRE_LIBS@ | 11 | Libs: -L${libdir} -lopkele @LIBCURL@ @PCRE_LIBS@ @EXPAT_LIBS@ @TIDY_LIBS@ |
diff --git a/test/.gitignore b/test/.gitignore index 918b3c9..31ae686 100644 --- a/test/.gitignore +++ b/test/.gitignore | |||
@@ -2,3 +2,4 @@ | |||
2 | /.libs | 2 | /.libs |
3 | /test | 3 | /test |
4 | *.o | 4 | *.o |
5 | /idiscover | ||
diff --git a/test/Makefile.am b/test/Makefile.am index 0d1c0ef..b573d55 100644 --- a/test/Makefile.am +++ b/test/Makefile.am | |||
@@ -1,5 +1,6 @@ | |||
1 | noinst_PROGRAMS = test | 1 | noinst_PROGRAMS = test idiscover |
2 | 2 | ||
3 | AM_CPPFLAGS=${CPPFLAGS_DEBUG} | ||
3 | DEFAULT_INCLUDES = -I${top_builddir} | 4 | DEFAULT_INCLUDES = -I${top_builddir} |
4 | INCLUDES = -I${top_srcdir}/include/ ${KONFORKA_CFLAGS} ${LIBCURL_CPPFLAGS} | 5 | INCLUDES = -I${top_srcdir}/include/ ${KONFORKA_CFLAGS} ${LIBCURL_CPPFLAGS} |
5 | 6 | ||
@@ -10,3 +11,6 @@ EXTRA_DIST=$(addsuffix .html,$(addprefix html/, \ | |||
10 | empty head-in-body hkn-delegate hkn-server hkn in-body \ | 11 | empty head-in-body hkn-delegate hkn-server hkn in-body \ |
11 | unclosed-head spaced-links spaced-link-attrs 2rels \ | 12 | unclosed-head spaced-links spaced-link-attrs 2rels \ |
12 | )) | 13 | )) |
14 | |||
15 | idiscover_SOURCES = idiscover.cc | ||
16 | idiscover_LDADD = ${top_builddir}/lib/libopkele.la | ||
diff --git a/test/idiscover.cc b/test/idiscover.cc new file mode 100644 index 0000000..d9a7c62 --- a/dev/null +++ b/test/idiscover.cc | |||
@@ -0,0 +1,54 @@ | |||
1 | #include <iostream> | ||
2 | #include <stdexcept> | ||
3 | #include <iterator> | ||
4 | #include <algorithm> | ||
5 | using namespace std; | ||
6 | #include <opkele/exception.h> | ||
7 | #include <opkele/discovery.h> | ||
8 | |||
9 | template<typename _PDT> | ||
10 | ostream& operator<<(ostream& o,const opkele::xrd::priority_map<_PDT>& pm) { | ||
11 | for(typename opkele::xrd::priority_map<_PDT>::const_iterator i=pm.begin(); | ||
12 | i!=pm.end();++i) | ||
13 | o << ' ' << i->second << '[' << i->first << ']'; | ||
14 | return o; | ||
15 | } | ||
16 | |||
17 | ostream& operator<<(ostream& o,const opkele::xrd::service_t s) { | ||
18 | o << "{" << endl | ||
19 | << " Type: "; | ||
20 | copy(s.types.begin(),s.types.end(), | ||
21 | ostream_iterator<string>(o," ")); | ||
22 | o << endl | ||
23 | << " URI: " << s.uris << endl | ||
24 | << " LocalID: " << s.local_ids << endl | ||
25 | << " ProviderID: " << s.provider_id << endl; | ||
26 | o << "}"; | ||
27 | } | ||
28 | |||
29 | int main(int argc,char **argv) { | ||
30 | try { | ||
31 | if(argc<2) | ||
32 | throw opkele::exception(OPKELE_CP_ "Please, give me something to resolve"); | ||
33 | for(int a=1;a<argc;++a) { | ||
34 | opkele::idiscovery_t discovery(argv[a]); | ||
35 | clog | ||
36 | << "===============================================================" << endl | ||
37 | << "User-supplied ID: " << argv[a] << endl | ||
38 | << "Normalized ID: " << discovery.normalized_id << endl | ||
39 | << "Canonicalized ID: " << discovery.canonicalized_id << endl | ||
40 | << "The identity is " << (discovery.xri_identity?"":"not ") << "an i-name" << endl; | ||
41 | if(discovery.xrd.expires) | ||
42 | clog << "Information expires in " << discovery.xrd.expires-time(0) << " seconds" << endl; | ||
43 | clog << endl | ||
44 | << "CanonicalID: " << discovery.xrd.canonical_ids << endl | ||
45 | << "LocalID: " << discovery.xrd.local_ids << endl | ||
46 | << "ProviderID: " << discovery.xrd.provider_id << endl | ||
47 | << "Services: " << discovery.xrd.services << endl; | ||
48 | } | ||
49 | }catch(exception& e) { | ||
50 | cerr << "oops: " << e.what() << endl; | ||
51 | _exit(1); | ||
52 | } | ||
53 | _exit(0); | ||
54 | } | ||