summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--.gitignore33
-rw-r--r--COPYING2
-rw-r--r--Makefile.am3
-rw-r--r--NEWS.xml6
-rwxr-xr-xautogen.sh2
-rw-r--r--autoregen.sh2
-rw-r--r--configure.ac4
-rw-r--r--include/opkele/expat.h3
-rw-r--r--lib/basic_rp.cc3
-rw-r--r--lib/discovery.cc31
-rw-r--r--lib/expat.cc9
-rw-r--r--test/RP.cc1
12 files changed, 71 insertions, 28 deletions
diff --git a/.gitignore b/.gitignore
index 87771db..16be7d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,21 +1,16 @@
1configure 1/configure
2Makefile.in 2Makefile.in
3Doxyfile 3/Doxyfile
4config.log 4/config.log
5depcomp 5/config.h
6config.guess 6/INSTALL
7config.h 7/NEWS
8config.sub
9ltmain.sh
10INSTALL
11NEWS
12Makefile 8Makefile
13config.status 9/config.status
14stamp-h1 10/stamp-h1
15config.h.in 11/config.h.in
16libtool 12/autom4te.cache
17autom4te.cache 13/libopkele.pc
18libopkele.pc 14/aclocal.m4
19missing 15/aclocal.d
20aclocal.m4 16/aux.d
21install-sh
diff --git a/COPYING b/COPYING
index 46d3f30..b9cc74c 100644
--- a/COPYING
+++ b/COPYING
@@ -1,19 +1,19 @@
1Copyright (c) 2005-2008 Klever Group (http://www.klever.net/) 1Copyright (c) 2005-2009 Klever Group (http://www.klever.net/)
2 2
3Permission is hereby granted, free of charge, to any person obtaining a copy of 3Permission is hereby granted, free of charge, to any person obtaining a copy of
4this software and associated documentation files (the "Software"), to deal in 4this software and associated documentation files (the "Software"), to deal in
5the Software without restriction, including without limitation the rights to 5the Software without restriction, including without limitation the rights to
6use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 6use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7of the Software, and to permit persons to whom the Software is furnished to do 7of the Software, and to permit persons to whom the Software is furnished to do
8so, subject to the following conditions: 8so, subject to the following conditions:
9 9
10The above copyright notice and this permission notice shall be included in all 10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software. 11copies or substantial portions of the Software.
12 12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19SOFTWARE. 19SOFTWARE.
diff --git a/Makefile.am b/Makefile.am
index 3227bdb..7726dad 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,28 +1,29 @@
1
2SUBDIRS=include lib test 1SUBDIRS=include lib test
3EXTRA_DIST= NEWS NEWS.xml NEWS.xsl 2EXTRA_DIST= NEWS NEWS.xml NEWS.xsl
4 3
4ACLOCAL_AMFLAGS=-I aclocal.d
5
5pkgconfigdir=${libdir}/pkgconfig 6pkgconfigdir=${libdir}/pkgconfig
6pkgconfig_DATA=libopkele.pc 7pkgconfig_DATA=libopkele.pc
7 8
8all-local: NEWS 9all-local: NEWS
9if HAVE_DOXYGEN 10if HAVE_DOXYGEN
10clean-local: 11clean-local:
11 rm -rf doxydox 12 rm -rf doxydox
12endif 13endif
13 14
14NEWS: NEWS.xsl NEWS.xml 15NEWS: NEWS.xsl NEWS.xml
15 ${XSLTPROC} -o $@ NEWS.xsl NEWS.xml 16 ${XSLTPROC} -o $@ NEWS.xsl NEWS.xml
16 17
17if HAVE_DOXYGEN 18if HAVE_DOXYGEN
18dox: Doxyfile 19dox: Doxyfile
19 ${DOXYGEN} 20 ${DOXYGEN}
20endif 21endif
21 22
22ISSUEFILES = $$(find ${top_srcdir} -type f '(' \ 23ISSUEFILES = $$(find ${top_srcdir} -type f '(' \
23 -name '*.cc' -or -name '*.h' \ 24 -name '*.cc' -or -name '*.h' \
24 ')' ) \ 25 ')' ) \
25 ${top_srcdir}/configure.ac 26 ${top_srcdir}/configure.ac
26issues: todo fixme xxx 27issues: todo fixme xxx
27todo fixme xxx: 28todo fixme xxx:
28 @grep --color=auto -in '$@:' ${ISSUEFILES} || true 29 @grep --color=auto -in '$@:' ${ISSUEFILES} || true
diff --git a/NEWS.xml b/NEWS.xml
index 160b197..0206018 100644
--- a/NEWS.xml
+++ b/NEWS.xml
@@ -1,65 +1,71 @@
1<?xml version="1.0" encoding="us-ascii"?> 1<?xml version="1.0" encoding="us-ascii"?>
2<news> 2<news>
3 <version version="2.0.2" date="April 11th, 2009">
4 <ni>Handling of unknown encodings during discovery</ni>
5 <ni>Discovery robustness improvements</ni>
6 <ni>Workaround for OPs (e.g. livejournal.com) breaking specs</ni>
7 <ni>Build fixes and improvements</ni>
8 </version>
3 <version version="2.0.1" date="November 22nd, 2008"> 9 <version version="2.0.1" date="November 22nd, 2008">
4 <ni>Compile-time fixes and improvements</ni> 10 <ni>Compile-time fixes and improvements</ni>
5 <ni>Portability improvements for FreeBSD</ni> 11 <ni>Portability improvements for FreeBSD</ni>
6 <ni>Really suppress debugging message from htmltidy when --disable-debug is in 12 <ni>Really suppress debugging message from htmltidy when --disable-debug is in
7 effect</ni> 13 effect</ni>
8 <ni>minor bugfixes</ni> 14 <ni>minor bugfixes</ni>
9 <ni>thread-safety improvements</ni> 15 <ni>thread-safety improvements</ni>
10 </version> 16 </version>
11 <version version="2.0" date="June 26th, 2008"> 17 <version version="2.0" date="June 26th, 2008">
12 <ni>OpenID 2.0 support</ni> 18 <ni>OpenID 2.0 support</ni>
13 <ni>Major rewrite of the whole thing</ni> 19 <ni>Major rewrite of the whole thing</ni>
14 <ni>Support for XRDS (YADIS and XRI/inames) discovery</ni> 20 <ni>Support for XRDS (YADIS and XRI/inames) discovery</ni>
15 <ni>Sheerly improved html-based discovery (only code using new, 2.0-enabled 21 <ni>Sheerly improved html-based discovery (only code using new, 2.0-enabled
16 classes benefits from it)</ni> 22 classes benefits from it)</ni>
17 <ni>Deprecation of the old api</ni> 23 <ni>Deprecation of the old api</ni>
18 <ni>Added sample RP and OP implementations</ni> 24 <ni>Added sample RP and OP implementations</ni>
19 <ni>Require expat xml stream parser library</ni> 25 <ni>Require expat xml stream parser library</ni>
20 <ni>Require htmltidy library</ni> 26 <ni>Require htmltidy library</ni>
21 <ni>Require tr1/memory (shared_ptr) support - either modern gcc or boost 27 <ni>Require tr1/memory (shared_ptr) support - either modern gcc or boost
22 library</ni> 28 library</ni>
23 </version> 29 </version>
24 <version version="0.3.2" date="November 22nd, 2007"> 30 <version version="0.3.2" date="November 22nd, 2007">
25 <ni>code cleanup for stricter compiler</ni> 31 <ni>code cleanup for stricter compiler</ni>
26 </version> 32 </version>
27 <version version="0.3.1" date="November 20th, 2007"> 33 <version version="0.3.1" date="November 20th, 2007">
28 <ni>more robustness improvements in links discovery</ni> 34 <ni>more robustness improvements in links discovery</ni>
29 <ni>removed dependency on pcre c++ bindings, because there are few of them and 35 <ni>removed dependency on pcre c++ bindings, because there are few of them and
30 not everyone likes all of them</ni> 36 not everyone likes all of them</ni>
31 <ni>minor build improvements</ni> 37 <ni>minor build improvements</ni>
32 </version> 38 </version>
33 <version version="0.3" date="August 9th, 2007"> 39 <version version="0.3" date="August 9th, 2007">
34 <ni>fixed canonicalization procedure to be specs-compliant. Note, that the old 40 <ni>fixed canonicalization procedure to be specs-compliant. Note, that the old
35 consumer_t::canonicalize is now called consumer_t::normalize and the 41 consumer_t::canonicalize is now called consumer_t::normalize and the
36 canonicalize memeber is now virtual to allow caching layer, not static</ni> 42 canonicalize memeber is now virtual to allow caching layer, not static</ni>
37 <ni>robustness improvement in handling associations expiry</ni> 43 <ni>robustness improvement in handling associations expiry</ni>
38 <ni>minor documentation updates</ni> 44 <ni>minor documentation updates</ni>
39 </version> 45 </version>
40 <version version="0.2.1" date="June 24th, 2007"> 46 <version version="0.2.1" date="June 24th, 2007">
41 <ni>open id server invalid signature bugfix</ni> 47 <ni>open id server invalid signature bugfix</ni>
42 </version> 48 </version>
43 <version version="0.2" date="June 19th, 2007"> 49 <version version="0.2" date="June 19th, 2007">
44 <ni>A few robustness improvements and optimizations</ni> 50 <ni>A few robustness improvements and optimizations</ni>
45 <ni>More liberal key/values messages parsing</ni> 51 <ni>More liberal key/values messages parsing</ni>
46 <ni>Changed unusable --with-pcre++ configure option to --with-pcrepp</ni> 52 <ni>Changed unusable --with-pcre++ configure option to --with-pcrepp</ni>
47 </version> 53 </version>
48 <version version="0.1.1" date="January 16th, 2007"> 54 <version version="0.1.1" date="January 16th, 2007">
49 <ni>Fixed a bug in curl errors handling</ni> 55 <ni>Fixed a bug in curl errors handling</ni>
50 <ni>added --disable-ssl-verify-host and --disable-ssl-verify-peer options to 56 <ni>added --disable-ssl-verify-host and --disable-ssl-verify-peer options to
51 configure to alter default implementation of consumer's retrieve_links 57 configure to alter default implementation of consumer's retrieve_links
52 behaviour</ni> 58 behaviour</ni>
53 <ni>Build fix that eliminates the need to pass --disable-konforka in the 59 <ni>Build fix that eliminates the need to pass --disable-konforka in the
54 absence of it.</ni> 60 absence of it.</ni>
55 </version> 61 </version>
56 <version version="0.1" date="January 12th, 2007"> 62 <version version="0.1" date="January 12th, 2007">
57 <ni>OpenID simple registration extension implementation</ni> 63 <ni>OpenID simple registration extension implementation</ni>
58 <ni>OpenID extensions framework</ni> 64 <ni>OpenID extensions framework</ni>
59 <ni>Canonicalization bugfix</ni> 65 <ni>Canonicalization bugfix</ni>
60 <ni>Slightly improved interoperability with buggy implementations</ni> 66 <ni>Slightly improved interoperability with buggy implementations</ni>
61 </version> 67 </version>
62 <version version="0.0" date="July 25th, 2005"> 68 <version version="0.0" date="July 25th, 2005">
63 <ni>Initial release</ni> 69 <ni>Initial release</ni>
64 </version> 70 </version>
65</news> 71</news>
diff --git a/autogen.sh b/autogen.sh
index bf32a35..578206d 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,11 +1,11 @@
1#!/bin/sh 1#!/bin/sh
2tool_libtoolize="$(type -P glibtoolize || type -P libtoolize)" 2tool_libtoolize="$(type -P glibtoolize || type -P libtoolize)"
3if test -z "$tool_libtoolize" ; then 3if test -z "$tool_libtoolize" ; then
4 echo "Failed to find libtoolize." ; exit 1; 4 echo "Failed to find libtoolize." ; exit 1;
5fi 5fi
6 "$tool_libtoolize" -f \ 6 "$tool_libtoolize" -f \
7&& aclocal \ 7&& aclocal -I aclocal.d \
8&& autoheader \ 8&& autoheader \
9&& automake -a \ 9&& automake -a \
10&& autoconf \ 10&& autoconf \
11&& ./configure "$@" 11&& ./configure "$@"
diff --git a/autoregen.sh b/autoregen.sh
new file mode 100644
index 0000000..ce75a08
--- a/dev/null
+++ b/autoregen.sh
@@ -0,0 +1,2 @@
1#!/bin/bash
2eval sh autogen.sh $(./config.status --version | grep '^ with options "'|sed -e 's/^[^"]\+"//' -e 's/"$//') "$@"
diff --git a/configure.ac b/configure.ac
index a7b56ff..2ded490 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,195 +1,197 @@
1AC_INIT([libopkele], [2.0.1], [libopkele-bugs@klever.net]) 1AC_INIT([libopkele], [2.0.2], [libopkele-bugs@klever.net])
2AC_CONFIG_SRCDIR([include/opkele/opkele-config.h]) 2AC_CONFIG_SRCDIR([include/opkele/opkele-config.h])
3AC_CONFIG_HEADERS([config.h include/opkele/acconfig.h]) 3AC_CONFIG_HEADERS([config.h include/opkele/acconfig.h])
4AC_CONFIG_MACRO_DIR([aclocal.d])
5AC_CONFIG_AUX_DIR([aux.d])
4AM_INIT_AUTOMAKE([dist-bzip2]) 6AM_INIT_AUTOMAKE([dist-bzip2])
5 7
6AC_PROG_INSTALL 8AC_PROG_INSTALL
7AC_PROG_CXX 9AC_PROG_CXX
8AC_PROG_CC 10AC_PROG_CC
9AC_PROG_LIBTOOL 11AC_PROG_LIBTOOL
10PKG_PROG_PKG_CONFIG 12PKG_PROG_PKG_CONFIG
11 13
12AC_HEADER_STDC 14AC_HEADER_STDC
13AC_CHECK_FUNCS([timegm]) 15AC_CHECK_FUNCS([timegm])
14 16
15AC_PATH_PROG([XSLTPROC],[xsltproc],[true]) 17AC_PATH_PROG([XSLTPROC],[xsltproc],[true])
16 18
17AC_MSG_CHECKING([for source tree version]) 19AC_MSG_CHECKING([for source tree version])
18if headrev=$(cd $srcdir && git rev-parse --verify HEAD 2>/dev/null) ; then 20if headrev=$(cd $srcdir && git rev-parse --verify HEAD 2>/dev/null) ; then
19 PACKAGE_SRC_VERSION="$(cd $srcdir && git describe --tags $headrev)" 21 PACKAGE_SRC_VERSION="$(cd $srcdir && git describe --tags $headrev)"
20 test "$PACKAGE_SRC_VERSION" = "$PACKAGE_VERSION" \ 22 test "$PACKAGE_SRC_VERSION" = "$PACKAGE_VERSION" \
21 -o "${PACKAGE_SRC_VERSION#${PACKAGE_VERSION}-}" != "$PACKAGE_SRC_VERSION" || PACKAGE_SRC_VERSION="${PACKAGE_VERSION}:${PACKAGE_SRC_VERSION}" 23 -o "${PACKAGE_SRC_VERSION#${PACKAGE_VERSION}-}" != "$PACKAGE_SRC_VERSION" || PACKAGE_SRC_VERSION="${PACKAGE_VERSION}:${PACKAGE_SRC_VERSION}"
22 ( cd $srcdir && git diff-index $headrev | read dirt ) && PACKAGE_SRC_VERSION="${PACKAGE_SRC_VERSION}-dirty" 24 ( cd $srcdir && git diff-index $headrev | read dirt ) && PACKAGE_SRC_VERSION="${PACKAGE_SRC_VERSION}-dirty"
23else 25else
24 PACKAGE_SRC_VERSION="$PACKAGE_VERSION" 26 PACKAGE_SRC_VERSION="$PACKAGE_VERSION"
25fi 27fi
26AC_MSG_RESULT([$PACKAGE_SRC_VERSION]) 28AC_MSG_RESULT([$PACKAGE_SRC_VERSION])
27AC_SUBST([PACKAGE_SRC_VERSION]) 29AC_SUBST([PACKAGE_SRC_VERSION])
28AC_DEFINE_UNQUOTED([PACKAGE_SRC_VERSION],["$PACKAGE_SRC_VERSION"],[more or less precise source tree version]) 30AC_DEFINE_UNQUOTED([PACKAGE_SRC_VERSION],["$PACKAGE_SRC_VERSION"],[more or less precise source tree version])
29 31
30tr1_mem_std="false" 32tr1_mem_std="false"
31tr1_mem_boost="false" 33tr1_mem_boost="false"
32AC_CHECK_SHAREDPTR(std::tr1,tr1/memory,[ tr1_mem_std=true ]) 34AC_CHECK_SHAREDPTR(std::tr1,tr1/memory,[ tr1_mem_std=true ])
33AC_CHECK_SHAREDPTR(boost,boost/shared_ptr.hpp,[ tr1_mem_boost=true ]) 35AC_CHECK_SHAREDPTR(boost,boost/shared_ptr.hpp,[ tr1_mem_boost=true ])
34tr1_mem="" 36tr1_mem=""
35AC_ARG_WITH([tr1-memory], 37AC_ARG_WITH([tr1-memory],
36 AC_HELP_STRING([--with-tr1-memory=<boost|std>],[select tr1/memory (shared_ptr<>) implementation to use]), 38 AC_HELP_STRING([--with-tr1-memory=<boost|std>],[select tr1/memory (shared_ptr<>) implementation to use]),
37 [ tr1_mem="$withval" ] 39 [ tr1_mem="$withval" ]
38) 40)
39AC_MSG_CHECKING([for tr1/memory implementation to use]) 41AC_MSG_CHECKING([for tr1/memory implementation to use])
40test -z "$tr1_mem" && $tr1_mem_std && tr1_mem=std 42test -z "$tr1_mem" && $tr1_mem_std && tr1_mem=std
41test -z "$tr1_mem" && $tr1_mem_boost && tr1_mem=boost 43test -z "$tr1_mem" && $tr1_mem_boost && tr1_mem=boost
42if test -z "$tr1_mem" ; then 44if test -z "$tr1_mem" ; then
43 AC_MSG_RESULT([none found]) 45 AC_MSG_RESULT([none found])
44else 46else
45 AC_MSG_RESULT([$tr1_mem]) 47 AC_MSG_RESULT([$tr1_mem])
46fi 48fi
47case "$tr1_mem" in 49case "$tr1_mem" in
48 std) 50 std)
49 $tr1_mem_std || AC_MSG_ERROR([std implementation requested, but not found]) 51 $tr1_mem_std || AC_MSG_ERROR([std implementation requested, but not found])
50 OPKELE_TR1_MEM_NS=std::tr1 52 OPKELE_TR1_MEM_NS=std::tr1
51 OPKELE_TR1_MEM_HEADER=tr1/memory 53 OPKELE_TR1_MEM_HEADER=tr1/memory
52 ;; 54 ;;
53 boost) 55 boost)
54 $tr1_mem_boost || AC_MSG_ERROR([boost implementation requested, but not found]) 56 $tr1_mem_boost || AC_MSG_ERROR([boost implementation requested, but not found])
55 OPKELE_TR1_MEM_NS=boost 57 OPKELE_TR1_MEM_NS=boost
56 OPKELE_TR1_MEM_HEADER=boost/shared_ptr.hpp 58 OPKELE_TR1_MEM_HEADER=boost/shared_ptr.hpp
57 ;; 59 ;;
58 *) 60 *)
59 AC_MSG_ERROR([no shared_ptr<> implementation found]) 61 AC_MSG_ERROR([no shared_ptr<> implementation found])
60 ;; 62 ;;
61esac 63esac
62AC_SUBST([OPKELE_TR1_MEM_NS]) 64AC_SUBST([OPKELE_TR1_MEM_NS])
63AC_SUBST([OPKELE_TR1_MEM_HEADER]) 65AC_SUBST([OPKELE_TR1_MEM_HEADER])
64 66
65AC_MSG_CHECKING([for deprecated attribute support]) 67AC_MSG_CHECKING([for deprecated attribute support])
66AC_COMPILE_IFELSE([ 68AC_COMPILE_IFELSE([
67 int __attribute__((deprecated)) deprecated_function(); 69 int __attribute__((deprecated)) deprecated_function();
68 ],[ 70 ],[
69 AC_MSG_RESULT([yes]) 71 AC_MSG_RESULT([yes])
70 AC_DEFINE([OPKELE_DEPRECATE],[__attribute__((deprecated))],[deprecated function attribute]) 72 AC_DEFINE([OPKELE_DEPRECATE],[__attribute__((deprecated))],[deprecated function attribute])
71 ],[ 73 ],[
72 AC_MSG_RESULT([no]) 74 AC_MSG_RESULT([no])
73 AC_DEFINE([OPKELE_DEPRECATE],,[deprecated function attribute]) 75 AC_DEFINE([OPKELE_DEPRECATE],,[deprecated function attribute])
74 ] 76 ]
75) 77)
76 78
77AC_LANG_PUSH([C++]) 79AC_LANG_PUSH([C++])
78AC_MSG_CHECKING([for abi::__cxa_demangle]) 80AC_MSG_CHECKING([for abi::__cxa_demangle])
79AC_COMPILE_IFELSE([ 81AC_COMPILE_IFELSE([
80 #include <typeinfo> 82 #include <typeinfo>
81 using namespace std; 83 using namespace std;
82 #include <cxxabi.h> 84 #include <cxxabi.h>
83 int main(int c,char **v) { 85 int main(int c,char **v) {
84 int dstat; 86 int dstat;
85 char *demangled = abi::__cxa_demangle(typeid(dstat).name(),0,0,&dstat); 87 char *demangled = abi::__cxa_demangle(typeid(dstat).name(),0,0,&dstat);
86 return 0; 88 return 0;
87 } 89 }
88 ],[ 90 ],[
89 AC_MSG_RESULT([yes]) 91 AC_MSG_RESULT([yes])
90 AC_DEFINE([HAVE_DEMANGLE],,[defined if abi::__cxa_demangle is available]) 92 AC_DEFINE([HAVE_DEMANGLE],,[defined if abi::__cxa_demangle is available])
91 ],[ 93 ],[
92 AC_MSG_RESULT([no]) 94 AC_MSG_RESULT([no])
93 ] 95 ]
94) 96)
95AC_LANG_POP([C++]) 97AC_LANG_POP([C++])
96 98
97 99
98 100
99 101
100PKG_CHECK_MODULES([OPENSSL],[openssl],,[ 102PKG_CHECK_MODULES([OPENSSL],[openssl],,[
101 AC_MSG_ERROR([no openssl library found. get one from http://www.openssl.org/]) 103 AC_MSG_ERROR([no openssl library found. get one from http://www.openssl.org/])
102]) 104])
103 105
104WANT_KONFORKA="yes" 106WANT_KONFORKA="yes"
105AC_ARG_ENABLE([konforka], 107AC_ARG_ENABLE([konforka],
106 AC_HELP_STRING([--disable-konforka],[do not use konforka library (default: use if found)]), 108 AC_HELP_STRING([--disable-konforka],[do not use konforka library (default: use if found)]),
107 [ 109 [
108 test "${enableval}" = "no" && WANT_KONFORKA="no" 110 test "${enableval}" = "no" && WANT_KONFORKA="no"
109 ] 111 ]
110) 112)
111if test "${WANT_KONFORKA}" = "yes" ; then 113if test "${WANT_KONFORKA}" = "yes" ; then
112 PKG_CHECK_MODULES([KONFORKA],[konforka],[ 114 PKG_CHECK_MODULES([KONFORKA],[konforka],[
113 AC_SUBST([KONFORKA_CFLAGS]) 115 AC_SUBST([KONFORKA_CFLAGS])
114 AC_SUBST([KONFORKA_LIBS]) 116 AC_SUBST([KONFORKA_LIBS])
115 AC_DEFINE([HAVE_KONFORKA],,[defined in presence of konforka library]) 117 AC_DEFINE([HAVE_KONFORKA],,[defined in presence of konforka library])
116 AC_DEFINE([OPKELE_HAVE_KONFORKA],,[defined in presence of konforka library]) 118 AC_DEFINE([OPKELE_HAVE_KONFORKA],,[defined in presence of konforka library])
117 AC_SUBST([KONFORKA_KONFORKA],[konforka]) 119 AC_SUBST([KONFORKA_KONFORKA],[konforka])
118 ],[true]) 120 ],[true])
119fi 121fi
120 122
121WANT_DOXYGEN="yes" 123WANT_DOXYGEN="yes"
122AC_ARG_ENABLE([doxygen], 124AC_ARG_ENABLE([doxygen],
123 AC_HELP_STRING([--disable-doxygen],[do not generate documentation]), 125 AC_HELP_STRING([--disable-doxygen],[do not generate documentation]),
124 [ 126 [
125 test "${enableval}" = "no" && WANT_DOXYGEN="no" 127 test "${enableval}" = "no" && WANT_DOXYGEN="no"
126 ] 128 ]
127) 129)
128if test "${WANT_DOXYGEN}" = "yes" ; then 130if test "${WANT_DOXYGEN}" = "yes" ; then
129 AC_WITH_DOXYGEN 131 AC_WITH_DOXYGEN
130 AC_WITH_DOT 132 AC_WITH_DOT
131else 133else
132 AM_CONDITIONAL([HAVE_DOXYGEN],[false]) 134 AM_CONDITIONAL([HAVE_DOXYGEN],[false])
133 AM_CONDITIONAL([HAVE_DOT],[false]) 135 AM_CONDITIONAL([HAVE_DOT],[false])
134fi 136fi
135 137
136LIBCURL_CHECK_CONFIG(,,,[ 138LIBCURL_CHECK_CONFIG(,,,[
137 AC_MSG_ERROR([no required libcurl library. get one from http://curl.haxx.se/]) 139 AC_MSG_ERROR([no required libcurl library. get one from http://curl.haxx.se/])
138]) 140])
139 141
140AC_CHECK_HEADER([expat.h],[ 142AC_CHECK_HEADER([expat.h],[
141 AC_CHECK_LIB([expat],[XML_ParserCreate],[ 143 AC_CHECK_LIB([expat],[XML_ParserCreate],[
142 EXPAT_LIBS=-lexpat 144 EXPAT_LIBS=-lexpat
143 EXPAT_CFLAGS= 145 EXPAT_CFLAGS=
144 AC_SUBST([EXPAT_LIBS]) 146 AC_SUBST([EXPAT_LIBS])
145 AC_SUBST([EXPAT_CFLAGS]) 147 AC_SUBST([EXPAT_CFLAGS])
146 ],[ 148 ],[
147 AC_MSG_ERROR([no required expat library. get one from http://expat.sourceforge.net/]) 149 AC_MSG_ERROR([no required expat library. get one from http://expat.sourceforge.net/])
148 ]) 150 ])
149],[ 151],[
150 AC_MSG_ERROR([no required expat library. get one from http://expat.sourceforge.net/]) 152 AC_MSG_ERROR([no required expat library. get one from http://expat.sourceforge.net/])
151]) 153])
152 154
153AC_CHECK_HEADERS([tidy.h tidy/tidy.h],[ 155AC_CHECK_HEADERS([tidy.h tidy/tidy.h],[
154 AC_CHECK_LIB([tidy],[tidyParseBuffer],[ 156 AC_CHECK_LIB([tidy],[tidyParseBuffer],[
155 TIDY_LIBS=-ltidy 157 TIDY_LIBS=-ltidy
156 TIDY_CFLAGS= 158 TIDY_CFLAGS=
157 AC_SUBST([TIDY_LIBS]) 159 AC_SUBST([TIDY_LIBS])
158 AC_SUBST([TIDY_CFLAGS]) 160 AC_SUBST([TIDY_CFLAGS])
159 ],[ 161 ],[
160 AC_MSG_ERROR([no required htmltidy library found. get one from http://tidy.sourceforge.net/]) 162 AC_MSG_ERROR([no required htmltidy library found. get one from http://tidy.sourceforge.net/])
161 ]) 163 ])
162],[ 164],[
163 test "$ac_header" = "tidy/tidy.h" \ 165 test "$ac_header" = "tidy/tidy.h" \
164 && AC_MSG_ERROR([no required htmltidy library found. get one from http://tidy.sourceforge.net/]) 166 && AC_MSG_ERROR([no required htmltidy library found. get one from http://tidy.sourceforge.net/])
165]) 167])
166 168
167if test -n "$PCRE_LIBS" -a -n "$PCRE_CFLAGS" ; then 169if test -n "$PCRE_LIBS" -a -n "$PCRE_CFLAGS" ; then
168 AC_SUBST([PCRE_CFLAGS]) 170 AC_SUBST([PCRE_CFLAGS])
169 AC_SUBST([PCRE_LIBS]) 171 AC_SUBST([PCRE_LIBS])
170 : 172 :
171else 173else
172 PKG_CHECK_MODULES([PCRE],[libpcre],,[ 174 PKG_CHECK_MODULES([PCRE],[libpcre],,[
173 AC_MSG_ERROR([no libpcre found, go get it at http://www.pcre.org/]) 175 AC_MSG_ERROR([no libpcre found, go get it at http://www.pcre.org/])
174 ]) 176 ])
175fi 177fi
176 178
177PKG_CHECK_MODULES([SQLITE3],[sqlite3],[have_sqlite3=true],[have_sqlite3=false]) 179PKG_CHECK_MODULES([SQLITE3],[sqlite3],[have_sqlite3=true],[have_sqlite3=false])
178AM_CONDITIONAL([HAVE_SQLITE3],[$have_sqlite3]) 180AM_CONDITIONAL([HAVE_SQLITE3],[$have_sqlite3])
179PKG_CHECK_MODULES([KINGATE],[kingate-plaincgi],[have_kingate=true],[have_kingate=false]) 181PKG_CHECK_MODULES([KINGATE],[kingate-plaincgi],[have_kingate=true],[have_kingate=false])
180AM_CONDITIONAL([HAVE_KINGATE],[$have_kingate]) 182AM_CONDITIONAL([HAVE_KINGATE],[$have_kingate])
181PKG_CHECK_MODULES([UUID],[uuid],[have_uuid=true],[have_uuid=false]) 183PKG_CHECK_MODULES([UUID],[uuid],[have_uuid=true],[have_uuid=false])
182AM_CONDITIONAL([HAVE_UUID],[$have_uuid]) 184AM_CONDITIONAL([HAVE_UUID],[$have_uuid])
183if $have_uuid ; then 185if $have_uuid ; then
184 AC_DEFINE([HAVE_LIBUUID],,[defined in presence of libuuid]) 186 AC_DEFINE([HAVE_LIBUUID],,[defined in presence of libuuid])
185 AC_SUBST([UUID_UUID],[uuid]) 187 AC_SUBST([UUID_UUID],[uuid])
186fi 188fi
187 189
188curl_ssl_verify_host="true" 190curl_ssl_verify_host="true"
189AC_ARG_ENABLE([ssl-verify-host], 191AC_ARG_ENABLE([ssl-verify-host],
190 AC_HELP_STRING([--disable-ssl-verify-host],[disable cURL cert/host relationships verification]), 192 AC_HELP_STRING([--disable-ssl-verify-host],[disable cURL cert/host relationships verification]),
191 [ test "${enableval}" = "no" && curl_ssl_verify_host="false" ] 193 [ test "${enableval}" = "no" && curl_ssl_verify_host="false" ]
192) 194)
193${curl_ssl_verify_host} || AC_DEFINE([DISABLE_CURL_SSL_VERIFYHOST],,[defined if cURL is not to verify cert/host]) 195${curl_ssl_verify_host} || AC_DEFINE([DISABLE_CURL_SSL_VERIFYHOST],,[defined if cURL is not to verify cert/host])
194 196
195curl_ssl_verify_peer="true" 197curl_ssl_verify_peer="true"
diff --git a/include/opkele/expat.h b/include/opkele/expat.h
index 3ab1630..21be003 100644
--- a/include/opkele/expat.h
+++ b/include/opkele/expat.h
@@ -1,91 +1,94 @@
1#ifndef __OPKELE_EXPAT_H 1#ifndef __OPKELE_EXPAT_H
2#define __OPKELE_EXPAT_H 2#define __OPKELE_EXPAT_H
3 3
4#include <cassert> 4#include <cassert>
5#include <expat.h> 5#include <expat.h>
6 6
7namespace opkele { 7namespace opkele {
8 8
9 namespace util { 9 namespace util {
10 10
11 class expat_t { 11 class expat_t {
12 public: 12 public:
13 XML_Parser _x; 13 XML_Parser _x;
14 14
15 expat_t() : _x(0) { } 15 expat_t() : _x(0) { }
16 expat_t(XML_Parser x) : _x(x) { } 16 expat_t(XML_Parser x) : _x(x) { }
17 virtual ~expat_t() throw(); 17 virtual ~expat_t() throw();
18 18
19 expat_t& operator=(XML_Parser x); 19 expat_t& operator=(XML_Parser x);
20 20
21 operator const XML_Parser(void) const { return _x; } 21 operator const XML_Parser(void) const { return _x; }
22 operator XML_Parser(void) { return _x; } 22 operator XML_Parser(void) { return _x; }
23 23
24 inline bool parse(const char *s,int len,bool final=false) { 24 inline bool parse(const char *s,int len,bool final=false) {
25 assert(_x); 25 assert(_x);
26 return XML_Parse(_x,s,len,final); 26 return XML_Parse(_x,s,len,final);
27 } 27 }
28 28
29 virtual int unknown_encoding(const XML_Char * /* n */,XML_Encoding * /* i */) { return XML_STATUS_ERROR; }
30 void set_unknown_encoding_handler();
31
29 virtual void start_element(const XML_Char * /* n */,const XML_Char ** /* a */) { } 32 virtual void start_element(const XML_Char * /* n */,const XML_Char ** /* a */) { }
30 virtual void end_element(const XML_Char * /* n */) { } 33 virtual void end_element(const XML_Char * /* n */) { }
31 void set_element_handler(); 34 void set_element_handler();
32 35
33 virtual void character_data(const XML_Char * /* s */,int /* l */) { } 36 virtual void character_data(const XML_Char * /* s */,int /* l */) { }
34 void set_character_data_handler(); 37 void set_character_data_handler();
35 38
36 virtual void processing_instruction(const XML_Char * /* t */,const XML_Char * /* d */) { } 39 virtual void processing_instruction(const XML_Char * /* t */,const XML_Char * /* d */) { }
37 void set_processing_instruction_handler(); 40 void set_processing_instruction_handler();
38 41
39 virtual void comment(const XML_Char * /* d */) { } 42 virtual void comment(const XML_Char * /* d */) { }
40 void set_comment_handler(); 43 void set_comment_handler();
41 44
42 virtual void start_cdata_section() { } 45 virtual void start_cdata_section() { }
43 virtual void end_cdata_section() { } 46 virtual void end_cdata_section() { }
44 void set_cdata_section_handler(); 47 void set_cdata_section_handler();
45 48
46 virtual void default_handler(const XML_Char * /* s */,int /* l */) { } 49 virtual void default_handler(const XML_Char * /* s */,int /* l */) { }
47 void set_default_handler(); 50 void set_default_handler();
48 void set_default_handler_expand(); 51 void set_default_handler_expand();
49 52
50 virtual void start_namespace_decl(const XML_Char * /* p */,const XML_Char * /* u */) { } 53 virtual void start_namespace_decl(const XML_Char * /* p */,const XML_Char * /* u */) { }
51 virtual void end_namespace_decl(const XML_Char * /* p */) { } 54 virtual void end_namespace_decl(const XML_Char * /* p */) { }
52 void set_namespace_decl_handler(); 55 void set_namespace_decl_handler();
53 56
54 inline enum XML_Error get_error_code() { 57 inline enum XML_Error get_error_code() {
55 assert(_x); return XML_GetErrorCode(_x); } 58 assert(_x); return XML_GetErrorCode(_x); }
56 static inline const XML_LChar *error_string(XML_Error c) { 59 static inline const XML_LChar *error_string(XML_Error c) {
57 return XML_ErrorString(c); } 60 return XML_ErrorString(c); }
58 61
59 inline long get_current_byte_index() { 62 inline long get_current_byte_index() {
60 assert(_x); return XML_GetCurrentByteIndex(_x); } 63 assert(_x); return XML_GetCurrentByteIndex(_x); }
61 inline int get_current_line_number() { 64 inline int get_current_line_number() {
62 assert(_x); return XML_GetCurrentLineNumber(_x); } 65 assert(_x); return XML_GetCurrentLineNumber(_x); }
63 inline int get_current_column_number() { 66 inline int get_current_column_number() {
64 assert(_x); return XML_GetCurrentColumnNumber(_x); } 67 assert(_x); return XML_GetCurrentColumnNumber(_x); }
65 68
66 inline void set_user_data() { 69 inline void set_user_data() {
67 assert(_x); XML_SetUserData(_x,this); } 70 assert(_x); XML_SetUserData(_x,this); }
68 71
69 inline bool set_base(const XML_Char *b) { 72 inline bool set_base(const XML_Char *b) {
70 assert(_x); return XML_SetBase(_x,b); } 73 assert(_x); return XML_SetBase(_x,b); }
71 inline const XML_Char *get_base() { 74 inline const XML_Char *get_base() {
72 assert(_x); return XML_GetBase(_x); } 75 assert(_x); return XML_GetBase(_x); }
73 76
74 inline int get_specified_attribute_count() { 77 inline int get_specified_attribute_count() {
75 assert(_x); return XML_GetSpecifiedAttributeCount(_x); } 78 assert(_x); return XML_GetSpecifiedAttributeCount(_x); }
76 79
77 inline bool set_param_entity_parsing(enum XML_ParamEntityParsing c) { 80 inline bool set_param_entity_parsing(enum XML_ParamEntityParsing c) {
78 assert(_x); return XML_SetParamEntityParsing(_x,c); } 81 assert(_x); return XML_SetParamEntityParsing(_x,c); }
79 82
80 inline static XML_Parser parser_create(const XML_Char *e=0) { 83 inline static XML_Parser parser_create(const XML_Char *e=0) {
81 return XML_ParserCreate(e); } 84 return XML_ParserCreate(e); }
82 inline static XML_Parser parser_create_ns(const XML_Char *e=0,XML_Char s='\t') { 85 inline static XML_Parser parser_create_ns(const XML_Char *e=0,XML_Char s='\t') {
83 return XML_ParserCreateNS(e,s); } 86 return XML_ParserCreateNS(e,s); }
84 87
85 }; 88 };
86 89
87 } 90 }
88 91
89} 92}
90 93
91#endif /* __OPKELE_EXPAT_H */ 94#endif /* __OPKELE_EXPAT_H */
diff --git a/lib/basic_rp.cc b/lib/basic_rp.cc
index 3cad71c..9c7113b 100644
--- a/lib/basic_rp.cc
+++ b/lib/basic_rp.cc
@@ -29,298 +29,299 @@ namespace opkele {
29 throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related assertion"); 29 throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related assertion");
30 assert(!claimed_id.empty()); 30 assert(!claimed_id.empty());
31 return identity; 31 return identity;
32 } 32 }
33 33
34 static void dh_get_secret( 34 static void dh_get_secret(
35 secret_t& secret, const basic_openid_message& om, 35 secret_t& secret, const basic_openid_message& om,
36 const char *exp_assoc, const char *exp_sess, 36 const char *exp_assoc, const char *exp_sess,
37 util::dh_t& dh, 37 util::dh_t& dh,
38 size_t d_len, unsigned char *(*d_fun)(const unsigned char*,size_t,unsigned char*), 38 size_t d_len, unsigned char *(*d_fun)(const unsigned char*,size_t,unsigned char*),
39 size_t exp_s_len) try { 39 size_t exp_s_len) try {
40 if(om.get_field("assoc_type")!=exp_assoc || om.get_field("session_type")!=exp_sess) 40 if(om.get_field("assoc_type")!=exp_assoc || om.get_field("session_type")!=exp_sess)
41 throw bad_input(OPKELE_CP_ "Unexpected associate response"); 41 throw bad_input(OPKELE_CP_ "Unexpected associate response");
42 util::bignum_t s_pub = util::base64_to_bignum(om.get_field("dh_server_public")); 42 util::bignum_t s_pub = util::base64_to_bignum(om.get_field("dh_server_public"));
43 vector<unsigned char> ck(DH_size(dh)+1); 43 vector<unsigned char> ck(DH_size(dh)+1);
44 unsigned char *ckptr = &(ck.front())+1; 44 unsigned char *ckptr = &(ck.front())+1;
45 int cklen = DH_compute_key(ckptr,s_pub,dh); 45 int cklen = DH_compute_key(ckptr,s_pub,dh);
46 if(cklen<0) 46 if(cklen<0)
47 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); 47 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()");
48 if(cklen && (*ckptr)&0x80) { 48 if(cklen && (*ckptr)&0x80) {
49 (*(--ckptr))=0; ++cklen; } 49 (*(--ckptr))=0; ++cklen; }
50 assert(d_len<=SHA256_DIGEST_LENGTH); 50 assert(d_len<=SHA256_DIGEST_LENGTH);
51 unsigned char key_digest[SHA256_DIGEST_LENGTH]; 51 unsigned char key_digest[SHA256_DIGEST_LENGTH];
52 secret.enxor_from_base64((*d_fun)(ckptr,cklen,key_digest),om.get_field("enc_mac_key")); 52 secret.enxor_from_base64((*d_fun)(ckptr,cklen,key_digest),om.get_field("enc_mac_key"));
53 if(secret.size()!=exp_s_len) 53 if(secret.size()!=exp_s_len)
54 throw bad_input(OPKELE_CP_ "Secret length isn't consistent with association type"); 54 throw bad_input(OPKELE_CP_ "Secret length isn't consistent with association type");
55 }catch(opkele::failed_lookup& ofl) { 55 }catch(opkele::failed_lookup& ofl) {
56 throw bad_input(OPKELE_CP_ "Incoherent response from OP"); 56 throw bad_input(OPKELE_CP_ "Incoherent response from OP");
57 } OPKELE_RETHROW 57 } OPKELE_RETHROW
58 58
59 static void direct_request(basic_openid_message& oum,const basic_openid_message& inm,const string& OP) { 59 static void direct_request(basic_openid_message& oum,const basic_openid_message& inm,const string& OP) {
60 util::curl_pick_t curl = util::curl_pick_t::easy_init(); 60 util::curl_pick_t curl = util::curl_pick_t::easy_init();
61 if(!curl) 61 if(!curl)
62 throw exception_curl(OPKELE_CP_ "failed to initialize curl"); 62 throw exception_curl(OPKELE_CP_ "failed to initialize curl");
63 string request = inm.query_string(); 63 string request = inm.query_string();
64 CURLcode r; 64 CURLcode r;
65 (r=curl.misc_sets()) 65 (r=curl.misc_sets())
66 || (r=curl.easy_setopt(CURLOPT_URL,OP.c_str())) 66 || (r=curl.easy_setopt(CURLOPT_URL,OP.c_str()))
67 || (r=curl.easy_setopt(CURLOPT_POST,1)) 67 || (r=curl.easy_setopt(CURLOPT_POST,1))
68 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) 68 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data()))
69 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) 69 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length()))
70 || (r=curl.set_write()); 70 || (r=curl.set_write());
71 if(r) 71 if(r)
72 throw exception_curl(OPKELE_CP_ "failed to set curly options",r); 72 throw exception_curl(OPKELE_CP_ "failed to set curly options",r);
73 if( (r=curl.easy_perform()) ) 73 if( (r=curl.easy_perform()) )
74 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); 74 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r);
75 oum.from_keyvalues(curl.response); 75 oum.from_keyvalues(curl.response);
76 } 76 }
77 77
78 78
79 assoc_t basic_RP::associate(const string& OP) { 79 assoc_t basic_RP::associate(const string& OP) {
80 util::dh_t dh = DH_new(); 80 util::dh_t dh = DH_new();
81 if(!dh) 81 if(!dh)
82 throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); 82 throw exception_openssl(OPKELE_CP_ "failed to DH_new()");
83 dh->p = util::dec_to_bignum(data::_default_p); 83 dh->p = util::dec_to_bignum(data::_default_p);
84 dh->g = util::dec_to_bignum(data::_default_g); 84 dh->g = util::dec_to_bignum(data::_default_g);
85 if(!DH_generate_key(dh)) 85 if(!DH_generate_key(dh))
86 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); 86 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()");
87 openid_message_t req; 87 openid_message_t req;
88 req.set_field("ns",OIURI_OPENID20); 88 req.set_field("ns",OIURI_OPENID20);
89 req.set_field("mode","associate"); 89 req.set_field("mode","associate");
90 req.set_field("dh_modulus",util::bignum_to_base64(dh->p)); 90 req.set_field("dh_modulus",util::bignum_to_base64(dh->p));
91 req.set_field("dh_gen",util::bignum_to_base64(dh->g)); 91 req.set_field("dh_gen",util::bignum_to_base64(dh->g));
92 req.set_field("dh_consumer_public",util::bignum_to_base64(dh->pub_key)); 92 req.set_field("dh_consumer_public",util::bignum_to_base64(dh->pub_key));
93 openid_message_t res; 93 openid_message_t res;
94 req.set_field("assoc_type","HMAC-SHA256"); 94 req.set_field("assoc_type","HMAC-SHA256");
95 req.set_field("session_type","DH-SHA256"); 95 req.set_field("session_type","DH-SHA256");
96 secret_t secret; 96 secret_t secret;
97 int expires_in; 97 int expires_in;
98 try { 98 try {
99 direct_request(res,req,OP); 99 direct_request(res,req,OP);
100 dh_get_secret( secret, res, 100 dh_get_secret( secret, res,
101 "HMAC-SHA256", "DH-SHA256", 101 "HMAC-SHA256", "DH-SHA256",
102 dh, SHA256_DIGEST_LENGTH, SHA256, SHA256_DIGEST_LENGTH ); 102 dh, SHA256_DIGEST_LENGTH, SHA256, SHA256_DIGEST_LENGTH );
103 expires_in = util::string_to_long(res.get_field("expires_in")); 103 expires_in = util::string_to_long(res.get_field("expires_in"));
104 }catch(exception&) { 104 }catch(exception&) {
105 try { 105 try {
106 req.set_field("assoc_type","HMAC-SHA1"); 106 req.set_field("assoc_type","HMAC-SHA1");
107 req.set_field("session_type","DH-SHA1"); 107 req.set_field("session_type","DH-SHA1");
108 direct_request(res,req,OP); 108 direct_request(res,req,OP);
109 dh_get_secret( secret, res, 109 dh_get_secret( secret, res,
110 "HMAC-SHA1", "DH-SHA1", 110 "HMAC-SHA1", "DH-SHA1",
111 dh, SHA_DIGEST_LENGTH, SHA1, SHA_DIGEST_LENGTH ); 111 dh, SHA_DIGEST_LENGTH, SHA1, SHA_DIGEST_LENGTH );
112 expires_in = util::string_to_long(res.get_field("expires_in")); 112 expires_in = util::string_to_long(res.get_field("expires_in"));
113 }catch(bad_input&) { 113 }catch(bad_input&) {
114 throw dumb_RP(OPKELE_CP_ "OP failed to supply an association"); 114 throw dumb_RP(OPKELE_CP_ "OP failed to supply an association");
115 } 115 }
116 } 116 }
117 return store_assoc( 117 return store_assoc(
118 OP, res.get_field("assoc_handle"), 118 OP, res.get_field("assoc_handle"),
119 res.get_field("assoc_type"), secret, 119 res.get_field("assoc_type"), secret,
120 expires_in ); 120 expires_in );
121 } 121 }
122 122
123 basic_openid_message& basic_RP::checkid_( 123 basic_openid_message& basic_RP::checkid_(
124 basic_openid_message& rv, 124 basic_openid_message& rv,
125 mode_t mode, 125 mode_t mode,
126 const string& return_to,const string& realm, 126 const string& return_to,const string& realm,
127 extension_t *ext) { 127 extension_t *ext) {
128 rv.reset_fields(); 128 rv.reset_fields();
129 rv.set_field("ns",OIURI_OPENID20); 129 rv.set_field("ns",OIURI_OPENID20);
130 if(mode==mode_checkid_immediate) 130 if(mode==mode_checkid_immediate)
131 rv.set_field("mode","checkid_immediate"); 131 rv.set_field("mode","checkid_immediate");
132 else if(mode==mode_checkid_setup) 132 else if(mode==mode_checkid_setup)
133 rv.set_field("mode","checkid_setup"); 133 rv.set_field("mode","checkid_setup");
134 else 134 else
135 throw bad_input(OPKELE_CP_ "unknown checkid_* mode"); 135 throw bad_input(OPKELE_CP_ "unknown checkid_* mode");
136 if(realm.empty() && return_to.empty()) 136 if(realm.empty() && return_to.empty())
137 throw bad_input(OPKELE_CP_ "At least one of realm and return_to must be non-empty"); 137 throw bad_input(OPKELE_CP_ "At least one of realm and return_to must be non-empty");
138 if(!realm.empty()) { 138 if(!realm.empty()) {
139 rv.set_field("realm",realm); 139 rv.set_field("realm",realm);
140 rv.set_field("trust_root",realm); 140 rv.set_field("trust_root",realm);
141 } 141 }
142 if(!return_to.empty()) 142 if(!return_to.empty())
143 rv.set_field("return_to",return_to); 143 rv.set_field("return_to",return_to);
144 const openid_endpoint_t& ep = get_endpoint(); 144 const openid_endpoint_t& ep = get_endpoint();
145 rv.set_field("claimed_id",ep.claimed_id); 145 rv.set_field("claimed_id",ep.claimed_id);
146 rv.set_field("identity",ep.local_id); 146 rv.set_field("identity",ep.local_id);
147 try { 147 try {
148 rv.set_field("assoc_handle",find_assoc(ep.uri)->handle()); 148 rv.set_field("assoc_handle",find_assoc(ep.uri)->handle());
149 }catch(dumb_RP& drp) { 149 }catch(dumb_RP& drp) {
150 }catch(failed_lookup& fl) { 150 }catch(failed_lookup& fl) {
151 try { 151 try {
152 rv.set_field("assoc_handle",associate(ep.uri)->handle()); 152 rv.set_field("assoc_handle",associate(ep.uri)->handle());
153 }catch(dumb_RP& drp) { } 153 }catch(dumb_RP& drp) { }
154 } OPKELE_RETHROW 154 } OPKELE_RETHROW
155 if(ext) ext->rp_checkid_hook(rv); 155 if(ext) ext->rp_checkid_hook(rv);
156 return rv; 156 return rv;
157 } 157 }
158 158
159 class signed_part_message_proxy : public basic_openid_message { 159 class signed_part_message_proxy : public basic_openid_message {
160 public: 160 public:
161 const basic_openid_message& x; 161 const basic_openid_message& x;
162 set<string> signeds; 162 set<string> signeds;
163 163
164 signed_part_message_proxy(const basic_openid_message& xx) : x(xx) { 164 signed_part_message_proxy(const basic_openid_message& xx) : x(xx) {
165 const string& slist = x.get_field("signed"); 165 const string& slist = x.get_field("signed");
166 string::size_type p = 0; 166 string::size_type p = 0;
167 while(true) { 167 while(true) {
168 string::size_type co = slist.find(',',p); 168 string::size_type co = slist.find(',',p);
169 string f = (co==string::npos) 169 string f = (co==string::npos)
170 ?slist.substr(p):slist.substr(p,co-p); 170 ?slist.substr(p):slist.substr(p,co-p);
171 signeds.insert(f); 171 signeds.insert(f);
172 if(co==string::npos) break; 172 if(co==string::npos) break;
173 p = co+1; 173 p = co+1;
174 } 174 }
175 } 175 }
176 176
177 bool has_field(const string& n) const { 177 bool has_field(const string& n) const {
178 return signeds.find(n)!=signeds.end() && x.has_field(n); } 178 return signeds.find(n)!=signeds.end() && x.has_field(n); }
179 const string& get_field(const string& n) const { 179 const string& get_field(const string& n) const {
180 if(signeds.find(n)==signeds.end()) 180 if(signeds.find(n)==signeds.end())
181 throw failed_lookup(OPKELE_CP_ "The field isn't known to be signed"); 181 throw failed_lookup(OPKELE_CP_ "The field isn't known to be signed");
182 return x.get_field(n); } 182 return x.get_field(n); }
183 183
184 fields_iterator fields_begin() const { 184 fields_iterator fields_begin() const {
185 return signeds.begin(); } 185 return signeds.begin(); }
186 fields_iterator fields_end() const { 186 fields_iterator fields_end() const {
187 return signeds.end(); } 187 return signeds.end(); }
188 }; 188 };
189 189
190 static void parse_query(const string& u,string::size_type q, 190 static void parse_query(const string& u,string::size_type q,
191 map<string,string>& p) { 191 map<string,string>& p) {
192 if(q==string::npos) 192 if(q==string::npos)
193 return; 193 return;
194 assert(u[q]=='?'); 194 assert(u[q]=='?');
195 ++q; 195 ++q;
196 string::size_type l = u.size(); 196 string::size_type l = u.size();
197 while(q<l) { 197 while(q<l) {
198 string::size_type eq = u.find('=',q); 198 string::size_type eq = u.find('=',q);
199 string::size_type am = u.find('&',q); 199 string::size_type am = u.find('&',q);
200 if(am==string::npos) { 200 if(am==string::npos) {
201 if(eq==string::npos) { 201 if(eq==string::npos) {
202 p[""] = u.substr(q); 202 p[""] = u.substr(q);
203 }else{ 203 }else{
204 p[u.substr(q,eq-q)] = u.substr(eq+1); 204 p[u.substr(q,eq-q)] = u.substr(eq+1);
205 } 205 }
206 break; 206 break;
207 }else{ 207 }else{
208 if(eq==string::npos || eq>am) { 208 if(eq==string::npos || eq>am) {
209 p[""] = u.substr(q,eq-q); 209 p[""] = u.substr(q,eq-q);
210 }else{ 210 }else{
211 p[u.substr(q,eq-q)] = u.substr(eq+1,am-eq-1); 211 p[u.substr(q,eq-q)] = u.substr(eq+1,am-eq-1);
212 } 212 }
213 q = ++am; 213 q = ++am;
214 } 214 }
215 } 215 }
216 } 216 }
217 217
218 void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) { 218 void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) {
219 reset_vars(); 219 reset_vars();
220 bool o2 = om.has_field("ns") 220 bool o2 = om.has_field("ns")
221 && om.get_field("ns")==OIURI_OPENID20; 221 && om.get_field("ns")==OIURI_OPENID20
222 && om.has_field("op_endpoint") && !om.get_field("op_endpoint").empty();
222 if( (!o2) && om.has_field("user_setup_url")) 223 if( (!o2) && om.has_field("user_setup_url"))
223 throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided", 224 throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided",
224 om.get_field("user_setup_url")); 225 om.get_field("user_setup_url"));
225 string m = om.get_field("mode"); 226 string m = om.get_field("mode");
226 if(o2 && m=="setup_needed") 227 if(o2 && m=="setup_needed")
227 throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided"); 228 throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided");
228 if(m=="cancel") 229 if(m=="cancel")
229 throw id_res_cancel(OPKELE_CP_ "authentication cancelled"); 230 throw id_res_cancel(OPKELE_CP_ "authentication cancelled");
230 bool go_dumb=false; 231 bool go_dumb=false;
231 try { 232 try {
232 string OP = o2 233 string OP = o2
233 ?om.get_field("op_endpoint") 234 ?om.get_field("op_endpoint")
234 :get_endpoint().uri; 235 :get_endpoint().uri;
235 assoc_t assoc = retrieve_assoc( 236 assoc_t assoc = retrieve_assoc(
236 OP,om.get_field("assoc_handle")); 237 OP,om.get_field("assoc_handle"));
237 if(om.get_field("sig")!=util::base64_signature(assoc,om)) 238 if(om.get_field("sig")!=util::base64_signature(assoc,om))
238 throw id_res_mismatch(OPKELE_CP_ "signature mismatch"); 239 throw id_res_mismatch(OPKELE_CP_ "signature mismatch");
239 }catch(dumb_RP& drp) { 240 }catch(dumb_RP& drp) {
240 go_dumb=true; 241 go_dumb=true;
241 }catch(failed_lookup& e) { 242 }catch(failed_lookup& e) {
242 go_dumb=true; 243 go_dumb=true;
243 } OPKELE_RETHROW 244 } OPKELE_RETHROW
244 if(go_dumb) { 245 if(go_dumb) {
245 try { 246 try {
246 string OP = o2 247 string OP = o2
247 ?om.get_field("op_endpoint") 248 ?om.get_field("op_endpoint")
248 :get_endpoint().uri; 249 :get_endpoint().uri;
249 check_authentication(OP,om); 250 check_authentication(OP,om);
250 }catch(failed_check_authentication& fca) { 251 }catch(failed_check_authentication& fca) {
251 throw id_res_failed(OPKELE_CP_ "failed to check_authentication()"); 252 throw id_res_failed(OPKELE_CP_ "failed to check_authentication()");
252 } OPKELE_RETHROW 253 } OPKELE_RETHROW
253 } 254 }
254 signed_part_message_proxy signeds(om); 255 signed_part_message_proxy signeds(om);
255 if(o2) { 256 if(o2) {
256 check_nonce(om.get_field("op_endpoint"), 257 check_nonce(om.get_field("op_endpoint"),
257 om.get_field("response_nonce")); 258 om.get_field("response_nonce"));
258 static const char *mustsign[] = { 259 static const char *mustsign[] = {
259 "op_endpoint", "return_to", "response_nonce", "assoc_handle", 260 "op_endpoint", "return_to", "response_nonce", "assoc_handle",
260 "claimed_id", "identity" }; 261 "claimed_id", "identity" };
261 for(size_t ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) { 262 for(size_t ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) {
262 if(om.has_field(mustsign[ms]) && !signeds.has_field(mustsign[ms])) 263 if(om.has_field(mustsign[ms]) && !signeds.has_field(mustsign[ms]))
263 throw bad_input(OPKELE_CP_ string("Field '")+mustsign[ms]+"' is not signed against the specs"); 264 throw bad_input(OPKELE_CP_ string("Field '")+mustsign[ms]+"' is not signed against the specs");
264 } 265 }
265 if( ( 266 if( (
266 (om.has_field("claimed_id")?1:0) 267 (om.has_field("claimed_id")?1:0)
267 ^ 268 ^
268 (om.has_field("identity")?1:0) 269 (om.has_field("identity")?1:0)
269 )&1 ) 270 )&1 )
270 throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent"); 271 throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent");
271 272
272 string turl = util::rfc_3986_normalize_uri(get_this_url()); 273 string turl = util::rfc_3986_normalize_uri(get_this_url());
273 util::strip_uri_fragment_part(turl); 274 util::strip_uri_fragment_part(turl);
274 string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to")); 275 string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to"));
275 util::strip_uri_fragment_part(rurl); 276 util::strip_uri_fragment_part(rurl);
276 string::size_type 277 string::size_type
277 tq = turl.find('?'), rq = rurl.find('?'); 278 tq = turl.find('?'), rq = rurl.find('?');
278 if( 279 if(
279 ((tq==string::npos)?turl:turl.substr(0,tq)) 280 ((tq==string::npos)?turl:turl.substr(0,tq))
280 != 281 !=
281 ((rq==string::npos)?rurl:rurl.substr(0,rq)) 282 ((rq==string::npos)?rurl:rurl.substr(0,rq))
282 ) 283 )
283 throw id_res_bad_return_to(OPKELE_CP_ "return_to url doesn't match request url"); 284 throw id_res_bad_return_to(OPKELE_CP_ "return_to url doesn't match request url");
284 map<string,string> tp; parse_query(turl,tq,tp); 285 map<string,string> tp; parse_query(turl,tq,tp);
285 map<string,string> rp; parse_query(rurl,rq,rp); 286 map<string,string> rp; parse_query(rurl,rq,rp);
286 for(map<string,string>::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) { 287 for(map<string,string>::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) {
287 map<string,string>::const_iterator tpi = tp.find(rpi->first); 288 map<string,string>::const_iterator tpi = tp.find(rpi->first);
288 if(tpi==tp.end()) 289 if(tpi==tp.end())
289 throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to is missing from the request"); 290 throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to is missing from the request");
290 if(tpi->second!=rpi->second) 291 if(tpi->second!=rpi->second)
291 throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to doesn't matche the request"); 292 throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to doesn't matche the request");
292 } 293 }
293 294
294 if(om.has_field("claimed_id")) { 295 if(om.has_field("claimed_id")) {
295 claimed_id = om.get_field("claimed_id"); 296 claimed_id = om.get_field("claimed_id");
296 identity = om.get_field("identity"); 297 identity = om.get_field("identity");
297 verify_OP( 298 verify_OP(
298 om.get_field("op_endpoint"), 299 om.get_field("op_endpoint"),
299 claimed_id, identity ); 300 claimed_id, identity );
300 } 301 }
301 302
302 }else{ 303 }else{
303 claimed_id = get_endpoint().claimed_id; 304 claimed_id = get_endpoint().claimed_id;
304 /* TODO: check if this is the identity we asked for */ 305 /* TODO: check if this is the identity we asked for */
305 identity = om.get_field("identity"); 306 identity = om.get_field("identity");
306 } 307 }
307 if(ext) ext->rp_id_res_hook(om,signeds); 308 if(ext) ext->rp_id_res_hook(om,signeds);
308 } 309 }
309 310
310 void basic_RP::check_authentication(const string& OP, 311 void basic_RP::check_authentication(const string& OP,
311 const basic_openid_message& om){ 312 const basic_openid_message& om){
312 openid_message_t res; 313 openid_message_t res;
313 static const string checkauthmode = "check_authentication"; 314 static const string checkauthmode = "check_authentication";
314 direct_request(res,util::change_mode_message_proxy(om,checkauthmode),OP); 315 direct_request(res,util::change_mode_message_proxy(om,checkauthmode),OP);
315 if(res.has_field("is_valid")) { 316 if(res.has_field("is_valid")) {
316 if(res.get_field("is_valid")=="true") { 317 if(res.get_field("is_valid")=="true") {
317 if(res.has_field("invalidate_handle")) 318 if(res.has_field("invalidate_handle"))
318 invalidate_assoc(OP,res.get_field("invalidate_handle")); 319 invalidate_assoc(OP,res.get_field("invalidate_handle"));
319 return; 320 return;
320 } 321 }
321 } 322 }
322 throw failed_check_authentication( 323 throw failed_check_authentication(
323 OPKELE_CP_ "failed to verify response"); 324 OPKELE_CP_ "failed to verify response");
324 } 325 }
325 326
326} 327}
diff --git a/lib/discovery.cc b/lib/discovery.cc
index bd1f917..b4ed3b6 100644
--- a/lib/discovery.cc
+++ b/lib/discovery.cc
@@ -94,494 +94,517 @@ namespace opkele {
94 string save_html; 94 string save_html;
95 95
96 XRD_t *xrd; 96 XRD_t *xrd;
97 service_t *xrd_service; 97 service_t *xrd_service;
98 string* cdata; 98 string* cdata;
99 99
100 idigger_t() 100 idigger_t()
101 : util::curl_t(easy_init()), 101 : util::curl_t(easy_init()),
102 util::expat_t(0), 102 util::expat_t(0),
103 xri_proxy(XRI_PROXY_URL) { 103 xri_proxy(XRI_PROXY_URL) {
104 CURLcode r; 104 CURLcode r;
105 (r=misc_sets()) 105 (r=misc_sets())
106 || (r=set_write()) 106 || (r=set_write())
107 || (r=set_header()) 107 || (r=set_header())
108 ; 108 ;
109 if(r) 109 if(r)
110 throw exception_curl(OPKELE_CP_ "failed to set curly options",r); 110 throw exception_curl(OPKELE_CP_ "failed to set curly options",r);
111 } 111 }
112 ~idigger_t() throw() { } 112 ~idigger_t() throw() { }
113 113
114 void yadiscover(endpoint_discovery_iterator oi,const string& yurl,const char **types,bool redirs) { 114 void yadiscover(endpoint_discovery_iterator oi,const string& yurl,const char **types,bool redirs) {
115 idiscovery_t idis; 115 idiscovery_t idis;
116 idis.xri_identity = false; 116 idis.xri_identity = false;
117 discover_at(idis,yurl,xmode_html|xmode_xrd|(redirs?0:xmode_noredirs)); 117 discover_at(idis,yurl,xmode_html|xmode_xrd|(redirs?0:xmode_noredirs));
118 if(!xrds_location.empty()) { 118 if(!xrds_location.empty()) {
119 idis.clear(); 119 idis.clear();
120 discover_at(idis,xrds_location,xmode_xrd); 120 discover_at(idis,xrds_location,xmode_xrd);
121 } 121 }
122 idis.normalized_id = idis.canonicalized_id = yurl; 122 idis.normalized_id = idis.canonicalized_id = yurl;
123 service_type_t st; 123 service_type_t st;
124 for(st.uri=*types;*types;st.uri=*(++types)) 124 for(st.uri=*types;*types;st.uri=*(++types))
125 queue_endpoints(oi,idis,&st); 125 queue_endpoints(oi,idis,&st);
126 } 126 }
127 127
128 string discover(endpoint_discovery_iterator& oi,const string& identity) { 128 string discover(endpoint_discovery_iterator& oi,const string& identity) {
129 string rv; 129 string rv;
130 idiscovery_t idis; 130 idiscovery_t idis;
131 string::size_type fsc = identity.find_first_not_of(data::_whitespace_chars); 131 string::size_type fsc = identity.find_first_not_of(data::_whitespace_chars);
132 if(fsc==string::npos) 132 if(fsc==string::npos)
133 throw bad_input(OPKELE_CP_ "whitespace-only identity"); 133 throw bad_input(OPKELE_CP_ "whitespace-only identity");
134 string::size_type lsc = identity.find_last_not_of(data::_whitespace_chars); 134 string::size_type lsc = identity.find_last_not_of(data::_whitespace_chars);
135 assert(lsc!=string::npos); 135 assert(lsc!=string::npos);
136 if(!strncasecmp(identity.c_str()+fsc,"xri://",sizeof("xri://")-1)) 136 if(!strncasecmp(identity.c_str()+fsc,"xri://",sizeof("xri://")-1))
137 fsc += sizeof("xri://")-1; 137 fsc += sizeof("xri://")-1;
138 if((fsc+1)>=lsc) 138 if((fsc+1)>=lsc)
139 throw bad_input(OPKELE_CP_ "not a character of importance in identity"); 139 throw bad_input(OPKELE_CP_ "not a character of importance in identity");
140 string id(identity,fsc,lsc-fsc+1); 140 string id(identity,fsc,lsc-fsc+1);
141 idis.clear(); 141 idis.clear();
142 if(strchr(data::_iname_leaders,id[0])) { 142 if(strchr(data::_iname_leaders,id[0])) {
143 /* TODO: further normalize xri identity? Like folding case 143 /* TODO: further normalize xri identity? Like folding case
144 * or whatever... */ 144 * or whatever... */
145 rv = id; 145 rv = id;
146 set<string> cids; 146 set<string> cids;
147 for(const struct service_type_t *st=op_service_types; 147 for(const struct service_type_t *st=op_service_types;
148 st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) { 148 st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) {
149 idis.clear(); 149 idis.clear();
150 discover_at( idis, 150 discover_at( idis,
151 xri_proxy + util::url_encode(id)+ 151 xri_proxy + util::url_encode(id)+
152 "?_xrd_t="+util::url_encode(st->uri)+ 152 "?_xrd_t="+util::url_encode(st->uri)+
153 "&_xrd_r=application/xrd%2Bxml" 153 "&_xrd_r=application/xrd%2Bxml"
154 ";sep=true;refs=true", 154 ";sep=true;refs=true",
155 xmode_xrd ); 155 xmode_xrd );
156 if(status_code==241) continue; 156 if(status_code==241) continue;
157 if(status_code!=100) 157 if(status_code!=100)
158 throw failed_xri_resolution(OPKELE_CP_ 158 throw failed_xri_resolution(OPKELE_CP_
159 "XRI resolution failed with '"+status_string+"' message" 159 "XRI resolution failed with '"+status_string+"' message"
160 ", while looking for SEP with type '"+st->uri+"'", status_code); 160 ", while looking for SEP with type '"+st->uri+"'", status_code);
161 if(idis.xrd.canonical_ids.empty()) 161 if(idis.xrd.canonical_ids.empty())
162 throw opkele::failed_discovery(OPKELE_CP_ "No CanonicalID for XRI identity found"); 162 throw opkele::failed_discovery(OPKELE_CP_ "No CanonicalID for XRI identity found");
163 string cid = idis.xrd.canonical_ids.begin()->second; 163 string cid = idis.xrd.canonical_ids.begin()->second;
164 if(cids.find(cid)==cids.end()) { 164 if(cids.find(cid)==cids.end()) {
165 cids.insert(cid); 165 cids.insert(cid);
166 idis.clear(); 166 idis.clear();
167 discover_at( idis, 167 discover_at( idis,
168 xri_proxy + util::url_encode(id)+ 168 xri_proxy + util::url_encode(id)+
169 "?_xrd_t="+util::url_encode(st->uri)+ 169 "?_xrd_t="+util::url_encode(st->uri)+
170 "&_xrd_r=application/xrd%2Bxml" 170 "&_xrd_r=application/xrd%2Bxml"
171 ";sep=true;refs=true", 171 ";sep=true;refs=true",
172 xmode_xrd ); 172 xmode_xrd );
173 if(status_code==241) continue; 173 if(status_code==241) continue;
174 if(status_code!=100) 174 if(status_code!=100)
175 throw failed_xri_resolution(OPKELE_CP_ 175 throw failed_xri_resolution(OPKELE_CP_
176 "XRI resolution failed with '"+status_string+"' message" 176 "XRI resolution failed with '"+status_string+"' message"
177 ", while looking for SEP with type '"+st->uri+"'" 177 ", while looking for SEP with type '"+st->uri+"'"
178 " on canonical id", status_code); 178 " on canonical id", status_code);
179 } 179 }
180 idis.canonicalized_id = cid; 180 idis.canonicalized_id = cid;
181 idis.normalized_id = rv; idis.xri_identity = true; 181 idis.normalized_id = rv; idis.xri_identity = true;
182 queue_endpoints(oi,idis,st); 182 queue_endpoints(oi,idis,st);
183 } 183 }
184 }else{ 184 }else{
185 idis.xri_identity = false; 185 idis.xri_identity = false;
186 if(id.find("://")==string::npos) 186 if(id.find("://")==string::npos)
187 id.insert(0,"http://"); 187 id.insert(0,"http://");
188 string::size_type fp = id.find('#'); 188 string::size_type fp = id.find('#');
189 if(fp!=string::npos) { 189 if(fp!=string::npos) {
190 string::size_type qp = id.find('?'); 190 string::size_type qp = id.find('?');
191 if(qp==string::npos || qp<fp) 191 if(qp==string::npos || qp<fp)
192 id.erase(fp); 192 id.erase(fp);
193 else if(qp>fp) 193 else if(qp>fp)
194 id.erase(fp,qp-fp); 194 id.erase(fp,qp-fp);
195 } 195 }
196 rv = idis.normalized_id = util::rfc_3986_normalize_uri(id); 196 rv = idis.normalized_id = util::rfc_3986_normalize_uri(id);
197 discover_at(idis,id,xmode_html|xmode_xrd); 197 discover_at(idis,id,xmode_html|xmode_xrd);
198 const char * eu = 0; 198 const char * eu = 0;
199 CURLcode r = easy_getinfo(CURLINFO_EFFECTIVE_URL,&eu); 199 CURLcode r = easy_getinfo(CURLINFO_EFFECTIVE_URL,&eu);
200 if(r) 200 if(r)
201 throw exception_curl(OPKELE_CP_ "failed to get CURLINFO_EFFECTIVE_URL",r); 201 throw exception_curl(OPKELE_CP_ "failed to get CURLINFO_EFFECTIVE_URL",r);
202 string cid = util::strip_uri_fragment_part( idis.canonicalized_id = util::rfc_3986_normalize_uri(eu) ); 202 string cid = util::strip_uri_fragment_part( idis.canonicalized_id = util::rfc_3986_normalize_uri(eu) );
203 if(xrds_location.empty()) { 203 if(xrds_location.empty()) {
204 if(idis.xrd.empty()) 204 if(idis.xrd.empty())
205 html2xrd(oi,idis); 205 html2xrd(oi,idis);
206 else{ 206 else{
207 for(const service_type_t *st=op_service_types; 207 for(const service_type_t *st=op_service_types;
208 st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) 208 st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st)
209 queue_endpoints(oi,idis,st); 209 queue_endpoints(oi,idis,st);
210 } 210 }
211 }else{ 211 }else{
212 idis.clear(); 212 idis.clear();
213 idis.canonicalized_id = cid; 213 idis.canonicalized_id = cid;
214 discover_at(idis,xrds_location,xmode_xrd); 214 discover_at(idis,xrds_location,xmode_xrd);
215 if(idis.xrd.empty()) 215 if(idis.xrd.empty())
216 html2xrd(oi,idis); 216 html2xrd(oi,idis);
217 else{ 217 else{
218 for(const service_type_t *st=op_service_types; 218 for(const service_type_t *st=op_service_types;
219 st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) 219 st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st)
220 queue_endpoints(oi,idis,st); 220 queue_endpoints(oi,idis,st);
221 } 221 }
222 } 222 }
223 } 223 }
224 return rv; 224 return rv;
225 } 225 }
226 226
227 void discover_at(idiscovery_t& idis,const string& url,int xm) { 227 void discover_at(idiscovery_t& idis,const string& url,int xm) {
228 CURLcode r = easy_setopt(CURLOPT_MAXREDIRS, (xm&xmode_noredirs)?0:5); 228 CURLcode r = easy_setopt(CURLOPT_MAXREDIRS, (xm&xmode_noredirs)?0:5);
229 if(r) 229 if(r)
230 throw exception_curl(OPKELE_CP_ "failed to set curly maxredirs option"); 230 throw exception_curl(OPKELE_CP_ "failed to set curly maxredirs option");
231 if( (r=easy_setopt(CURLOPT_URL,url.c_str())) ) 231 if( (r=easy_setopt(CURLOPT_URL,url.c_str())) )
232 throw exception_curl(OPKELE_CP_ "failed to set curly urlie",r); 232 throw exception_curl(OPKELE_CP_ "failed to set curly urlie",r);
233 233
234 http_content_type.clear(); 234 http_content_type.clear();
235 xmode = xm; 235 xmode = xm;
236 prepare_to_parse(); 236 prepare_to_parse();
237 if(xmode&xmode_html) { 237 if(xmode&xmode_html) {
238 xrds_location.clear(); 238 xrds_location.clear();
239 save_html.clear(); 239 save_html.clear();
240 save_html.reserve(max_html); 240 save_html.reserve(max_html);
241 } 241 }
242 xrd = &idis.xrd; 242 xrd = &idis.xrd;
243 243
244 r = easy_perform(); 244 r = easy_perform();
245 if(r && r!=CURLE_WRITE_ERROR) 245 if(r && r!=CURLE_WRITE_ERROR)
246 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); 246 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r);
247 247
248 if(!parser_choked) { 248 if(!parser_choked) {
249 parse(0,0,true); 249 parse(0,0,true);
250 }else if(xmode&xmode_html){ 250 }else if(xmode&xmode_html){
251 /* TODO: do not bother if we've seen xml */ 251 /* TODO: do not bother if we've seen xml */
252 try { 252 try {
253 util::tidy_doc_t td = util::tidy_doc_t::create(); 253 util::tidy_doc_t td = util::tidy_doc_t::create();
254 if(!td) 254 if(!td)
255 throw exception_tidy(OPKELE_CP_ "failed to create htmltidy document"); 255 throw exception_tidy(OPKELE_CP_ "failed to create htmltidy document");
256#ifdef NDEBUG 256#ifdef NDEBUG
257 td.opt_set(TidyQuiet,true); 257 td.opt_set(TidyQuiet,true);
258 td.opt_set(TidyShowWarnings,false); 258 td.opt_set(TidyShowWarnings,false);
259#else /* NDEBUG */ 259#else /* NDEBUG */
260 td.opt_set(TidyQuiet,false); 260 td.opt_set(TidyQuiet,false);
261 td.opt_set(TidyShowWarnings,true); 261 td.opt_set(TidyShowWarnings,true);
262#endif /* NDEBUG */ 262#endif /* NDEBUG */
263 td.opt_set(TidyForceOutput,true); 263 td.opt_set(TidyForceOutput,true);
264 td.opt_set(TidyXhtmlOut,true); 264 td.opt_set(TidyXhtmlOut,true);
265 td.opt_set(TidyDoctypeMode,TidyDoctypeOmit); 265 td.opt_set(TidyDoctypeMode,TidyDoctypeOmit);
266 td.opt_set(TidyMark,false); 266 td.opt_set(TidyMark,false);
267 td.opt_set(TidyNumEntities,true); 267 td.opt_set(TidyNumEntities,true);
268 if(td.parse_string(save_html)<=0) 268 if(td.parse_string(save_html)<=0)
269 throw exception_tidy(OPKELE_CP_ "tidy failed to parse document"); 269 throw exception_tidy(OPKELE_CP_ "tidy failed to parse document");
270 if(td.clean_and_repair()<=0) 270 if(td.clean_and_repair()<=0)
271 throw exception_tidy(OPKELE_CP_ "tidy failed to clean and repair"); 271 throw exception_tidy(OPKELE_CP_ "tidy failed to clean and repair");
272 util::tidy_buf_t tide; 272 util::tidy_buf_t tide;
273 if(td.save_buffer(tide)<=0) 273 if(td.save_buffer(tide)<=0)
274 throw exception_tidy(OPKELE_CP_ "tidy failed to save buffer"); 274 throw exception_tidy(OPKELE_CP_ "tidy failed to save buffer");
275 prepare_to_parse(); 275 prepare_to_parse();
276 parse(tide.c_str(),tide.size(),true); 276 parse(tide.c_str(),tide.size(),true);
277 }catch(exception_tidy& et) { } 277 }catch(exception_tidy& et) { }
278 } 278 }
279 save_html.clear(); 279 save_html.clear();
280 } 280 }
281 281
282 void prepare_to_parse() { 282 void prepare_to_parse() {
283 (*(expat_t*)this) = parser_create_ns(); 283 (*(expat_t*)this) = parser_create_ns();
284 set_user_data(); set_element_handler(); 284 set_user_data(); set_element_handler();
285 set_character_data_handler(); 285 set_character_data_handler();
286 set_unknown_encoding_handler();
286 287
287 if(xmode&xmode_html) { 288 if(xmode&xmode_html) {
288 html_openid1.clear(); html_openid2.clear(); 289 html_openid1.clear(); html_openid2.clear();
289 parser_choked = false; 290 parser_choked = false;
290 } 291 }
291 292
292 cdata = 0; xrd_service = 0; skipping = 0; 293 cdata = 0; xrd_service = 0; skipping = 0;
293 pt_stack.clear(); 294 pt_stack.clear();
294 status_code = 100; status_string.clear(); 295 status_code = 100; status_string.clear();
295 } 296 }
296 297
297 void html2xrd(endpoint_discovery_iterator& oi,idiscovery_t& id) { 298 void html2xrd(endpoint_discovery_iterator& oi,idiscovery_t& id) {
298 XRD_t& x = id.xrd; 299 XRD_t& x = id.xrd;
299 if(!html_openid2.uris.empty()) { 300 if(!html_openid2.uris.empty()) {
300 html_openid2.types.insert(STURI_OPENID20); 301 html_openid2.types.insert(STURI_OPENID20);
301 x.services.add(-1,html_openid2); 302 x.services.add(-1,html_openid2);
302 queue_endpoints(oi,id,&op_service_types[st_index_2]); 303 queue_endpoints(oi,id,&op_service_types[st_index_2]);
303 } 304 }
304 if(!html_openid1.uris.empty()) { 305 if(!html_openid1.uris.empty()) {
305 html_openid1.types.insert(STURI_OPENID11); 306 html_openid1.types.insert(STURI_OPENID11);
306 x.services.add(-1,html_openid1); 307 x.services.add(-1,html_openid1);
307 queue_endpoints(oi,id,&op_service_types[st_index_1]); 308 queue_endpoints(oi,id,&op_service_types[st_index_1]);
308 } 309 }
309 } 310 }
310 311
311 size_t write(void *p,size_t s,size_t nm) { 312 size_t write(void *p,size_t s,size_t nm) {
312 /* TODO: limit total size */ 313 /* TODO: limit total size */
313 size_t bytes = s*nm; 314 size_t bytes = s*nm;
314 const char *inbuf = (const char*)p; 315 const char *inbuf = (const char*)p;
315 if(xmode&xmode_html) { 316 if(xmode&xmode_html) {
316 size_t mbts = save_html.capacity()-save_html.size(); 317 size_t mbts = save_html.capacity()-save_html.size();
317 size_t bts = 0; 318 size_t bts = 0;
318 if(mbts>0) { 319 if(mbts>0) {
319 bts = (bytes>mbts)?mbts:bytes; 320 bts = (bytes>mbts)?mbts:bytes;
320 save_html.append(inbuf,bts); 321 save_html.append(inbuf,bts);
321 } 322 }
322 if(skipping<0) return bts; 323 if(skipping<0) return bts;
323 } 324 }
324 if(skipping<0) return 0; 325 if(skipping<0) return 0;
325 bool rp = parse(inbuf,bytes,false); 326 bool rp = parse(inbuf,bytes,false);
326 if(!rp) { 327 if(!rp) {
327 parser_choked = true; 328 parser_choked = true;
328 skipping = -1; 329 skipping = -1;
329 if(!(xmode&xmode_html)) 330 if(!(xmode&xmode_html))
330 bytes = 0; 331 bytes = 0;
331 } 332 }
332 return bytes; 333 return bytes;
333 } 334 }
334 size_t header(void *p,size_t s,size_t nm) { 335 size_t header(void *p,size_t s,size_t nm) {
335 size_t bytes = s*nm; 336 size_t bytes = s*nm;
336 const char *h = (const char*)p; 337 const char *h = (const char*)p;
337 const char *colon = (const char*)memchr(p,':',bytes); 338 const char *colon = (const char*)memchr(p,':',bytes);
338 const char *space = (const char*)memchr(p,' ',bytes); 339 const char *space = (const char*)memchr(p,' ',bytes);
339 if(space && ( (!colon) || space<colon ) ) { 340 if(space && ( (!colon) || space<colon ) ) {
340 xrds_location.clear(); http_content_type.clear(); 341 xrds_location.clear(); http_content_type.clear();
341 }else if(colon) { 342 }else if(colon) {
342 const char *hv = ++colon; 343 const char *hv = ++colon;
343 size_t hnl = colon-h; 344 size_t hnl = colon-h;
344 int rb; 345 int rb;
345 for(rb = bytes-hnl-1;rb>0 && isspace(*hv);++hv,--rb) ; 346 for(rb = bytes-hnl-1;rb>0 && isspace(*hv);++hv,--rb) ;
346 while(rb>0 && isspace(hv[rb-1])) --rb; 347 while(rb>0 && isspace(hv[rb-1])) --rb;
347 if(rb) { 348 if(rb) {
348 if( (hnl>=sizeof(XRDS_HEADER)) 349 if( (hnl>=sizeof(XRDS_HEADER))
349 && !strncasecmp(h,XRDS_HEADER":", 350 && !strncasecmp(h,XRDS_HEADER":",
350 sizeof(XRDS_HEADER)) ) { 351 sizeof(XRDS_HEADER)) ) {
351 xrds_location.assign(hv,rb); 352 xrds_location.assign(hv,rb);
352 }else if( (hnl>=sizeof(CT_HEADER)) 353 }else if( (hnl>=sizeof(CT_HEADER))
353 && !strncasecmp(h,CT_HEADER":", 354 && !strncasecmp(h,CT_HEADER":",
354 sizeof(CT_HEADER)) ) { 355 sizeof(CT_HEADER)) ) {
355 const char *sc = (const char*)memchr( 356 const char *sc = (const char*)memchr(
356 hv,';',rb); 357 hv,';',rb);
357 http_content_type.assign(hv,sc?(sc-hv):rb); 358 http_content_type.assign(hv,sc?(sc-hv):rb);
358 } 359 }
359 } 360 }
360 } 361 }
361 return curl_t::header(p,s,nm); 362 return curl_t::header(p,s,nm);
362 } 363 }
363 364
364 void start_element(const XML_Char *n,const XML_Char **a) { 365 void start_element(const XML_Char *n,const XML_Char **a) {
365 if(skipping<0) return; 366 if(skipping<0) return;
366 if(skipping) { 367 if(skipping) {
367 if(xmode&xmode_html) 368 if(xmode&xmode_html)
368 html_start_element(n,a); 369 html_start_element(n,a);
369 ++skipping; return; 370 ++skipping; return;
370 } 371 }
371 if(pt_stack.empty()) { 372 if(pt_stack.empty()) {
372 if(is_qelement(n,NSURI_XRDS "\tXRDS")) 373 if(is_qelement(n,NSURI_XRDS "\tXRDS"))
373 return; 374 return;
374 if(is_qelement(n,NSURI_XRD "\tXRD")) { 375 if(is_qelement(n,NSURI_XRD "\tXRD")) {
375 assert(xrd); 376 assert(xrd);
376 xrd->clear(); 377 xrd->clear();
377 pt_stack.push_back(n); 378 pt_stack.push_back(n);
378 }else if(xmode&xmode_html) { 379 }else if(xmode&xmode_html) {
379 html_start_element(n,a); 380 html_start_element(n,a);
380 }else{ 381 }else{
381 skipping = -1; 382 skipping = -1;
382 } 383 }
383 }else{ 384 }else{
384 int pt_s = pt_stack.size(); 385 int pt_s = pt_stack.size();
385 if(pt_s==1) { 386 if(pt_s==1) {
386 if(is_qelement(n,NSURI_XRD "\tCanonicalID")) { 387 if(is_qelement(n,NSURI_XRD "\tCanonicalID")) {
387 assert(xrd); 388 assert(xrd);
388 cdata = &(xrd->canonical_ids.add(element_priority(a),string())); 389 cdata = &(xrd->canonical_ids.add(element_priority(a),string()));
389 }else if(is_qelement(n,NSURI_XRD "\tLocalID")) { 390 }else if(is_qelement(n,NSURI_XRD "\tLocalID")) {
390 assert(xrd); 391 assert(xrd);
391 cdata = &(xrd->local_ids.add(element_priority(a),string())); 392 cdata = &(xrd->local_ids.add(element_priority(a),string()));
392 }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { 393 }else if(is_qelement(n,NSURI_XRD "\tProviderID")) {
393 assert(xrd); 394 assert(xrd);
394 cdata = &(xrd->provider_id); 395 cdata = &(xrd->provider_id);
395 }else if(is_qelement(n,NSURI_XRD "\tService")) { 396 }else if(is_qelement(n,NSURI_XRD "\tService")) {
396 assert(xrd); 397 assert(xrd);
397 xrd_service = &(xrd->services.add(element_priority(a), 398 xrd_service = &(xrd->services.add(element_priority(a),
398 service_t())); 399 service_t()));
399 pt_stack.push_back(n); 400 pt_stack.push_back(n);
400 }else if(is_qelement(n,NSURI_XRD "\tStatus")) { 401 }else if(is_qelement(n,NSURI_XRD "\tStatus")) {
401 for(;*a;) { 402 for(;*a;) {
402 if(!strcasecmp(*(a++),"code")) { 403 if(!strcasecmp(*(a++),"code")) {
403 if(sscanf(*(a++),"%ld",&status_code)==1 && status_code!=100) { 404 if(sscanf(*(a++),"%ld",&status_code)==1 && status_code!=100) {
404 cdata = &status_string; 405 cdata = &status_string;
405 pt_stack.push_back(n); 406 pt_stack.push_back(n);
406 break; 407 break;
407 } 408 }
408 }else 409 }else
409 ++a; 410 ++a;
410 } 411 }
411 }else if(is_qelement(n,NSURI_XRD "\tExpires")) { 412 }else if(is_qelement(n,NSURI_XRD "\tExpires")) {
412 assert(xrd); 413 assert(xrd);
413 cdata_buf.clear(); 414 cdata_buf.clear();
414 cdata = &cdata_buf; 415 cdata = &cdata_buf;
415 }else if(xmode&xmode_html) { 416 }else if(xmode&xmode_html) {
416 html_start_element(n,a); 417 html_start_element(n,a);
417 }else{ 418 }else{
418 skipping = 1; 419 skipping = 1;
419 } 420 }
420 }else if(pt_s==2) { 421 }else if(pt_s==2) {
421 if(is_qelement(pt_stack.back().c_str(), NSURI_XRD "\tService")) { 422 if(is_qelement(pt_stack.back().c_str(), NSURI_XRD "\tService")) {
422 if(is_qelement(n,NSURI_XRD "\tType")) { 423 if(is_qelement(n,NSURI_XRD "\tType")) {
423 assert(xrd); assert(xrd_service); 424 assert(xrd); assert(xrd_service);
424 cdata_buf.clear(); 425 cdata_buf.clear();
425 cdata = &cdata_buf; 426 cdata = &cdata_buf;
426 }else if(is_qelement(n,NSURI_XRD "\tURI")) { 427 }else if(is_qelement(n,NSURI_XRD "\tURI")) {
427 assert(xrd); assert(xrd_service); 428 assert(xrd); assert(xrd_service);
428 const char *append = element_attr(a,"append"); 429 const char *append = element_attr(a,"append");
429 xrd::uri_t& uri = xrd_service->uris.add(element_priority(a),xrd::uri_t("",append?append:"")); 430 xrd::uri_t& uri = xrd_service->uris.add(element_priority(a),xrd::uri_t("",append?append:""));
430 cdata = &uri.uri; 431 cdata = &uri.uri;
431 }else if(is_qelement(n,NSURI_XRD "\tLocalID") 432 }else if(is_qelement(n,NSURI_XRD "\tLocalID")
432 || is_qelement(n,NSURI_OPENID10 "\tDelegate") ) { 433 || is_qelement(n,NSURI_OPENID10 "\tDelegate") ) {
433 assert(xrd); assert(xrd_service); 434 assert(xrd); assert(xrd_service);
434 cdata = &(xrd_service->local_ids.add(element_priority(a),string())); 435 cdata = &(xrd_service->local_ids.add(element_priority(a),string()));
435 }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { 436 }else if(is_qelement(n,NSURI_XRD "\tProviderID")) {
436 assert(xrd); assert(xrd_service); 437 assert(xrd); assert(xrd_service);
437 cdata = &(xrd_service->provider_id); 438 cdata = &(xrd_service->provider_id);
438 }else{ 439 }else{
439 skipping = 1; 440 skipping = 1;
440 } 441 }
441 }else 442 }else
442 skipping = 1; 443 skipping = 1;
443 }else if(xmode&xmode_html) { 444 }else if(xmode&xmode_html) {
444 html_start_element(n,a); 445 html_start_element(n,a);
445 }else{ 446 }else{
446 skipping = 1; 447 skipping = 1;
447 } 448 }
448 } 449 }
449 } 450 }
450 void end_element(const XML_Char *n) { 451 void end_element(const XML_Char *n) {
451 if(skipping<0) return; 452 if(skipping<0) return;
452 if(skipping) { 453 if(skipping) {
453 --skipping; return; 454 --skipping; return;
454 } 455 }
455 if(is_qelement(n,NSURI_XRD "\tType")) { 456 if(is_qelement(n,NSURI_XRD "\tType")) {
456 assert(xrd); assert(xrd_service); assert(cdata==&cdata_buf); 457 if(xrd && xrd_service) {
458 assert(cdata==&cdata_buf);
457 xrd_service->types.insert(cdata_buf); 459 xrd_service->types.insert(cdata_buf);
460 }
458 }else if(is_qelement(n,NSURI_XRD "\tService")) { 461 }else if(is_qelement(n,NSURI_XRD "\tService")) {
459 assert(xrd); assert(xrd_service); 462 if(!(xrd && xrd_service)) {
463 skipping = -1;
464 }else{
460 assert(!pt_stack.empty()); 465 assert(!pt_stack.empty());
461 assert(pt_stack.back()==(NSURI_XRD "\tService")); 466 assert(pt_stack.back()==(NSURI_XRD "\tService"));
462 pt_stack.pop_back(); 467 pt_stack.pop_back();
463 xrd_service = 0; 468 xrd_service = 0;
469 }
464 }else if(is_qelement(n,NSURI_XRD "\tStatus")) { 470 }else if(is_qelement(n,NSURI_XRD "\tStatus")) {
465 assert(xrd); 471 if(!xrd) {
472 skipping=-1;
473 }else{
466 if(is_qelement(pt_stack.back().c_str(),n)) { 474 if(is_qelement(pt_stack.back().c_str(),n)) {
467 assert(cdata==&status_string); 475 assert(cdata==&status_string);
468 pt_stack.pop_back(); 476 pt_stack.pop_back();
469 if(status_code!=100) 477 if(status_code!=100)
470 skipping = -1; 478 skipping = -1;
471 } 479 }
480 }
472 }else if(is_qelement(n,NSURI_XRD "\tExpires")) { 481 }else if(is_qelement(n,NSURI_XRD "\tExpires")) {
473 assert(xrd); 482 if(!xrd) {
483 skipping=-1;
484 }else{
474 xrd->expires = util::w3c_to_time(cdata_buf); 485 xrd->expires = util::w3c_to_time(cdata_buf);
486 }
487 }else if(is_qelement(n,NSURI_XRD "\tXRD")) {
488 assert(!pt_stack.empty());
489 assert(pt_stack.back()==(NSURI_XRD "\tXRD"));
490 pt_stack.pop_back();
475 }else if((xmode&xmode_html) && is_element(n,"head")) { 491 }else if((xmode&xmode_html) && is_element(n,"head")) {
476 skipping = -1; 492 skipping = -1;
477 } 493 }
478 cdata = 0; 494 cdata = 0;
479 } 495 }
480 void character_data(const XML_Char *s,int l) { 496 void character_data(const XML_Char *s,int l) {
481 if(skipping) return; 497 if(skipping) return;
482 if(cdata) cdata->append(s,l); 498 if(cdata) cdata->append(s,l);
483 } 499 }
484 500
485 void html_start_element(const XML_Char *n,const XML_Char **a) { 501 void html_start_element(const XML_Char *n,const XML_Char **a) {
486 if(is_element(n,"meta")) { 502 if(is_element(n,"meta")) {
487 bool heq = false; 503 bool heq = false;
488 string l; 504 string l;
489 for(;*a;a+=2) { 505 for(;*a;a+=2) {
490 if(!( strcasecmp(a[0],"http-equiv") 506 if(!( strcasecmp(a[0],"http-equiv")
491 || strcasecmp(a[1],XRDS_HEADER) )) 507 || strcasecmp(a[1],XRDS_HEADER) ))
492 heq = true; 508 heq = true;
493 else if(!strcasecmp(a[0],"content")) 509 else if(!strcasecmp(a[0],"content"))
494 l.assign(a[1]); 510 l.assign(a[1]);
495 } 511 }
496 if(heq) 512 if(heq)
497 xrds_location = l; 513 xrds_location = l;
498 }else if(is_element(n,"link")) { 514 }else if(is_element(n,"link")) {
499 string rels; 515 string rels;
500 string href; 516 string href;
501 for(;*a;a+=2) { 517 for(;*a;a+=2) {
502 if( !strcasecmp(a[0],"rel") ) { 518 if( !strcasecmp(a[0],"rel") ) {
503 rels.assign(a[1]); 519 rels.assign(a[1]);
504 }else if( !strcasecmp(a[0],"href") ) { 520 }else if( !strcasecmp(a[0],"href") ) {
505 const char *ns = a[1]; 521 const char *ns = a[1];
506 for(;*ns && isspace(*ns);++ns) ; 522 for(;*ns && isspace(*ns);++ns) ;
507 href.assign(ns); 523 href.assign(ns);
508 string::size_type lns=href.find_last_not_of(data::_whitespace_chars); 524 string::size_type lns=href.find_last_not_of(data::_whitespace_chars);
509 href.erase(lns+1); 525 href.erase(lns+1);
510 } 526 }
511 } 527 }
512 for(string::size_type ns=rels.find_first_not_of(data::_whitespace_chars); 528 for(string::size_type ns=rels.find_first_not_of(data::_whitespace_chars);
513 ns!=string::npos; ns=rels.find_first_not_of(data::_whitespace_chars,ns)) { 529 ns!=string::npos; ns=rels.find_first_not_of(data::_whitespace_chars,ns)) {
514 string::size_type s = rels.find_first_of(data::_whitespace_chars,ns); 530 string::size_type s = rels.find_first_of(data::_whitespace_chars,ns);
515 string rel; 531 string rel;
516 if(s==string::npos) { 532 if(s==string::npos) {
517 rel.assign(rels,ns,string::npos); 533 rel.assign(rels,ns,string::npos);
518 ns = string::npos; 534 ns = string::npos;
519 }else{ 535 }else{
520 rel.assign(rels,ns,s-ns); 536 rel.assign(rels,ns,s-ns);
521 ns = s; 537 ns = s;
522 } 538 }
523 if(rel=="openid.server") 539 if(rel=="openid.server")
524 html_openid1.uris.add(-1,xrd::uri_t(href)); 540 html_openid1.uris.add(-1,xrd::uri_t(href));
525 else if(rel=="openid.delegate") 541 else if(rel=="openid.delegate")
526 html_openid1.local_ids.add(-1,href); 542 html_openid1.local_ids.add(-1,href);
527 else if(rel=="openid2.provider") 543 else if(rel=="openid2.provider")
528 html_openid2.uris.add(-1,xrd::uri_t(href)); 544 html_openid2.uris.add(-1,xrd::uri_t(href));
529 else if(rel=="openid2.local_id") 545 else if(rel=="openid2.local_id")
530 html_openid2.local_ids.add(-1,href); 546 html_openid2.local_ids.add(-1,href);
531 } 547 }
532 }else if(is_element(n,"body")) { 548 }else if(is_element(n,"body")) {
533 skipping = -1; 549 skipping = -1;
534 } 550 }
535 } 551 }
536 552
537 void queue_endpoints(endpoint_discovery_iterator& oi, 553 void queue_endpoints(endpoint_discovery_iterator& oi,
538 const idiscovery_t &id, 554 const idiscovery_t &id,
539 const service_type_t *st) { 555 const service_type_t *st) {
540 openid_endpoint_t ep; 556 openid_endpoint_t ep;
541 ep.claimed_id = id.canonicalized_id; 557 ep.claimed_id = id.canonicalized_id;
542 for(xrd::services_t::const_iterator isvc=id.xrd.services.begin(); 558 for(xrd::services_t::const_iterator isvc=id.xrd.services.begin();
543 isvc!=id.xrd.services.end(); ++isvc) { 559 isvc!=id.xrd.services.end(); ++isvc) {
544 const xrd::service_t svc = isvc->second; 560 const xrd::service_t svc = isvc->second;
545 if(svc.types.find(st->uri)==svc.types.end()) continue; 561 if(svc.types.find(st->uri)==svc.types.end()) continue;
546 for(xrd::uris_t::const_iterator iu=svc.uris.begin();iu!=svc.uris.end();++iu) { 562 for(xrd::uris_t::const_iterator iu=svc.uris.begin();iu!=svc.uris.end();++iu) {
547 ep.uri = iu->second.uri; 563 ep.uri = iu->second.uri;
548 if(id.xri_identity) { 564 if(id.xri_identity) {
549 if(iu->second.append=="qxri") { 565 if(iu->second.append=="qxri") {
550 ep.uri += id.normalized_id; 566 ep.uri += id.normalized_id;
551 } /* TODO: else handle other append attribute values */ 567 } /* TODO: else handle other append attribute values */
552 } 568 }
553 if(st->forceid) { 569 if(st->forceid) {
554 ep.local_id = ep.claimed_id = st->forceid; 570 ep.local_id = ep.claimed_id = st->forceid;
555 *(oi++) = ep; 571 *(oi++) = ep;
556 }else{ 572 }else{
557 if(svc.local_ids.empty()) { 573 if(svc.local_ids.empty()) {
558 ep.local_id = ep.claimed_id; 574 ep.local_id = ep.claimed_id;
559 *(oi++) = ep; 575 *(oi++) = ep;
560 }else{ 576 }else{
561 for(xrd::local_ids_t::const_iterator ilid=svc.local_ids.begin(); 577 for(xrd::local_ids_t::const_iterator ilid=svc.local_ids.begin();
562 ilid!=svc.local_ids.end(); ++ilid) { 578 ilid!=svc.local_ids.end(); ++ilid) {
563 ep.local_id = ilid->second; 579 ep.local_id = ilid->second;
564 *(oi++) = ep; 580 *(oi++) = ep;
565 } 581 }
566 } 582 }
567 } 583 }
568 } 584 }
569 } 585 }
570 } 586 }
571 587
588 int unknown_encoding(const XML_Char* /* n */,XML_Encoding *i) {
589 for(unsigned int ii=0;ii < sizeof(i->map)/sizeof(i->map[0]);++ii)
590 i->map[ii] = ii;
591 i->convert = 0; i->release = 0;
592 return XML_STATUS_OK;
593 }
594
572 }; 595 };
573 596
574 string idiscover(endpoint_discovery_iterator oi,const string& identity) { 597 string idiscover(endpoint_discovery_iterator oi,const string& identity) {
575 idigger_t idigger; 598 idigger_t idigger;
576 return idigger.discover(oi,identity); 599 return idigger.discover(oi,identity);
577 } 600 }
578 601
579 void yadiscover(endpoint_discovery_iterator oi,const string& yurl,const char **types,bool redirs) try { 602 void yadiscover(endpoint_discovery_iterator oi,const string& yurl,const char **types,bool redirs) try {
580 idigger_t idigger; 603 idigger_t idigger;
581 idigger.yadiscover(oi,yurl,types,redirs); 604 idigger.yadiscover(oi,yurl,types,redirs);
582 }catch(exception_curl& ec) { 605 }catch(exception_curl& ec) {
583 if(redirs || ec._error!=CURLE_TOO_MANY_REDIRECTS) 606 if(redirs || ec._error!=CURLE_TOO_MANY_REDIRECTS)
584 throw; 607 throw;
585 } 608 }
586 609
587} 610}
diff --git a/lib/expat.cc b/lib/expat.cc
index c4dab7e..fb58a9a 100644
--- a/lib/expat.cc
+++ b/lib/expat.cc
@@ -1,97 +1,106 @@
1#include <opkele/expat.h> 1#include <opkele/expat.h>
2 2
3namespace opkele { 3namespace opkele {
4 4
5 namespace util { 5 namespace util {
6 6
7 expat_t::~expat_t() throw() { 7 expat_t::~expat_t() throw() {
8 if(_x) 8 if(_x)
9 XML_ParserFree(_x); 9 XML_ParserFree(_x);
10 } 10 }
11 11
12 expat_t& expat_t::operator=(XML_Parser x) { 12 expat_t& expat_t::operator=(XML_Parser x) {
13 if(_x) 13 if(_x)
14 XML_ParserFree(_x); 14 XML_ParserFree(_x);
15 _x = x; 15 _x = x;
16 return *this; 16 return *this;
17 } 17 }
18 18
19 static void _start_element(void* ud,const XML_Char *n,const XML_Char **a) { 19 static void _start_element(void* ud,const XML_Char *n,const XML_Char **a) {
20 ((expat_t*)ud)->start_element(n,a); 20 ((expat_t*)ud)->start_element(n,a);
21 } 21 }
22 static void _end_element(void *ud,const XML_Char *n) { 22 static void _end_element(void *ud,const XML_Char *n) {
23 ((expat_t*)ud)->end_element(n); 23 ((expat_t*)ud)->end_element(n);
24 } 24 }
25 25
26 void expat_t::set_element_handler() { 26 void expat_t::set_element_handler() {
27 assert(_x); 27 assert(_x);
28 XML_SetElementHandler(_x,_start_element,_end_element); 28 XML_SetElementHandler(_x,_start_element,_end_element);
29 } 29 }
30 30
31 static void _character_data(void *ud,const XML_Char *s,int l) { 31 static void _character_data(void *ud,const XML_Char *s,int l) {
32 ((expat_t*)ud)->character_data(s,l); 32 ((expat_t*)ud)->character_data(s,l);
33 } 33 }
34 34
35 void expat_t::set_character_data_handler() { 35 void expat_t::set_character_data_handler() {
36 assert(_x); 36 assert(_x);
37 XML_SetCharacterDataHandler(_x,_character_data); 37 XML_SetCharacterDataHandler(_x,_character_data);
38 } 38 }
39 39
40 static void _processing_instruction(void *ud,const XML_Char *t,const XML_Char *d) { 40 static void _processing_instruction(void *ud,const XML_Char *t,const XML_Char *d) {
41 ((expat_t*)ud)->processing_instruction(t,d); 41 ((expat_t*)ud)->processing_instruction(t,d);
42 } 42 }
43 43
44 void expat_t::set_processing_instruction_handler() { 44 void expat_t::set_processing_instruction_handler() {
45 assert(_x); 45 assert(_x);
46 XML_SetProcessingInstructionHandler(_x,_processing_instruction); 46 XML_SetProcessingInstructionHandler(_x,_processing_instruction);
47 } 47 }
48 48
49 static void _comment(void *ud,const XML_Char *d) { 49 static void _comment(void *ud,const XML_Char *d) {
50 ((expat_t*)ud)->comment(d); 50 ((expat_t*)ud)->comment(d);
51 } 51 }
52 52
53 void expat_t::set_comment_handler() { 53 void expat_t::set_comment_handler() {
54 assert(_x); 54 assert(_x);
55 XML_SetCommentHandler(_x,_comment); 55 XML_SetCommentHandler(_x,_comment);
56 } 56 }
57 57
58 static void _start_cdata_section(void *ud) { 58 static void _start_cdata_section(void *ud) {
59 ((expat_t*)ud)->start_cdata_section(); 59 ((expat_t*)ud)->start_cdata_section();
60 } 60 }
61 static void _end_cdata_section(void *ud) { 61 static void _end_cdata_section(void *ud) {
62 ((expat_t*)ud)->end_cdata_section(); 62 ((expat_t*)ud)->end_cdata_section();
63 } 63 }
64 64
65 void expat_t::set_cdata_section_handler() { 65 void expat_t::set_cdata_section_handler() {
66 assert(_x); 66 assert(_x);
67 XML_SetCdataSectionHandler(_x,_start_cdata_section,_end_cdata_section); 67 XML_SetCdataSectionHandler(_x,_start_cdata_section,_end_cdata_section);
68 } 68 }
69 69
70 static void _default_handler(void *ud,const XML_Char *s,int l) { 70 static void _default_handler(void *ud,const XML_Char *s,int l) {
71 ((expat_t*)ud)->default_handler(s,l); 71 ((expat_t*)ud)->default_handler(s,l);
72 } 72 }
73 73
74 void expat_t::set_default_handler() { 74 void expat_t::set_default_handler() {
75 assert(_x); 75 assert(_x);
76 XML_SetDefaultHandler(_x,_default_handler); 76 XML_SetDefaultHandler(_x,_default_handler);
77 } 77 }
78 void expat_t::set_default_handler_expand() { 78 void expat_t::set_default_handler_expand() {
79 assert(_x); 79 assert(_x);
80 XML_SetDefaultHandlerExpand(_x,_default_handler); 80 XML_SetDefaultHandlerExpand(_x,_default_handler);
81 } 81 }
82 82
83 static void _start_namespace_decl(void *ud,const XML_Char *p,const XML_Char *u) { 83 static void _start_namespace_decl(void *ud,const XML_Char *p,const XML_Char *u) {
84 ((expat_t*)ud)->start_namespace_decl(p,u); 84 ((expat_t*)ud)->start_namespace_decl(p,u);
85 } 85 }
86 static void _end_namespace_decl(void *ud,const XML_Char *p) { 86 static void _end_namespace_decl(void *ud,const XML_Char *p) {
87 ((expat_t*)ud)->end_namespace_decl(p); 87 ((expat_t*)ud)->end_namespace_decl(p);
88 } 88 }
89 89
90 void expat_t::set_namespace_decl_handler() { 90 void expat_t::set_namespace_decl_handler() {
91 assert(_x); 91 assert(_x);
92 XML_SetNamespaceDeclHandler(_x,_start_namespace_decl,_end_namespace_decl); 92 XML_SetNamespaceDeclHandler(_x,_start_namespace_decl,_end_namespace_decl);
93 } 93 }
94 94
95 static int _unknown_encoding(void *ehd,const XML_Char *n,XML_Encoding *i) {
96 return ((expat_t*)ehd)->unknown_encoding(n,i);
97 }
98
99 void expat_t::set_unknown_encoding_handler() {
100 assert(_x);
101 XML_SetUnknownEncodingHandler(_x,_unknown_encoding,this);
102 }
103
95 } 104 }
96 105
97} 106}
diff --git a/test/RP.cc b/test/RP.cc
index 35ee71d..f015723 100644
--- a/test/RP.cc
+++ b/test/RP.cc
@@ -1,195 +1,196 @@
1#include <uuid/uuid.h> 1#include <uuid/uuid.h>
2#include <iostream> 2#include <iostream>
3#include <cassert> 3#include <cassert>
4#include <cstdlib>
4#include <stdexcept> 5#include <stdexcept>
5#include <string> 6#include <string>
6#include <set> 7#include <set>
7#include <iterator> 8#include <iterator>
8using namespace std; 9using namespace std;
9#include <kingate/exception.h> 10#include <kingate/exception.h>
10#include <kingate/plaincgi.h> 11#include <kingate/plaincgi.h>
11#include <kingate/cgi_gateway.h> 12#include <kingate/cgi_gateway.h>
12#include <opkele/exception.h> 13#include <opkele/exception.h>
13#include <opkele/types.h> 14#include <opkele/types.h>
14#include <opkele/util.h> 15#include <opkele/util.h>
15#include <opkele/uris.h> 16#include <opkele/uris.h>
16#include <opkele/discovery.h> 17#include <opkele/discovery.h>
17#include <opkele/association.h> 18#include <opkele/association.h>
18#include <opkele/sreg.h> 19#include <opkele/sreg.h>
19using namespace opkele; 20using namespace opkele;
20#include <opkele/prequeue_rp.h> 21#include <opkele/prequeue_rp.h>
21#include <opkele/debug.h> 22#include <opkele/debug.h>
22 23
23#include "sqlite.h" 24#include "sqlite.h"
24#include "kingate_openid_message.h" 25#include "kingate_openid_message.h"
25 26
26#undef DUMB_RP 27#undef DUMB_RP
27 28
28#ifdef DUMB_RP 29#ifdef DUMB_RP
29# define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb") 30# define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb")
30#else 31#else
31# define DUMBTHROW (void)0 32# define DUMBTHROW (void)0
32#endif 33#endif
33 34
34class rpdb_t : public sqlite3_t { 35class rpdb_t : public sqlite3_t {
35 public: 36 public:
36 rpdb_t() 37 rpdb_t()
37 : sqlite3_t("/tmp/RP.db") { 38 : sqlite3_t("/tmp/RP.db") {
38 assert(_D); 39 assert(_D);
39 char **resp; int nrow,ncol; char *errm; 40 char **resp; int nrow,ncol; char *errm;
40 if(sqlite3_get_table( 41 if(sqlite3_get_table(
41 _D,"SELECT a_op FROM assoc LIMIT 0", 42 _D,"SELECT a_op FROM assoc LIMIT 0",
42 &resp,&nrow,&ncol,&errm)!=SQLITE_OK) { 43 &resp,&nrow,&ncol,&errm)!=SQLITE_OK) {
43 extern const char *__RP_db_bootstrap; 44 extern const char *__RP_db_bootstrap;
44 DOUT_("Bootstrapping DB"); 45 DOUT_("Bootstrapping DB");
45 if(sqlite3_exec(_D,__RP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK) 46 if(sqlite3_exec(_D,__RP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK)
46 throw opkele::exception(OPKELE_CP_ string("Failed to bootstrap SQLite database: ")+errm); 47 throw opkele::exception(OPKELE_CP_ string("Failed to bootstrap SQLite database: ")+errm);
47 }else 48 }else
48 sqlite3_free_table(resp); 49 sqlite3_free_table(resp);
49 50
50 } 51 }
51}; 52};
52 53
53class example_rp_t : public opkele::prequeue_RP { 54class example_rp_t : public opkele::prequeue_RP {
54 public: 55 public:
55 mutable rpdb_t db; 56 mutable rpdb_t db;
56 kingate::cookie htc; 57 kingate::cookie htc;
57 long as_id; 58 long as_id;
58 int ordinal; 59 int ordinal;
59 kingate::cgi_gateway& gw; 60 kingate::cgi_gateway& gw;
60 61
61 example_rp_t(kingate::cgi_gateway& g) 62 example_rp_t(kingate::cgi_gateway& g)
62 : as_id(-1), ordinal(0), gw(g), have_eqtop(false) { 63 : as_id(-1), ordinal(0), gw(g), have_eqtop(false) {
63 try { 64 try {
64 htc = gw.cookies.get_cookie("ht_session"); 65 htc = gw.cookies.get_cookie("ht_session");
65 as_id = opkele::util::string_to_long(gw.get_param("asid")); 66 as_id = opkele::util::string_to_long(gw.get_param("asid"));
66 }catch(kingate::exception_notfound& kenf) { 67 }catch(kingate::exception_notfound& kenf) {
67 uuid_t uuid; uuid_generate(uuid); 68 uuid_t uuid; uuid_generate(uuid);
68 htc = kingate::cookie("ht_session",util::encode_base64(uuid,sizeof(uuid))); 69 htc = kingate::cookie("ht_session",util::encode_base64(uuid,sizeof(uuid)));
69 sqlite3_mem_t<char*> S = sqlite3_mprintf( 70 sqlite3_mem_t<char*> S = sqlite3_mprintf(
70 "INSERT INTO ht_sessions (hts_id) VALUES (%Q)", 71 "INSERT INTO ht_sessions (hts_id) VALUES (%Q)",
71 htc.get_value().c_str()); 72 htc.get_value().c_str());
72 db.exec(S); 73 db.exec(S);
73 } 74 }
74 } 75 }
75 76
76 /* Global persistent store */ 77 /* Global persistent store */
77 78
78 opkele::assoc_t store_assoc( 79 opkele::assoc_t store_assoc(
79 const string& OP,const string& handle, 80 const string& OP,const string& handle,
80 const string& type,const secret_t& secret, 81 const string& type,const secret_t& secret,
81 int expires_in) { 82 int expires_in) {
82 DUMBTHROW; 83 DUMBTHROW;
83 DOUT_("Storing '" << handle << "' assoc with '" << OP << "'"); 84 DOUT_("Storing '" << handle << "' assoc with '" << OP << "'");
84 time_t exp = time(0)+expires_in; 85 time_t exp = time(0)+expires_in;
85 sqlite3_mem_t<char*> 86 sqlite3_mem_t<char*>
86 S = sqlite3_mprintf( 87 S = sqlite3_mprintf(
87 "INSERT INTO assoc" 88 "INSERT INTO assoc"
88 " (a_op,a_handle,a_type,a_ctime,a_etime,a_secret)" 89 " (a_op,a_handle,a_type,a_ctime,a_etime,a_secret)"
89 " VALUES (" 90 " VALUES ("
90 " %Q,%Q,%Q," 91 " %Q,%Q,%Q,"
91 " datetime('now'), datetime('now','+%d seconds')," 92 " datetime('now'), datetime('now','+%d seconds'),"
92 " %Q" 93 " %Q"
93 " );", OP.c_str(), handle.c_str(), type.c_str(), 94 " );", OP.c_str(), handle.c_str(), type.c_str(),
94 expires_in, 95 expires_in,
95 util::encode_base64(&(secret.front()),secret.size()).c_str() ); 96 util::encode_base64(&(secret.front()),secret.size()).c_str() );
96 db.exec(S); 97 db.exec(S);
97 return opkele::assoc_t(new opkele::association( 98 return opkele::assoc_t(new opkele::association(
98 OP, handle, type, secret, exp, false )); 99 OP, handle, type, secret, exp, false ));
99 } 100 }
100 101
101 opkele::assoc_t find_assoc( 102 opkele::assoc_t find_assoc(
102 const string& OP) { 103 const string& OP) {
103 DUMBTHROW; 104 DUMBTHROW;
104 DOUT_("Looking for an assoc with '" << OP << '\''); 105 DOUT_("Looking for an assoc with '" << OP << '\'');
105 sqlite3_mem_t<char*> 106 sqlite3_mem_t<char*>
106 S = sqlite3_mprintf( 107 S = sqlite3_mprintf(
107 "SELECT" 108 "SELECT"
108 " a_op,a_handle,a_type,a_secret," 109 " a_op,a_handle,a_type,a_secret,"
109 " strftime('%%s',a_etime) AS a_etime" 110 " strftime('%%s',a_etime) AS a_etime"
110 " FROM assoc" 111 " FROM assoc"
111 " WHERE a_op=%Q AND a_itime IS NULL AND NOT a_stateless" 112 " WHERE a_op=%Q AND a_itime IS NULL AND NOT a_stateless"
112 " AND ( a_etime > datetime('now','-30 seconds') )" 113 " AND ( a_etime > datetime('now','-30 seconds') )"
113 " LIMIT 1", 114 " LIMIT 1",
114 OP.c_str()); 115 OP.c_str());
115 sqlite3_table_t T; 116 sqlite3_table_t T;
116 int nr,nc; 117 int nr,nc;
117 db.get_table(S,T,&nr,&nc); 118 db.get_table(S,T,&nr,&nc);
118 if(nr<1) 119 if(nr<1)
119 throw opkele::failed_lookup(OPKELE_CP_ "Couldn't find unexpired handle"); 120 throw opkele::failed_lookup(OPKELE_CP_ "Couldn't find unexpired handle");
120 assert(nr==1); 121 assert(nr==1);
121 assert(nc==5); 122 assert(nc==5);
122 secret_t secret; 123 secret_t secret;
123 util::decode_base64(T.get(1,3,nc),secret); 124 util::decode_base64(T.get(1,3,nc),secret);
124 DOUT_(" found '" << T.get(1,1,nc) << '\''); 125 DOUT_(" found '" << T.get(1,1,nc) << '\'');
125 return opkele::assoc_t(new opkele::association( 126 return opkele::assoc_t(new opkele::association(
126 T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), 127 T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc),
127 secret, strtol(T.get(1,4,nc),0,0), false )); 128 secret, strtol(T.get(1,4,nc),0,0), false ));
128 } 129 }
129 130
130 opkele::assoc_t retrieve_assoc( 131 opkele::assoc_t retrieve_assoc(
131 const string& OP,const string& handle) { 132 const string& OP,const string& handle) {
132 DUMBTHROW; 133 DUMBTHROW;
133 DOUT_("Retrieving assoc '" << handle << "' with '" << OP << '\''); 134 DOUT_("Retrieving assoc '" << handle << "' with '" << OP << '\'');
134 sqlite3_mem_t<char*> 135 sqlite3_mem_t<char*>
135 S = sqlite3_mprintf( 136 S = sqlite3_mprintf(
136 "SELECT" 137 "SELECT"
137 " a_op,a_handle,a_type,a_secret," 138 " a_op,a_handle,a_type,a_secret,"
138 " strftime('%%s',a_etime) AS a_etime" 139 " strftime('%%s',a_etime) AS a_etime"
139 " FROM assoc" 140 " FROM assoc"
140 " WHERE a_op=%Q AND a_handle=%Q" 141 " WHERE a_op=%Q AND a_handle=%Q"
141 " AND a_itime IS NULL AND NOT a_stateless" 142 " AND a_itime IS NULL AND NOT a_stateless"
142 " LIMIT 1", 143 " LIMIT 1",
143 OP.c_str(),handle.c_str()); 144 OP.c_str(),handle.c_str());
144 sqlite3_table_t T; 145 sqlite3_table_t T;
145 int nr,nc; 146 int nr,nc;
146 db.get_table(S,T,&nr,&nc); 147 db.get_table(S,T,&nr,&nc);
147 if(nr<1) 148 if(nr<1)
148 throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid association"); 149 throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid association");
149 assert(nr==1); assert(nc==5); 150 assert(nr==1); assert(nc==5);
150 secret_t secret; util::decode_base64(T.get(1,3,nc),secret); 151 secret_t secret; util::decode_base64(T.get(1,3,nc),secret);
151 DOUT_(" found. type=" << T.get(1,2,nc) << '\''); 152 DOUT_(" found. type=" << T.get(1,2,nc) << '\'');
152 return opkele::assoc_t(new opkele::association( 153 return opkele::assoc_t(new opkele::association(
153 T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), 154 T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc),
154 secret, strtol(T.get(1,4,nc),0,0), false )); 155 secret, strtol(T.get(1,4,nc),0,0), false ));
155 } 156 }
156 157
157 void invalidate_assoc( 158 void invalidate_assoc(
158 const string& OP,const string& handle) { 159 const string& OP,const string& handle) {
159 DUMBTHROW; 160 DUMBTHROW;
160 DOUT_("Invalidating assoc '" << handle << "' with '" << OP << '\''); 161 DOUT_("Invalidating assoc '" << handle << "' with '" << OP << '\'');
161 sqlite3_mem_t<char*> 162 sqlite3_mem_t<char*>
162 S = sqlite3_mprintf( 163 S = sqlite3_mprintf(
163 "UPDATE assoc SET a_itime=datetime('now')" 164 "UPDATE assoc SET a_itime=datetime('now')"
164 " WHERE a_op=%Q AND a_handle=%Q", 165 " WHERE a_op=%Q AND a_handle=%Q",
165 OP.c_str(), handle.c_str() ); 166 OP.c_str(), handle.c_str() );
166 db.exec(S); 167 db.exec(S);
167 } 168 }
168 169
169 void check_nonce(const string& OP,const string& nonce) { 170 void check_nonce(const string& OP,const string& nonce) {
170 DOUT_("Checking nonce '" << nonce << "' from '" << OP << '\''); 171 DOUT_("Checking nonce '" << nonce << "' from '" << OP << '\'');
171 sqlite3_mem_t<char*> 172 sqlite3_mem_t<char*>
172 S = sqlite3_mprintf( 173 S = sqlite3_mprintf(
173 "SELECT 1 FROM nonces WHERE n_op=%Q AND n_once=%Q", 174 "SELECT 1 FROM nonces WHERE n_op=%Q AND n_once=%Q",
174 OP.c_str(), nonce.c_str()); 175 OP.c_str(), nonce.c_str());
175 sqlite3_table_t T; 176 sqlite3_table_t T;
176 int nr,nc; 177 int nr,nc;
177 db.get_table(S,T,&nr,&nc); 178 db.get_table(S,T,&nr,&nc);
178 if(nr) 179 if(nr)
179 throw opkele::id_res_bad_nonce(OPKELE_CP_ "already seen that nonce"); 180 throw opkele::id_res_bad_nonce(OPKELE_CP_ "already seen that nonce");
180 sqlite3_mem_t<char*> 181 sqlite3_mem_t<char*>
181 SS = sqlite3_mprintf( 182 SS = sqlite3_mprintf(
182 "INSERT INTO nonces (n_op,n_once) VALUES (%Q,%Q)", 183 "INSERT INTO nonces (n_op,n_once) VALUES (%Q,%Q)",
183 OP.c_str(), nonce.c_str()); 184 OP.c_str(), nonce.c_str());
184 db.exec(SS); 185 db.exec(SS);
185 } 186 }
186 187
187 /* Session perisistent store */ 188 /* Session perisistent store */
188 189
189 void begin_queueing() { 190 void begin_queueing() {
190 assert(as_id>=0); 191 assert(as_id>=0);
191 DOUT_("Resetting queue for session '" << htc.get_value() << "'/" << as_id); 192 DOUT_("Resetting queue for session '" << htc.get_value() << "'/" << as_id);
192 sqlite3_mem_t<char*> S = sqlite3_mprintf( 193 sqlite3_mem_t<char*> S = sqlite3_mprintf(
193 "DELETE FROM endpoints_queue" 194 "DELETE FROM endpoints_queue"
194 " WHERE as_id=%ld", 195 " WHERE as_id=%ld",
195 as_id); 196 as_id);