summaryrefslogtreecommitdiffabout
authorMichael Krelin <hacker@klever.net>2005-07-19 13:08:32 (UTC)
committer Michael Krelin <hacker@klever.net>2005-07-19 13:08:32 (UTC)
commit4c82851dd5d5644a89d4f269079bf901f763ee33 (patch) (side-by-side diff)
treeb64c8b3c9a1be88e2a9c3f762272e0b4509ba7d9
parent907343b0c973eb295bec8795902a6d49744e9174 (diff)
downloadlibopkele-4c82851dd5d5644a89d4f269079bf901f763ee33.zip
libopkele-4c82851dd5d5644a89d4f269079bf901f763ee33.tar.gz
libopkele-4c82851dd5d5644a89d4f269079bf901f763ee33.tar.bz2
initial commit of libopkele - OpenID support library
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--.gitignore21
-rw-r--r--AUTHORS3
-rw-r--r--COPYING19
-rw-r--r--ChangeLog0
-rw-r--r--Doxyfile.in247
-rw-r--r--Makefile.am23
-rw-r--r--NEWS.xml6
-rw-r--r--NEWS.xsl24
-rw-r--r--README0
-rw-r--r--acinclude.d/libcurl.m4209
-rw-r--r--acinclude.m4213
-rwxr-xr-xautogen.sh9
-rw-r--r--configure.ac87
-rw-r--r--include/.gitignore2
-rw-r--r--include/Makefile.am11
-rw-r--r--include/opkele/.gitignore2
-rw-r--r--include/opkele/acconfig.h.in3
-rw-r--r--include/opkele/association.h89
-rw-r--r--include/opkele/consumer.h135
-rw-r--r--include/opkele/data.h12
-rw-r--r--include/opkele/exception.h206
-rw-r--r--include/opkele/opkele-config.h6
-rw-r--r--include/opkele/server.h95
-rw-r--r--include/opkele/types.h168
-rw-r--r--include/opkele/util.h60
-rw-r--r--lib/.gitignore7
-rw-r--r--lib/Makefile.am24
-rw-r--r--lib/consumer.cc316
-rw-r--r--lib/data.cc11
-rw-r--r--lib/exception.cc22
-rw-r--r--lib/params.cc96
-rw-r--r--lib/secret.cc61
-rw-r--r--lib/server.cc169
-rw-r--r--lib/util.cc138
-rw-r--r--libopkele.pc.in11
35 files changed, 2505 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..87771db
--- a/dev/null
+++ b/.gitignore
@@ -0,0 +1,21 @@
+configure
+Makefile.in
+Doxyfile
+config.log
+depcomp
+config.guess
+config.h
+config.sub
+ltmain.sh
+INSTALL
+NEWS
+Makefile
+config.status
+stamp-h1
+config.h.in
+libtool
+autom4te.cache
+libopkele.pc
+missing
+aclocal.m4
+install-sh
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..a9fb0c7
--- a/dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Klever dissected:
+ Michael 'hacker' Krelin <hacker@klever.net>
+ Leonid Ivanov <kamel@klever.net>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..7c61600
--- a/dev/null
+++ b/COPYING
@@ -0,0 +1,19 @@
+Copyright (c) 2005 Klever Group (http://www.klever.net/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/ChangeLog
diff --git a/Doxyfile.in b/Doxyfile.in
new file mode 100644
index 0000000..fac9a29
--- a/dev/null
+++ b/Doxyfile.in
@@ -0,0 +1,247 @@
+# Doxyfile 1.3.9.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = @PACKAGE@
+PROJECT_NUMBER = @VERSION@
+OUTPUT_DIRECTORY = @builddir@/doxydox
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = include
+STRIP_FROM_INC_PATH = include
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = NO
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = YES
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = NO
+SHOW_DIRECTORIES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+INPUT = \
+ @srcdir@/include/opkele/
+FILE_PATTERNS = *.h
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 2
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+GENERATE_XML = YES
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = @HAVE_DOT@
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH = @DOT@
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 0
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+SEARCHENGINE = NO
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..c577ef8
--- a/dev/null
+++ b/Makefile.am
@@ -0,0 +1,23 @@
+
+SUBDIRS=include lib
+EXTRA_DIST= NEWS NEWS.xml NEWS.xsl
+
+DISTCHECK_CONFIGURE_FLAGS=--with-pkgconfigdir=$${dc_install_base}/lib/pkgconfig
+if HAVE_PKGCONFIG
+pkgconfigdir=@PKGCONFIG_DIR@
+pkgconfig_DATA=libopkele.pc
+endif
+
+all-local: NEWS
+if HAVE_DOXYGEN
+clean-local:
+ rm -rf doxydox
+endif
+
+NEWS: NEWS.xsl NEWS.xml
+ ${XSLTPROC} -o $@ NEWS.xsl NEWS.xml
+
+if HAVE_DOXYGEN
+dox: Doxyfile
+ ${DOXYGEN}
+endif
diff --git a/NEWS.xml b/NEWS.xml
new file mode 100644
index 0000000..f8f3331
--- a/dev/null
+++ b/NEWS.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="us-ascii"?>
+<news>
+ <version version="0.0" date="July 16th, 2005">
+ <ni>Initial release</ni>
+ </version>
+</news>
diff --git a/NEWS.xsl b/NEWS.xsl
new file mode 100644
index 0000000..7c71307
--- a/dev/null
+++ b/NEWS.xsl
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="us-ascii"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ >
+ <xsl:output
+ method="text"
+ encoding="us-ascii"
+ media-type="text/plain" />
+
+ <xsl:template match="news">
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="version">
+ <xsl:value-of select="concat(@version,' (',@date,')&#xA;')"/>
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="ni">
+ <xsl:text> - </xsl:text>
+ <xsl:apply-templates mode="text"/>
+ <xsl:text>&#xA;</xsl:text>
+ </xsl:template>
+ <xsl:template match="*|text()"/>
+
+</xsl:stylesheet>
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/README
diff --git a/acinclude.d/libcurl.m4 b/acinclude.d/libcurl.m4
new file mode 100644
index 0000000..e80c206
--- a/dev/null
+++ b/acinclude.d/libcurl.m4
@@ -0,0 +1,209 @@
+# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION],
+# [ACTION-IF-YES], [ACTION-IF-NO])
+# ----------------------------------------------------------
+# David Shaw <dshaw@jabberwocky.com> Jan-23-2005
+#
+# Checks for libcurl. DEFAULT-ACTION is the string yes or no to
+# specify whether to default to --with-libcurl or --without-libcurl.
+# If not supplied, DEFAULT-ACTION is yes. MINIMUM-VERSION is the
+# minimum version of libcurl to accept. Pass the version as a regular
+# version number like 7.10.1. If not supplied, any version is
+# accepted. ACTION-IF-YES is a list of shell commands to run if
+# libcurl was successfully found and passed the various tests.
+# ACTION-IF-NO is a list of shell commands that are run otherwise.
+# Note that using --without-libcurl does run ACTION-IF-NO.
+#
+# This macro defines HAVE_LIBCURL if a working libcurl setup is found,
+# and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary values.
+# Other useful defines are LIBCURL_FEATURE_xxx where xxx are the
+# various features supported by libcurl, and LIBCURL_PROTOCOL_yyy
+# where yyy are the various protocols supported by libcurl. Both xxx
+# and yyy are capitalized. See the list of AH_TEMPLATEs at the top of
+# the macro for the complete list of possible defines. Shell
+# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also
+# defined to 'yes' for those features and protocols that were found.
+# Note that xxx and yyy keep the same capitalization as in the
+# curl-config list (e.g. it's "HTTP" and not "http").
+#
+# Users may override the detected values by doing something like:
+# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure
+#
+# For the sake of sanity, this macro assumes that any libcurl that is
+# found is after version 7.7.2, the first version that included the
+# curl-config script. Note that it is very important for people
+# packaging binary versions of libcurl to include this script!
+# Without curl-config, we can only make educated guesses as to what
+# protocols are available. Specifically, we assume that all of HTTP,
+# FTP, GOPHER, FILE, TELNET, LDAP, and DICT exist, and (if SSL exists)
+# HTTPS is present. All of these protocols existed when libcurl was
+# first created in version 7, so this is a safe assumption. If the
+# version is 7.11.0 or later, FTPS is assumed to be present as well.
+# FTPS existed before then, but was not yet fully standards compliant.
+
+AC_DEFUN([LIBCURL_CHECK_CONFIG],
+[
+ AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL])
+ AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4])
+ AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6])
+ AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz])
+ AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS])
+
+ AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_GOPHER],[Defined if libcurl supports GOPHER])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
+ AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
+
+ AC_ARG_WITH(libcurl,
+ AC_HELP_STRING([--with-libcurl=DIR],[look for the curl library in DIR]),
+ [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])])
+
+ if test "$_libcurl_with" != "no" ; then
+
+ AC_PROG_AWK
+
+ _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'"
+
+ _libcurl_try_link=yes
+
+ if test -d "$_libcurl_with" ; then
+ CPPFLAGS="${CPPFLAGS} -I$withval/include"
+ LDFLAGS="${LDFLAGS} -L$withval/lib"
+ fi
+
+ AC_PATH_PROG([_libcurl_config],[curl-config])
+
+ if test x$_libcurl_config != "x" ; then
+ AC_CACHE_CHECK([for the version of libcurl],
+ [libcurl_cv_lib_curl_version],
+ [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`])
+
+ _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse`
+ _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse`
+
+ if test $_libcurl_wanted -gt 0 ; then
+ AC_CACHE_CHECK([for libcurl >= version $2],
+ [libcurl_cv_lib_version_ok],
+ [
+ if test $_libcurl_version -ge $_libcurl_wanted ; then
+ libcurl_cv_lib_version_ok=yes
+ else
+ libcurl_cv_lib_version_ok=no
+ fi
+ ])
+ fi
+
+ if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then
+ if test x"$LIBCURL_CPPFLAGS" = "x" ; then
+ LIBCURL_CPPFLAGS=`$_libcurl_config --cflags`
+ fi
+ if test x"$LIBCURL" = "x" ; then
+ LIBCURL=`$_libcurl_config --libs`
+ fi
+
+ # All curl-config scripts support --feature
+ _libcurl_features=`$_libcurl_config --feature`
+
+ # Is it modern enough to have --protocols? (7.12.4)
+ if test $_libcurl_version -ge 461828 ; then
+ _libcurl_protocols=`$_libcurl_config --protocols`
+ fi
+ else
+ _libcurl_try_link=no
+ fi
+
+ unset _libcurl_wanted
+ fi
+
+ if test $_libcurl_try_link = yes ; then
+
+ # we didn't find curl-config, so let's see if the user-supplied
+ # link line (or failing that, "-lcurl") is enough.
+ LIBCURL=${LIBCURL-"-lcurl"}
+
+ AC_CACHE_CHECK([whether libcurl is usable],
+ [libcurl_cv_lib_curl_usable],
+ [
+ _libcurl_save_cppflags=$CPPFLAGS
+ CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS"
+ _libcurl_save_ldflags=$LDFLAGS
+ LDFLAGS="$LDFLAGS $LIBCURL"
+
+ AC_LINK_IFELSE(AC_LANG_PROGRAM([#include <curl/curl.h>],[
+/* Try and use a few common options to force a failure if we are
+ missing symbols or can't link. */
+int x;
+curl_easy_setopt(NULL,CURLOPT_URL,NULL);
+x=CURL_ERROR_SIZE;
+x=CURLOPT_WRITEFUNCTION;
+x=CURLOPT_FILE;
+x=CURLOPT_ERRORBUFFER;
+x=CURLOPT_STDERR;
+x=CURLOPT_VERBOSE;
+]),libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no)
+
+ CPPFLAGS=$_libcurl_save_cppflags
+ LDFLAGS=$_libcurl_save_ldflags
+ unset _libcurl_save_cppflags
+ unset _libcurl_save_ldflags
+ ])
+
+ if test $libcurl_cv_lib_curl_usable = yes ; then
+ AC_DEFINE(HAVE_LIBCURL,1,
+ [Define to 1 if you have a functional curl library.])
+ AC_SUBST(LIBCURL_CPPFLAGS)
+ AC_SUBST(LIBCURL)
+
+ for _libcurl_feature in $_libcurl_features ; do
+ AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
+ eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
+ done
+
+ if test "x$_libcurl_protocols" = "x" ; then
+
+ # We don't have --protocols, so just assume that all
+ # protocols are available
+ _libcurl_protocols="HTTP FTP GOPHER FILE TELNET LDAP DICT"
+
+ if test x$libcurl_feature_SSL = xyes ; then
+ _libcurl_protocols="$_libcurl_protocols HTTPS"
+
+ # FTPS wasn't standards-compliant until version
+ # 7.11.0
+ if test $_libcurl_version -ge 461568; then
+ _libcurl_protocols="$_libcurl_protocols FTPS"
+ fi
+ fi
+ fi
+
+ for _libcurl_protocol in $_libcurl_protocols ; do
+ AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1])
+ eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes
+ done
+ fi
+ fi
+
+ unset _libcurl_try_link
+ unset _libcurl_version_parse
+ unset _libcurl_config
+ unset _libcurl_feature
+ unset _libcurl_features
+ unset _libcurl_protocol
+ unset _libcurl_protocols
+ unset _libcurl_version
+ fi
+
+ if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then
+ # This is the IF-NO path
+ ifelse([$4],,:,[$4])
+ else
+ # This is the IF-YES path
+ ifelse([$3],,:,[$3])
+ fi
+
+ unset _libcurl_with
+])dnl
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..9c9f945
--- a/dev/null
+++ b/acinclude.m4
@@ -0,0 +1,213 @@
+dnl AC_WITH_PKGCONFIG([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: PKGCONFIG_PKGCONFIG PKGCONFIG_DIR
+dnl AM_CONDTIONAL: HAVE_PKGCONFIG
+AC_DEFUN([AC_WITH_PKGCONFIG],[
+ PKGCONFIG_PKGCONFIG=""
+ PKGCONFIG_DIR=""
+ HAVE_PKGCONFIG="no"
+ EXPLICIT_PKGCONFIGDIR="no"
+ test -z "${WANT_PKGCONFIG}" && WANT_PKGCONFIG=""
+ AC_PATH_PROG([PKGCONFIG_PKGCONFIG],[pkg-config],[false])
+ if test "${PKGCONFIG_PKGCONFIG}" != "false" ; then
+ AC_ARG_WITH([pkgconfigdir],
+ AC_HELP_STRING([--with-pkgconfigdir=dir],[Specify pkgconfig directory]),
+ [
+ if test "${withval}" = "no" ; then
+ WANT_PKGCONFIG="no"
+ else
+ PKGCONFIG_DIR="${withval}"
+ EXPLICIT_PKGCONFIGDIR="yes"
+ fi
+ ],[
+ AC_MSG_CHECKING([for pkgconfig directory])
+ PKGCONFIG_DIR="`${PKGCONFIG_PKGCONFIG} --debug 2>&1 | grep '^Scanning'| head -n 1 | cut -d\' -f2-|cut -d\' -f1`"
+ AC_MSG_RESULT([${PKGCONFIG_DIR}])
+ ]
+ )
+ if test -d "${PKGCONFIG_DIR}" ; then
+ HAVE_PKGCONFIG=yes
+ AC_SUBST([PKGCONFIG_PKGCONFIG])
+ AC_SUBST([PKGCONFIG_DIR])
+ else
+ AC_MSG_NOTICE([unexistent pkgconfig directory: ${PKGCONFIG_DIR}])
+ if test "${EXPLICIT_PKGCONFIGDIR}" = "yes" ; then
+ HAVE_PKGCONFIG=yes
+ AC_SUBST([PKGCONFIG_PKGCONFIG])
+ AC_SUBST([PKGCONFIG_DIR])
+ else
+ ifelse([$2], , :, [$2])
+ fi
+ fi
+ fi
+ AM_CONDITIONAL([HAVE_PKGCONFIG],[test "${HAVE_PKGCONFIG}" = "yes"])
+])
+
+dnl AC_WITH_DOXYGEN([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: DOXYGEN HAVE_DOXYGEN
+dnl AM_CONDTIONAL: HAVE_DOXYGEN
+AC_DEFUN([AC_WITH_DOXYGEN],[
+ HAVE_DOXYGEN="no"
+ AC_PATH_PROG([DOXYGEN],[doxygen],[false])
+ if test "${DOXYGEN}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_DOXYGEN="yes"
+ AC_SUBST([DOXYGEN])
+ $1
+ fi
+ AC_SUBST([HAVE_DOXYGEN])
+ AM_CONDITIONAL([HAVE_DOXYGEN],[test "${HAVE_DOXYGEN}" = "yes"])
+])
+
+dnl AC_WITH_DOT([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: DOT HAVE_DOT
+dnl AM_CONDITIONAL: HAVE_DOT
+AC_DEFUN([AC_WITH_DOT],[
+ HAVE_DOT="no"
+ AC_PATH_PROG([DOT],[dot],[false])
+ if test "${DOT}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_DOT="yes"
+ AC_SUBST([DOT])
+ $1
+ fi
+AC_SUBST([HAVE_DOT])
+ AM_CONDITIONAL([HAVE_DOT],[test "${HAVE_DOT}" = "yes"])
+])
+
+dnl AC_WITH_PCRE([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: PCRE_CONFIG PCRE_PREFIX PCRE_EXEC_PREFIX
+dnl PCRE_VERSION PCRE_CFLAGS PCRE_LIBS
+dnl PCRE_LIBS_POSIX PCRE_CFLAGS_POSIX
+dnl AM_CONDITIONAL: HAVE_PCRE
+dnl AC_DEFINE: HAVE_PCRE PCRE_VERSION
+AC_DEFUN([AC_WITH_PCRE],[
+ HAVE_PCRE="no"
+ PCRE_CONFIG=""
+ PCRE_PREFIX=""
+ PCRE_EXEC_PREFIX=""
+ PCRE_VERSION=""
+ PCRE_CFLAGS=""
+ PCRE_LIBS=""
+ PCRE_LOCATIONS="${PATH}:/usr/local/bin:/usr/bin"
+ test -z "$WANT_PCRE" && WANT_PCRE=""
+ AC_ARG_WITH([pcre],
+ AC_HELP_STRING([--with-pcre=location],[Look for pcre in specified locations]),
+ [
+ if test "${withval}" = "no" ; then
+ WANT_PCRE="no"
+ else
+ if test -x "${withval}" ; then
+ PCRE_CONFIG="${withval}"
+ elif test -x "${withval}/pcre-config" ; then
+ PCRE_CONFIG="${withval}/pcre-config"
+ elif test -x "${withval}/bin/pcre-config" ; then
+ PCRE_CONFIG="${withval}/bin/pcre-config"
+ fi
+ fi
+ ]
+ )
+ if test "${WANT_PCRE}" = "no" ; then
+ ifelse([$2], , :, [$2])
+ else
+ if test -z "${PCRE_CONFIG}" ; then
+ AC_PATH_PROG(PCRE_CONFIG,[pcre-config],false,[${PCRE_LOCATIONS}])
+ if test "${PCRE_CONFIG}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_PCRE="yes"
+ PCRE_PREFIX="`${PCRE_CONFIG} --prefix`"
+ PCRE_EXEC_PREFIX="`${PCRE_CONFIG} --exec-prefix`"
+ PCRE_VERSION="`${PCRE_CONFIG} --version`"
+ PCRE_CFLAGS="`${PCRE_CONFIG} --cflags`"
+ PCRE_LIBS="`${PCRE_CONFIG} --libs`"
+ PCRE_CFLAGS_POSIX="`${PCRE_CONFIG} --cflags-posix`"
+ PCRE_LIBS_POSIX="`${PCRE_CONFIG} --libs-posix`"
+ AC_SUBST([PCRE_CONFIG])
+ AC_SUBST([PCRE_PREFIX])
+ AC_SUBST([PCRE_EXEC_PREFIX])
+ AC_SUBST([PCRE_VERSION])
+ AC_SUBST([PCRE_CFLAGS])
+ AC_SUBST([PCRE_LIBS])
+ AC_SUBST([PCRE_CFLAGS_POSIX])
+ AC_SUBST([PCRE_LIBS_POSIX])
+ AC_DEFINE([HAVE_PCRE],,[pcre support])
+ AC_DEFINE_UNQUOTED([PCRE_VERSION],["${PCRE_VERSION}"],[pcre version])
+ $1
+ fi
+ fi
+ fi
+ AM_CONDITIONAL([HAVE_PCRE],[test "${HAVE_PCRE}" = "yes"])
+])
+
+dnl AC_WITH_PCREPP([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: PCREPP_CONFIG PCREPP_PREFIX PCREPP_EXEC_PREFIX
+dnl PCREPP_VERSION PCREPP_CFLAGS PCREPP_LIBS
+dnl AM_CONDITIONAL: HAVE_PCREPP
+dnl AC_DEFINE: HAVE_PCREPP PCREPP_VERSION
+AC_DEFUN([AC_WITH_PCREPP],[
+ HAVE_PCREPP="no"
+ PCREPP_CONFIG=""
+ PCREPP_PREFIX=""
+ PCREPP_EXEC_PREFIX=""
+ PCREPP_VERSION=""
+ PCREPP_CFLAGS=""
+ PCREPP_LIBS=""
+ PCREPP_LOCATIONS="${PATH}:/usr/local/bin:/usr/bin"
+ test -z "$WANT_PCREPP" && WANT_PCREPP=""
+ AC_ARG_WITH([pcre++],
+ AC_HELP_STRING([--with-pcre++=location],[Look for pcre++ in specified locations]),
+ [
+ if test "${withval}" = "no" ; then
+ WANT_PCREPP="no"
+ else
+ if test -x "${withval}" ; then
+ PCREPP_CONFIG="${withval}"
+ elif test -x "${withval}/pcre++-config" ; then
+ PCREPP_CONFIG="${withval}/pcre++-config"
+ elif test -x "${withval}/bin/pcre++-config" ; then
+ PCREPP_CONFIG="${withval}/bin/pcre++-config"
+ fi
+ fi
+ ]
+ )
+ if test "${WANT_PCREPP}" = "no" ; then
+ ifelse([$2], , :, [$2])
+ else
+ if test "${HAVE_PCRE}" != "yes" ; then
+ ifelse([$2], , :, [$2])
+ else
+ if test -z "${PCREPP_CONFIG}" ; then
+ AC_PATH_PROG([PCREPP_CONFIG],[pcre++-config],false,[${PCREPP_LOCATIONS}])
+ if test "${PCREPP_CONFIG}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_PCREPP="yes"
+ PCREPP_PREFIX="`${PCREPP_CONFIG} --prefix`"
+ PCREPP_EXEC_PREFIX="`${PCREPP_CONFIG} --exec-prefix`"
+ PCREPP_VERSION="`${PCREPP_CONFIG} --version`"
+ PCREPP_CFLAGS="`${PCREPP_CONFIG} --cflags` ${PCRE_CFLAGS}"
+ PCREPP_LIBS="`${PCREPP_CONFIG} --libs` ${PCRE_LIBS}"
+ AC_SUBST([PCREPP_CONFIG])
+ AC_SUBST([PCREPP_PREFIX])
+ AC_SUBST([PCREPP_EXEC_PREFIX])
+ AC_SUBST([PCREPP_VERSION])
+ AC_SUBST([PCREPP_CFLAGS])
+ AC_SUBST([PCREPP_LIBS])
+ AC_DEFINE([HAVE_PCREPP],,[pcre++ support])
+ AC_DEFINE_UNQUOTED([PCREPP_VERSION],["${PCREPP_VERSION}"],[pcre++ version])
+ $1
+ fi
+ fi
+ fi
+ fi
+ AM_CONDITIONAL([HAVE_PCREPP],[test "${HAVE_PCREPP}" = "yes"])
+])
+
+m4_include([acinclude.d/libcurl.m4])
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..ba27501
--- a/dev/null
+++ b/autogen.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+WANT_AUTOMAKE=1.8
+export WANT_AUTOMAKE
+libtoolize -f \
+&& aclocal \
+&& autoheader \
+&& automake -a \
+&& autoconf \
+&& ./configure "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..a31f5b1
--- a/dev/null
+++ b/configure.ac
@@ -0,0 +1,87 @@
+AC_INIT([libopkele], [0.0], [libopkele-bugs@klever.net])
+AC_CONFIG_SRCDIR([include/opkele/opkele-config.h])
+AC_CONFIG_HEADERS([config.h include/opkele/acconfig.h])
+AM_INIT_AUTOMAKE([dist-bzip2])
+
+AC_PROG_INSTALL
+AC_PROG_CXX
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+AC_HEADER_STDC
+
+AC_PATH_PROG([XSLTPROC],[xsltproc],[true])
+AC_WITH_PKGCONFIG
+
+PKG_CHECK_MODULES([OPENSSL],[openssl],[
+ AC_MSG_RESULT([yes])
+ ],[
+ AC_MSG_ERROR([no openssl library found. get one from http://www.openssl.org/])
+ ]
+)
+
+WANT_KONFORKA="yes"
+AC_ARG_ENABLE([konforka],
+ AC_HELP_STRING([--disable-konforka],[do not use konforka library (default: use if found)]),
+ [
+ test "${enableval}" = "no" && WANT_KONFORKA="no"
+ ]
+)
+if test "${WANT_KONFORKA}" = "yes" ; then
+ PKG_CHECK_MODULES([KONFORKA],[konforka],[
+ AC_MSG_RESULT([yes])
+ AC_SUBST([KONFORKA_CFLAGS])
+ AC_SUBST([KONFORKA_LIBS])
+ AC_DEFINE([HAVE_KONFORKA],,[defined in presence of konforka library])
+ AC_DEFINE([OPKELE_HAVE_KONFORKA],,[defined in presence of konforka library])
+ AC_SUBST([KONFORKA_KONFORKA],[konforka])
+ ]
+ )
+fi
+
+AC_LANG_PUSH([C++])
+ AC_CHECK_LIB([mimetic],[main],[
+ MIMETIC_LIBS=-lmimetic
+ AC_SUBST([MIMETIC_CFLAGS])
+ AC_SUBST([MIMETIC_LIBS])
+ ],[
+ AC_MSG_ERROR([no mimetic library found. get one from http://codesink.org/mimetic_mime_library.html])
+ ]
+ )
+AC_LANG_POP([C++])
+
+WANT_DOXYGEN="yes"
+AC_ARG_ENABLE([doxygen],
+ AC_HELP_STRING([--disable-doxygen],[do not generate documentation]),
+ [
+ test "${enableval}" = "no" && WANT_DOXYGEN="no"
+ ]
+)
+if test "${WANT_DOXYGEN}" = "yes" ; then
+ AC_WITH_DOXYGEN
+ AC_WITH_DOT
+else
+ AM_CONDITIONAL([HAVE_DOXYGEN],[false])
+ AM_CONDITIONAL([HAVE_DOT],[false])
+fi
+
+LIBCURL_CHECK_CONFIG(,,,[
+ AC_MSG_ERROR([no required libcurl library. get one from http://curl.haxx.se/])
+])
+AC_WITH_PCRE([
+ AC_WITH_PCREPP(,[
+ AC_MSG_ERROR([no pcre++ library found. get one at http://www.daemon.de/PCRE])
+ ])
+ ],[
+ AC_MSG_ERROR([no pcre library found. get one at http://www.pcre.org/])
+ ]
+)
+
+AC_CONFIG_FILES([
+ Makefile
+ libopkele.pc
+ Doxyfile
+ include/Makefile
+ lib/Makefile
+])
+AC_OUTPUT
diff --git a/include/.gitignore b/include/.gitignore
new file mode 100644
index 0000000..3dda729
--- a/dev/null
+++ b/include/.gitignore
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..b014752
--- a/dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,11 @@
+nobase_include_HEADERS = \
+ opkele/acconfig.h \
+ opkele/opkele-config.h \
+ opkele/types.h \
+ opkele/association.h \
+ opkele/exception.h \
+ opkele/server.h \
+ opkele/consumer.h
+EXTRA_DIST = \
+ opkele/data.h \
+ opkele/util.h
diff --git a/include/opkele/.gitignore b/include/opkele/.gitignore
new file mode 100644
index 0000000..ffa24dc
--- a/dev/null
+++ b/include/opkele/.gitignore
@@ -0,0 +1,2 @@
+acconfig.h
+stamp-h2
diff --git a/include/opkele/acconfig.h.in b/include/opkele/acconfig.h.in
new file mode 100644
index 0000000..d56a1cd
--- a/dev/null
+++ b/include/opkele/acconfig.h.in
@@ -0,0 +1,3 @@
+
+/* defined in presence of konforka library */
+#undef OPKELE_HAVE_KONFORKA
diff --git a/include/opkele/association.h b/include/opkele/association.h
new file mode 100644
index 0000000..5eb1cc3
--- a/dev/null
+++ b/include/opkele/association.h
@@ -0,0 +1,89 @@
+#ifndef __OPKELE_ASSOCIATION_H
+#define __OPKELE_ASSOCIATION_H
+
+#include <time.h>
+#include <opkele/types.h>
+
+/**
+ * @file
+ * @brief reference implementation of association_t
+ */
+
+/**
+ * @brief the main opkele namespace
+ */
+namespace opkele {
+
+ /**
+ * reference implementation of association_t class.
+ */
+ class association : public association_t {
+ public:
+ /**
+ * OpenID server name
+ */
+ string _server;
+ /**
+ * association handle
+ */
+ string _handle;
+ /**
+ * association type
+ */
+ string _assoc_type;
+ /**
+ * the secret
+ */
+ secret_t _secret;
+ /**
+ * expiration time
+ */
+ time_t _expires;
+ /**
+ * statelessness of the assoc_handle
+ */
+ bool _stateless;
+
+ /**
+ * @param __server the server name
+ * @param __handle association handle
+ * @param __assoc_type association type
+ * @param __secret the secret
+ * @param __expires expiration time
+ * @param __stateless statelessness of the assoc_handle
+ */
+ association(const string& __server, const string& __handle,
+ const string& __assoc_type, const secret_t& __secret,
+ time_t __expires, bool __stateless)
+ : _server(__server), _handle(__handle), _assoc_type(__assoc_type),
+ _secret(__secret), _expires(__expires), _stateless(__stateless) { }
+
+ /**
+ * @overload association_t::server()
+ */
+ virtual string server() const { return _server; }
+ /**
+ * @overload association_t::handle()
+ */
+ virtual string handle() const { return _handle; }
+ /**
+ * @overload association_t::assoc_type()
+ */
+ virtual string assoc_type() const { return _assoc_type; }
+ /**
+ * @overload association_t::secret()
+ */
+ virtual secret_t secret() const { return _secret; }
+ /**
+ * @overload association_t::expires_in()
+ */
+ virtual int expires_in() const { return _expires-time(0); }
+ /**
+ * @overload associationn_t::stateless()
+ */
+ virtual bool stateless() const { return _stateless; }
+ };
+
+}
+
+#endif /* __OPKELE_ASSOCIATION_H */
diff --git a/include/opkele/consumer.h b/include/opkele/consumer.h
new file mode 100644
index 0000000..b9c29bd
--- a/dev/null
+++ b/include/opkele/consumer.h
@@ -0,0 +1,135 @@
+#ifndef __OPKELE_CONSUMER_H
+#define __OPKELE_CONSUMER_H
+
+#include <opkele/types.h>
+
+/**
+ * @file
+ * @brief OpenID consumer-side functionality
+ */
+
+/**
+ * @brief the main opkele namespace
+ */
+namespace opkele {
+
+ /**
+ * implementation of basic consumer functionality
+ */
+ class consumer_t {
+ public:
+
+ /**
+ * store association. The function should be overridden in the real
+ * implementation to provide persistent associations store.
+ * @param server the OpenID server
+ * @param handle association handle
+ * @param secret the secret associated with the server and handle
+ * @param expires_in the number of seconds until the handle is expired
+ * @return the auto_ptr<> for the newly allocated association_t object
+ */
+ virtual assoc_t store_assoc(const string& server,const string& handle,const secret_t& secret,int expires_in) = 0;
+ /**
+ * retrieve stored association. The function should be overridden
+ * in the real implementation to provide persistent assocations
+ * store.
+ * @param server the OpenID server
+ * @param handle association handle
+ * @return the autho_ptr<> for the newly allocated association_t object
+ * @throw failed_lookup in case of error
+ */
+ virtual assoc_t retrieve_assoc(const string& server,const string& handle) = 0;
+ /**
+ * invalidate stored association. The function should be overridden
+ * in the real implementation of the consumer.
+ * @param server the OpenID server
+ * @param handle association handle
+ */
+ virtual void invalidate_assoc(const string& server,const string& handle) = 0;
+ /**
+ * retrieve any unexpired association for the server. If the
+ * function is not overridden in the real implementation, the new
+ * association will be established for each request.
+ * @param server the OpenID server
+ * @return the auto_ptr<> for the newly allocated association_t object
+ * @throw failed_lookup in case of absence of the handle
+ */
+ virtual assoc_t find_assoc(const string& server);
+
+ /**
+ * retrieve the metainformation contained in link tags from the
+ * page pointed by url. the function may implement caching of the
+ * information.
+ * @param url url to harvest for link tags
+ * @param server reference to the string object where to put
+ * openid.server value
+ * @param delegate reference to the string object where to put the
+ * openid.delegate value (if any)
+ */
+ virtual void retrieve_links(const string& url,string& server,string& delegate);
+
+ /**
+ * perform the associate request to OpenID server.
+ * @param server the OpenID server
+ * @return the auto_ptr<> for the newly allocated association_t
+ * object, representing established association
+ * @throw exception in case of error
+ */
+ assoc_t associate(const string& server);
+ /**
+ * prepare the parameters for the checkid_immediate
+ * request.
+ * @param identity the identity to verify
+ * @param return_to the return_to url to pass with the request
+ * @param trust_root the trust root to advertise with the request
+ * @return the location string
+ * @throw exception in case of error
+ */
+ string checkid_immediate(const string& identity,const string& return_to,const string& trust_root="");
+ /**
+ * prepare the parameters for the checkid_setup
+ * request.
+ * @param identity the identity to verify
+ * @param return_to the return_to url to pass with the request
+ * @param trust_root the trust root to advertise with the request
+ * @return the location string
+ * @throw exception in case of error
+ */
+ string checkid_setup(const string& identity,const string& return_to,const string& trust_root="");
+ /**
+ * the actual implementation behind checkid_immediate() and
+ * checkid_setup() functions.
+ * @param mode checkid_* mode - either mode_checkid_immediate or mode_checkid_setup
+ * @param identity the identity to verify
+ * @param return_to the return_to url to pass with the request
+ * @param trust_root the trust root to advertise with the request
+ * @return the location string
+ * @throw exception in case of error
+ */
+ string checkid_(mode_t mode,const string& identity,const string& return_to,const string& trust_root="");
+ /**
+ * verify the id_res response
+ * @param pin the response parameters
+ * @param identity the identity being checked (if not specified, extracted
+ * from the openid.identity parameter
+ * @throw id_res_mismatch in case of signature
+ * mismatch
+ * @throw id_res_setup in case of
+ * openid.user_setup_url failure (supposedly
+ * checkid_immediate only)
+ * @throw id_res_failed in case of failure
+ * @throw exception in case of other failures
+ */
+ void id_res(const params_t& pin,const string& identity="");
+ /**
+ * perform a check_authentication request.
+ * @param server the OpenID server
+ * @param p request parameters
+ */
+ void check_authentication(const string& server,const params_t& p);
+
+ };
+
+}
+
+#endif /* __OPKELE_CONSUMER_H */
diff --git a/include/opkele/data.h b/include/opkele/data.h
new file mode 100644
index 0000000..7fc635b
--- a/dev/null
+++ b/include/opkele/data.h
@@ -0,0 +1,12 @@
+#ifndef __OPKELE_DATA_H
+#define __OPKELE_DATA_H
+
+namespace opkele {
+
+ namespace data {
+ extern const char *_default_p;
+ extern const char *_default_g;
+ }
+}
+
+#endif /* __OPKELE_DATA_H */
diff --git a/include/opkele/exception.h b/include/opkele/exception.h
new file mode 100644
index 0000000..2ac0661
--- a/dev/null
+++ b/include/opkele/exception.h
@@ -0,0 +1,206 @@
+#ifndef __OPKELE_EXCEPTION_H
+#define __OPKELE_EXCEPTION_H
+
+/**
+ * @file
+ * @brief opkele exceptions
+ */
+
+#include <curl/curl.h>
+
+#include <opkele/opkele-config.h>
+#ifdef OPKELE_HAVE_KONFORKA
+# include <konforka/exception.h>
+/**
+ * the exception parameters declaration
+ */
+# define OPKELE_E_PARS const string& fi,const string&fu,int l,const string& w
+/**
+ * the exception parameters list to pass to constructor
+ */
+# define OPKELE_E_CONS_ fi,fu,l,
+/**
+ * the exception codepoint specification
+ */
+# define OPKELE_CP_ CODEPOINT,
+/**
+ * the simple rethrow of konforka-based exception
+ */
+# define OPKELE_RETHROW catch(konforka::exception& e) { e.see(CODEPOINT); throw }
+#else /* OPKELE_HAVE_KONFORKA */
+# include <stdexcept>
+/**
+ * the exception parameter declaration
+ */
+# define OPKELE_E_PARS const string& w
+/**
+ * the dummy prefix for exception parameters list to prepend in the absence of
+ * konforka library
+ */
+# define OPKELE_E_CONS_
+/**
+ * the dummy placeholder for konforka exception codepoint specification
+ */
+# define OPKELE_CP_
+/**
+ * the dummy define for the konforka-based rethrow of exception
+ */
+# define OPKELE_RETHROW
+#endif /* OPKELE_HAVE_KONFORKA */
+/**
+ * the exception parameters list to pass to constructor
+ */
+# define OPKELE_E_CONS OPKELE_E_CONS_ w
+
+/*
+ * @brief the main opkele namespace
+ */
+namespace opkele {
+ using std::string;
+
+ /**
+ * the base opkele exception class
+ */
+ class exception : public
+# ifdef OPKELE_HAVE_KONFORKA
+ konforka::exception
+# else
+ std::exception
+# endif
+ {
+ public:
+# ifdef OPKELE_HAVE_KONFORKA
+ explicit
+ exception(const string& fi,const string& fu,int l,const string& w)
+ : konforka::exception(fi,fu,l,w) { }
+# else /* OPKELE_HAVE_KONFORKA */
+ explicit
+ exception(const string& w)
+ : std::exception(w) { }
+# endif /* OPKELE_HAVE_KONFORKA */
+ };
+
+ /**
+ * thrown in case of failed conversion
+ */
+ class failed_conversion : public exception {
+ public:
+ failed_conversion(OPKELE_E_PARS)
+ : exception(OPKELE_E_CONS) { }
+ };
+ /**
+ * thrown in case of failed lookup (either parameter or persistent store)
+ */
+ class failed_lookup : public exception {
+ public:
+ failed_lookup(OPKELE_E_PARS)
+ : exception(OPKELE_E_CONS) { }
+ };
+ /**
+ * thrown in case of bad input (either local or network)
+ */
+ class bad_input : public exception {
+ public:
+ bad_input(OPKELE_E_PARS)
+ : exception(OPKELE_E_CONS) { }
+ };
+
+ /**
+ * thrown on failed assertion
+ */
+ class failed_assertion : public exception {
+ public:
+ failed_assertion(OPKELE_E_PARS)
+ : exception(OPKELE_E_CONS) { }
+ };
+
+ /**
+ * thrown if the handle being retrieved is invalid
+ */
+ class invalid_handle : public exception {
+ public:
+ invalid_handle(OPKELE_E_PARS)
+ : exception(OPKELE_E_CONS) { }
+ };
+ /**
+ * thrown if the handle passed to check_authentication request is not
+ * stateless
+ */
+ class stateful_handle : public exception {
+ public:
+ stateful_handle(OPKELE_E_PARS)
+ : exception(OPKELE_E_CONS) { }
+ };
+
+ /**
+ * thrown if check_authentication request fails
+ */
+ class failed_check_authentication : public exception {
+ public:
+ failed_check_authentication(OPKELE_E_PARS)
+ : exception(OPKELE_E_CONS) { }
+ };
+
+ /**
+ * thrown if the id_res request result is negative
+ */
+ class id_res_failed : public exception {
+ public:
+ id_res_failed(OPKELE_E_PARS)
+ : exception(OPKELE_E_CONS) { }
+ };
+ /**
+ * thrown if the user_setup_url is provided with negative response
+ */
+ class id_res_setup : public id_res_failed {
+ public:
+ string setup_url;
+ id_res_setup(OPKELE_E_PARS,const string& su)
+ : id_res_failed(OPKELE_E_CONS), setup_url(su) { }
+ ~id_res_setup() throw() { }
+ };
+ /**
+ * thrown in case of signature mismatch
+ */
+ class id_res_mismatch : public id_res_failed {
+ public:
+ id_res_mismatch(OPKELE_E_PARS)
+ : id_res_failed(OPKELE_E_CONS) { }
+ };
+
+ /**
+ * openssl malfunction occured
+ */
+ class exception_openssl : public exception {
+ public:
+ unsigned long _error;
+ string _ssl_string;
+ exception_openssl(OPKELE_E_PARS);
+ ~exception_openssl() throw() { }
+ };
+
+ /**
+ * network operation related error occured
+ */
+ class exception_network : public exception {
+ public:
+ exception_network(OPKELE_E_PARS)
+ : exception(OPKELE_E_CONS) { }
+ };
+
+ /**
+ * network operation related error occured, specifically, related to
+ * libcurl
+ */
+ class exception_curl : public exception_network {
+ public:
+ CURLcode _error;
+ string _curl_string;
+ exception_curl(OPKELE_E_PARS);
+ exception_curl(OPKELE_E_PARS,CURLcode e);
+ ~exception_curl() throw() { }
+ };
+
+}
+
+#endif /* __OPKELE_EXCEPTION_H */
diff --git a/include/opkele/opkele-config.h b/include/opkele/opkele-config.h
new file mode 100644
index 0000000..70c2d26
--- a/dev/null
+++ b/include/opkele/opkele-config.h
@@ -0,0 +1,6 @@
+#ifndef __OPKELE_OPKELE_CONFIG_H
+#define __OPKELE_OPKELE_CONFIG_H
+
+#include "opkele/acconfig.h"
+
+#endif /* __OPKELE_OPKELE_CONFIG_H */
diff --git a/include/opkele/server.h b/include/opkele/server.h
new file mode 100644
index 0000000..fe07448
--- a/dev/null
+++ b/include/opkele/server.h
@@ -0,0 +1,95 @@
+#ifndef __OPKELE_SERVER_H
+#define __OPKELE_SERVER_H
+
+/**
+ * @file
+ * @brief OpenID server-side functionality
+ */
+
+#include <opkele/types.h>
+
+/**
+ * @brief the main opkele namespace
+ */
+namespace opkele {
+
+ /**
+ * implementation of basic server functionality
+ */
+ class server_t {
+ public:
+
+ /**
+ * allocate the new association. The function should be overridden
+ * in the real implementation to provide persistent assocations
+ * store.
+ * @param mode the mode of request being processed to base the
+ * statelessness of the association upon
+ * @return the auto_ptr<> for the newly allocated association_t object
+ */
+ virtual assoc_t alloc_assoc(mode_t mode) = 0;
+ /**
+ * retrieve the association. The function should be overridden in
+ * the reqal implementation to provide persistent assocations
+ * store.
+ * @param h association handle
+ * @return the auto_ptr<> for the newly allocated association_t object
+ * @throw failed_lookup in case of failure
+ */
+ virtual assoc_t retrieve_assoc(const string& h) = 0;
+
+ /**
+ * validate the identity.
+ * @param assoc association object
+ * @param pin incoming request parameters
+ * @param identity being verified
+ * @param trust_root presented in the request
+ * @throw exception if identity can not be confirmed
+ */
+ virtual void validate(const association_t& assoc,const params_t& pin,const string& identity,const string& trust_root) = 0;
+
+
+ /**
+ * process the associate request.
+ * @param pin the incoming request parameters
+ * @param pout the store for the response parameters
+ */
+ void associate(const params_t& pin,params_t& pout);
+ /**
+ * process the checkid_immediate request.
+ * @param pin the incoming request parameters
+ * @param return_to reference to the object to store return_to url to
+ * @param pout the response parameters
+ * @throw exception in case of errors or negative reply
+ */
+ void checkid_immediate(const params_t& pin,string& return_to,params_t& pout);
+ /**
+ * process the checkid_setup request.
+ * @param pin the incoming request parameters
+ * @param return_to reference to the object to store return_to url to
+ * @param pout the response parameters
+ * @throw exception in case of errors or negative reply
+ */
+ void checkid_setup(const params_t& pin,string& return_to,params_t& pout);
+ /**
+ * the actual functionality behind checkid_immediate() and
+ * checkid_setup()
+ * @param mode the request being processed (either
+ * mode_checkid_immediate or mode_checkid_setup)
+ * @param pin the incoming request parameters
+ * @param return_to reference to the object to store return_to url to
+ * @param pout the response parameters
+ * @throw exception in case of errors or negative reply
+ */
+ void checkid_(mode_t mode,const params_t& pin,string& return_to,params_t& pout);
+ /**
+ * process the check_authentication request.
+ * @param pin incoming request parameters
+ * @param pout response parameters
+ */
+ void check_authentication(const params_t& pin,params_t& pout);
+ };
+
+}
+
+#endif /* __OPKELE_SERVER_H */
diff --git a/include/opkele/types.h b/include/opkele/types.h
new file mode 100644
index 0000000..ba06776
--- a/dev/null
+++ b/include/opkele/types.h
@@ -0,0 +1,168 @@
+#ifndef __OPKELE_TYPES_H
+#define __OPKELE_TYPES_H
+
+/**
+ * @file
+ * @brief various types declarations
+ */
+
+#include <ostream>
+#include <vector>
+#include <string>
+#include <map>
+#include <memory>
+
+/**
+ * @brief the main opkele namespace
+ */
+namespace opkele {
+ using std::vector;
+ using std::string;
+ using std::map;
+ using std::ostream;
+ using std::auto_ptr;
+
+ /**
+ * the OpenID operation mode
+ */
+ typedef enum _mode_t {
+ mode_associate,
+ mode_checkid_immediate,
+ mode_checkid_setup,
+ mode_check_association
+ } mode_t;
+
+ /**
+ * the association secret container
+ */
+ class secret_t : public vector<unsigned char> {
+ public:
+
+ /**
+ * xor the secret and hmac together and encode, using base64
+ * @param key_sha1 pointer to the sha1 digest
+ * @param rv reference to the return value
+ */
+ void enxor_to_base64(const unsigned char *key_sha1,string& rv) const;
+ /**
+ * decode base64-encoded secret and xor it with the sha1 digest
+ * @param key_sha1 pointer to the message digest
+ * @param b64 base64-encoded secret value
+ */
+ void enxor_from_base64(const unsigned char *key_sha1,const string& b64);
+ /**
+ * plainly encode to base64 representation
+ * @param rv reference to the return value
+ */
+ void to_base64(string& rv) const;
+ /**
+ * decode cleartext secret from base64
+ * @param b64 base64-encoded representation of the secret value
+ */
+ void from_base64(const string& b64);
+ };
+
+ /**
+ * Interface to the association.
+ */
+ class association_t {
+ public:
+
+ /**
+ * retrieve the server with which association was established.
+ * @return server name
+ */
+ virtual string server() const = 0;
+ /**
+ * retrieve the association handle.
+ * @return handle
+ */
+ virtual string handle() const = 0;
+ /**
+ * retrieve the association type.
+ * @return association type
+ */
+ virtual string assoc_type() const = 0;
+ /**
+ * retrieve the association secret.
+ * @return association secret
+ */
+ virtual secret_t secret() const = 0;
+ /**
+ * retrieve the number of seconds the association expires in.
+ * @return seconds till expiration
+ */
+ virtual int expires_in() const = 0;
+ /**
+ * check whether the association is stateless.
+ * @return true if stateless
+ */
+ virtual bool stateless() const = 0;
+ };
+
+ /**
+ * the auto_ptr<> for association_t object type
+ */
+ typedef auto_ptr<association_t> assoc_t;
+
+ /**
+ * request/response parameters map
+ */
+ class params_t : public map<string,string> {
+ public:
+
+ /**
+ * check whether the parameter is present.
+ * @param n the parameter name
+ * @return true if yes
+ */
+ bool has_param(const string& n) const;
+ /**
+ * retrieve the parameter (const version)
+ * @param n the parameter name
+ * @return the parameter value
+ * @throw failed_lookup if there is no such parameter
+ */
+ const string& get_param(const string& n) const;
+ /**
+ * retrieve the parameter.
+ * @param n the parameter name
+ * @return the parameter value
+ * @throw failed_lookup if there is no such parameter
+ */
+ string& get_param(const string& n);
+
+ /**
+ * parse the OpenID key/value data.
+ * @param kv the OpenID key/value data
+ */
+ void parse_keyvalues(const string& kv);
+ /**
+ * sign the fields.
+ * @param secret the secret used for signing
+ * @param sig reference to the string, containing base64-encoded
+ * result
+ * @param slist the comma-separated list of fields to sign
+ * @param prefix the string to prepend to parameter names
+ */
+ void sign(secret_t secret,string& sig,const string& slist,const char *prefix=0) const;
+
+ /**
+ * append parameters to the URL as a GET-request parameters.
+ * @param url the base URL
+ * @param prefix the string to prepend to parameter names
+ * @return the ready-to-use location
+ */
+ string append_query(const string& url,const char *prefix = "openid.") const;
+ };
+
+ /**
+ * dump the key/value pairs for the parameters to the stream.
+ * @param o output stream
+ * @param p the parameters
+ */
+ ostream& operator << (ostream& o,const params_t& p);
+
+}
+
+#endif /* __OPKELE_TYPES_H */
diff --git a/include/opkele/util.h b/include/opkele/util.h
new file mode 100644
index 0000000..fbbef93
--- a/dev/null
+++ b/include/opkele/util.h
@@ -0,0 +1,60 @@
+#ifndef __OPKELE_UTIL_H
+#define __OPKELE_UTIL_H
+
+#include <time.h>
+#include <string>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+
+namespace opkele {
+ using std::string;
+
+ namespace util {
+
+ class bignum_t {
+ public:
+ BIGNUM *_bn;
+
+ bignum_t() : _bn(0) { }
+ bignum_t(BIGNUM *bn) : _bn(bn) { }
+ ~bignum_t() throw() { if(_bn) BN_free(_bn); }
+
+ bignum_t& operator=(BIGNUM *bn) { if(_bn) BN_free(_bn); _bn = bn; return *this; }
+
+ operator const BIGNUM*(void) const { return _bn; }
+ operator BIGNUM*(void) { return _bn; }
+ };
+ class dh_t {
+ public:
+ DH *_dh;
+
+ dh_t() : _dh(0) { }
+ dh_t(DH *dh) : _dh(dh) { }
+ ~dh_t() throw() { if(_dh) DH_free(_dh); }
+
+ dh_t& operator=(DH *dh) { if(_dh) DH_free(_dh); _dh = dh; return *this; }
+
+ operator const DH*(void) const { return _dh; }
+ operator DH*(void) { return _dh; }
+
+ DH* operator->() { return _dh; }
+ const DH* operator->() const { return _dh; }
+ };
+
+ BIGNUM *base64_to_bignum(const string& b64);
+ BIGNUM *dec_to_bignum(const string& dec);
+ string bignum_to_base64(const BIGNUM *bn);
+
+ string time_to_w3c(time_t t);
+ time_t w3c_to_time(const string& w);
+
+ string canonicalize_url(const string& url);
+ string url_encode(const string& str);
+
+ string long_to_string(long l);
+ long string_to_long(const string& s);
+ }
+
+}
+
+#endif /* __OPKELE_UTIL_H */
diff --git a/lib/.gitignore b/lib/.gitignore
new file mode 100644
index 0000000..2325be6
--- a/dev/null
+++ b/lib/.gitignore
@@ -0,0 +1,7 @@
+*.lo
+*.o
+Makefile.in
+libopkele.la
+.libs
+.deps
+Makefile
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..6f3f9f3
--- a/dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,24 @@
+lib_LTLIBRARIES = libopkele.la
+
+INCLUDES = \
+ -I${top_srcdir}/include/ \
+ ${KONFORKA_CFLAGS} \
+ ${OPENSSL_CFLAGS} \
+ ${MIMETIC_CFLAGS} \
+ ${LIBCURL_CPPFLAGS} \
+ ${PCREPP_CFLAGS}
+LDADD = \
+ ${LIBCURL} \
+ ${PCREPP_LIBS} \
+ ${MIMETIC_LIBS} \
+ ${OPENSSL_LIBS} \
+ ${KONFORKA_LIBS}
+
+libopkele_la_SOURCES = \
+ params.cc \
+ util.cc \
+ server.cc \
+ secret.cc \
+ data.cc \
+ consumer.cc \
+ exception.cc
diff --git a/lib/consumer.cc b/lib/consumer.cc
new file mode 100644
index 0000000..bd76b61
--- a/dev/null
+++ b/lib/consumer.cc
@@ -0,0 +1,316 @@
+#include <algorithm>
+#include <opkele/util.h>
+#include <opkele/exception.h>
+#include <opkele/data.h>
+#include <opkele/consumer.h>
+#include <openssl/sha.h>
+#include <openssl/hmac.h>
+#include <mimetic/mimetic.h>
+#include <curl/curl.h>
+#include <pcre++.h>
+
+#include <iostream>
+
+/* silly mimetic */
+#undef PACKAGE
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef VERSION
+
+#include "config.h"
+
+namespace opkele {
+ using namespace std;
+
+ class curl_t {
+ public:
+ CURL *_c;
+
+ curl_t() : _c(0) { }
+ curl_t(CURL *c) : _c(c) { }
+ ~curl_t() throw() { if(_c) curl_easy_cleanup(_c); }
+
+ curl_t& operator=(CURL *c) { if(_c) curl_easy_cleanup(_c); _c=c; return *this; }
+
+ operator const CURL*(void) const { return _c; }
+ operator CURL*(void) { return _c; }
+ };
+
+ static CURLcode curl_misc_sets(CURL* c) {
+ CURLcode r;
+ (r=curl_easy_setopt(c,CURLOPT_FOLLOWLOCATION,1))
+ || (r=curl_easy_setopt(c,CURLOPT_MAXREDIRS,5))
+ || (r=curl_easy_setopt(c,CURLOPT_DNS_CACHE_TIMEOUT,120))
+ || (r=curl_easy_setopt(c,CURLOPT_DNS_USE_GLOBAL_CACHE,1))
+ || (r=curl_easy_setopt(c,CURLOPT_USERAGENT,PACKAGE_NAME"/"PACKAGE_VERSION))
+ || (r=curl_easy_setopt(c,CURLOPT_TIMEOUT,20))
+ ;
+ return r;
+ }
+
+ static size_t _curl_tostring(void *ptr,size_t size,size_t nmemb,void *stream) {
+ string *str = (string*)stream;
+ size_t bytes = size*nmemb;
+ size_t get = min(16384-str->length(),bytes);
+ str->append((const char*)ptr,get);
+ return get;
+ }
+
+ assoc_t consumer_t::associate(const string& server) {
+ util::dh_t dh = DH_new();
+ if(!dh)
+ throw exception_openssl(OPKELE_CP_ "failed to DH_new()");
+ dh->p = util::dec_to_bignum(data::_default_p);
+ dh->g = util::dec_to_bignum(data::_default_g);
+ if(!DH_generate_key(dh))
+ throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()");
+ string request =
+ "openid.mode=associate"
+ "&openid.assoc_type=HMAC-SHA1"
+ "&openid.session_type=DH-SHA1"
+ "&openid.dh_consumer_public=";
+ request += util::url_encode(util::bignum_to_base64(dh->pub_key));
+ curl_t curl = curl_easy_init();
+ if(!curl)
+ throw exception_curl(OPKELE_CP_ "failed to curl_easy_init()");
+ string response;
+ CURLcode r;
+ (r=curl_misc_sets(curl))
+ || (r=curl_easy_setopt(curl,CURLOPT_URL,server.c_str()))
+ || (r=curl_easy_setopt(curl,CURLOPT_POST,1))
+ || (r=curl_easy_setopt(curl,CURLOPT_POSTFIELDS,request.data()))
+ || (r=curl_easy_setopt(curl,CURLOPT_POSTFIELDSIZE,request.length()))
+ || (r=curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curl_tostring))
+ || (r=curl_easy_setopt(curl,CURLOPT_WRITEDATA,&response))
+ ;
+ if(r)
+ throw exception_curl(OPKELE_CP_ "failed to curl_easy_setopt()",r);
+ if(r=curl_easy_perform(curl))
+ throw exception_curl(OPKELE_CP_ "failed to curl_easy_perform()",r);
+ params_t p; p.parse_keyvalues(response);
+ if(p.has_param("assoc_type") && p.get_param("assoc_type")!="HMAC-SHA1")
+ throw bad_input(OPKELE_CP_ "unsupported assoc_type");
+ string st;
+ if(p.has_param("session_type")) st = p.get_param("session_type");
+ if((!st.empty()) && st!="DH-SHA1")
+ throw bad_input(OPKELE_CP_ "unsupported session_type");
+ secret_t secret;
+ if(st.empty()) {
+ secret.from_base64(p.get_param("mac_key"));
+ }else{
+ util::bignum_t s_pub = util::base64_to_bignum(p.get_param("dh_server_public"));
+ vector<unsigned char> ck(DH_size(dh));
+ int cklen = DH_compute_key(&(ck.front()),s_pub,dh);
+ if(cklen<0)
+ throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()");
+ ck.resize(cklen);
+ // OpenID algorithm requires extra zero in case of set bit here
+ if(ck[0]&0x80) ck.insert(ck.begin(),1,0);
+ unsigned char key_sha1[SHA_DIGEST_LENGTH];
+ SHA1(&(ck.front()),ck.size(),key_sha1);
+ secret.enxor_from_base64(key_sha1,p.get_param("enc_mac_key"));
+ }
+ int expires_in = 0;
+ if(p.has_param("expires_in")) {
+ expires_in = util::string_to_long(p.get_param("expires_in"));
+ }else if(p.has_param("issued") && p.has_param("expiry")) {
+ expires_in = util::w3c_to_time(p.get_param("expiry"))-util::w3c_to_time(p.get_param("issued"));
+ }else
+ throw bad_input(OPKELE_CP_ "no expiration information");
+ return store_assoc(server,p.get_param("assoc_handle"),secret,expires_in);
+ }
+
+ string consumer_t::checkid_immediate(const string& identity,const string& return_to,const string& trust_root) {
+ return checkid_(mode_checkid_immediate,identity,return_to,trust_root);
+ }
+ string consumer_t::checkid_setup(const string& identity,const string& return_to,const string& trust_root) {
+ return checkid_(mode_checkid_setup,identity,return_to,trust_root);
+ }
+ string consumer_t::checkid_(mode_t mode,const string& identity,const string& return_to,const string& trust_root) {
+ params_t p;
+ if(mode==mode_checkid_immediate)
+ p["mode"]="checkid_immediate";
+ else if(mode==mode_checkid_setup)
+ p["mode"]="checkid_setup";
+ else
+ throw bad_input(OPKELE_CP_ "unknown checkid_* mode");
+ string iurl = util::canonicalize_url(identity);
+ string server, delegate;
+ retrieve_links(iurl,server,delegate);
+ p["identity"] = delegate.empty()?iurl:delegate;
+ if(!trust_root.empty())
+ p["trust_root"] = trust_root;
+ p["return_to"] = return_to;
+ try {
+ try {
+ string ah = find_assoc(server)->handle();
+ p["assoc_handle"] = ah;
+ }catch(failed_lookup& fl) {
+ string ah = associate(server)->handle();
+ p["assoc_handle"] = ah;
+ }
+ }catch(exception& e) { }
+ return p.append_query(server);
+ }
+
+ void consumer_t::id_res(const params_t& pin,const string& identity) {
+ if(pin.has_param("openid.user_setup_url"))
+ throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided",pin.get_param("openid.user_setup_url"));
+ string server,delegate;
+ retrieve_links(identity.empty()?pin.get_param("openid.identity"):util::canonicalize_url(identity),server,delegate);
+ try {
+ assoc_t assoc = retrieve_assoc(server,pin.get_param("openid.assoc_handle"));
+ const string& sigenc = pin.get_param("openid.sig");
+ mimetic::Base64::Decoder b;
+ vector<unsigned char> sig;
+ mimetic::decode(
+ sigenc.begin(),sigenc.end(), b,
+ back_insert_iterator<vector<unsigned char> >(sig) );
+ const string& slist = pin.get_param("openid.signed");
+ string kv;
+ string::size_type p = 0;
+ while(true) {
+ string::size_type co = slist.find(',',p);
+ string f = (co==string::npos)?slist.substr(p):slist.substr(p,co-p);
+ kv += f;
+ kv += ':';
+ f.insert(0,"openid.");
+ kv += pin.get_param(f);
+ kv += '\n';
+ if(co==string::npos)
+ break;
+ p = co+1;
+ }
+ secret_t secret = assoc->secret();
+ unsigned int md_len = 0;
+ unsigned char *md = HMAC(
+ EVP_sha1(),
+ &(secret.front()),secret.size(),
+ (const unsigned char *)kv.data(),kv.length(),
+ 0,&md_len);
+ if(sig.size()!=md_len || memcmp(&(sig.front()),md,md_len))
+ throw id_res_mismatch(OPKELE_CP_ "signature mismatch");
+ }catch(failed_lookup& e) { /* XXX: more specific? */
+ const string& slist = pin.get_param("openid.signed");
+ string::size_type pp = 0;
+ params_t p;
+ while(true) {
+ string::size_type co = slist.find(',',pp);
+ string f = "openid.";
+ f += (co==string::npos)?slist.substr(pp):slist.substr(pp,co-pp);
+ p[f] = pin.get_param(f);
+ if(co==string::npos)
+ break;
+ pp = co+1;
+ }
+ p["openid.assoc_handle"] = pin.get_param("openid.assoc_handle");
+ p["openid.sig"] = pin.get_param("openid.sig");
+ p["openid.signed"] = pin.get_param("openid.signed");
+ try {
+ string ih = pin.get_param("openid.invalidate_handle");
+ p["openid.invalidate_handle"] = ih;
+ }catch(failed_lookup& fl) { }
+ try {
+ check_authentication(server,p);
+ }catch(failed_check_authentication& fca) {
+ throw id_res_failed(OPKELE_CP_ "failed to check_authentication()");
+ }
+ }
+ }
+
+ void consumer_t::check_authentication(const string& server,const params_t& p) {
+ string request = "openid.mode=check_authentication";
+ for(params_t::const_iterator i=p.begin();i!=p.end();++i) {
+ if(i->first!="openid.mode") {
+ request += '&';
+ request += i->first;
+ request += '=';
+ request += util::url_encode(i->second);
+ }
+ }
+ curl_t curl = curl_easy_init();
+ if(!curl)
+ throw exception_curl(OPKELE_CP_ "failed to curl_easy_init()");
+ string response;
+ CURLcode r;
+ (r=curl_misc_sets(curl))
+ || (r=curl_easy_setopt(curl,CURLOPT_URL,server.c_str()))
+ || (r=curl_easy_setopt(curl,CURLOPT_POST,1))
+ || (r=curl_easy_setopt(curl,CURLOPT_POSTFIELDS,request.data()))
+ || (r=curl_easy_setopt(curl,CURLOPT_POSTFIELDSIZE,request.length()))
+ || (r=curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curl_tostring))
+ || (r=curl_easy_setopt(curl,CURLOPT_WRITEDATA,&response))
+ ;
+ if(r)
+ throw exception_curl(OPKELE_CP_ "failed to curl_easy_setopt()",r);
+ if(r=curl_easy_perform(curl))
+ throw exception_curl(OPKELE_CP_ "failed to curl_easy_perform()",r);
+ params_t pp; pp.parse_keyvalues(response);
+ if(pp.has_param("invalidate_handle"))
+ invalidate_assoc(server,pp.get_param("invalidate_handle"));
+ if(pp.has_param("is_valid")) {
+ if(pp.get_param("is_valid")=="true")
+ return;
+ }else if(pp.has_param("lifetime")) {
+ if(util::string_to_long(pp.get_param("lifetime")))
+ return;
+ }
+ throw failed_check_authentication(OPKELE_CP_ "failed to verify response");
+ }
+
+ void consumer_t::retrieve_links(const string& url,string& server,string& delegate) {
+ server.erase();
+ delegate.erase();
+ curl_t curl = curl_easy_init();
+ if(!curl)
+ throw exception_curl(OPKELE_CP_ "failed to curl_easy_init()");
+ string html;
+ CURLcode r;
+ (r=curl_misc_sets(curl))
+ || (r=curl_easy_setopt(curl,CURLOPT_URL,url.c_str()))
+ || (r=curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curl_tostring))
+ || (r=curl_easy_setopt(curl,CURLOPT_WRITEDATA,&html))
+ ;
+ if(r)
+ throw exception_curl(OPKELE_CP_ "failed to curl_easy_setopt()",r);
+ r = curl_easy_perform(curl);
+ if(r && r!=CURLE_WRITE_ERROR)
+ throw exception_curl(OPKELE_CP_ "failed to curl_easy_perform()",r);
+ pcrepp::Pcre bre("<body\\b",PCRE_CASELESS);
+ // strip out everything past body
+ if(bre.search(html))
+ html.erase(bre.get_match_start());
+ pcrepp::Pcre hdre("<head[^>]*>",PCRE_CASELESS);
+ if(!hdre.search(html))
+ throw bad_input(OPKELE_CP_ "failed to find head");
+ html.erase(0,hdre.get_match_end()+1);
+ pcrepp::Pcre lre("<link\\b([^>]+)>",PCRE_CASELESS),
+ rre("\\brel=['\"]([^'\"]+)['\"]",PCRE_CASELESS),
+ hre("\\bhref=['\"]([^'\"]+)['\"]",PCRE_CASELESS);
+ while(lre.search(html)) {
+ string attrs = lre[0];
+ html.erase(0,lre.get_match_end()+1);
+ if(!(rre.search(attrs)&&hre.search(attrs)))
+ continue;
+ if(rre[0]=="openid.server") {
+ server = hre[0];
+ if(!delegate.empty())
+ break;
+ }else if(rre[0]=="openid.delegate") {
+ delegate = hre[0];
+ if(!server.empty())
+ break;
+ }
+ }
+ if(server.empty())
+ throw failed_assertion(OPKELE_CP_ "The location has no openid.server declaration");
+ }
+
+ assoc_t consumer_t::find_assoc(const string& server) {
+ throw failed_lookup(OPKELE_CP_ "no find_assoc() provided");
+ }
+
+}
diff --git a/lib/data.cc b/lib/data.cc
new file mode 100644
index 0000000..c040430
--- a/dev/null
+++ b/lib/data.cc
@@ -0,0 +1,11 @@
+#include <opkele/data.h>
+
+namespace opkele {
+
+ namespace data {
+
+ const char *_default_p = "155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848253359305585439638443";
+ const char *_default_g = "2";
+
+ }
+}
diff --git a/lib/exception.cc b/lib/exception.cc
new file mode 100644
index 0000000..b7c1702
--- a/dev/null
+++ b/lib/exception.cc
@@ -0,0 +1,22 @@
+#include <openssl/err.h>
+#include <curl/curl.h>
+#include <opkele/exception.h>
+
+namespace opkele {
+
+ exception_openssl::exception_openssl(OPKELE_E_PARS)
+ : _error(ERR_peek_last_error()),
+ _ssl_string(ERR_error_string(_error,0)),
+ exception(OPKELE_E_CONS_ w+" ["+_ssl_string+']') {
+ }
+
+ exception_curl::exception_curl(OPKELE_E_PARS)
+ : _error(CURLE_OK),
+ exception_network(OPKELE_E_CONS) { }
+ exception_curl::exception_curl(OPKELE_E_PARS,CURLcode e)
+ : _error(e),
+ _curl_string(curl_easy_strerror(e)),
+ exception_network(OPKELE_E_CONS_ w+" ["+_curl_string+']') {
+ }
+
+}
diff --git a/lib/params.cc b/lib/params.cc
new file mode 100644
index 0000000..14f1a53
--- a/dev/null
+++ b/lib/params.cc
@@ -0,0 +1,96 @@
+#include <opkele/types.h>
+#include <opkele/exception.h>
+#include <opkele/util.h>
+#include <openssl/sha.h>
+#include <openssl/hmac.h>
+#include <mimetic/mimetic.h>
+
+namespace opkele {
+ using namespace std;
+
+ bool params_t::has_param(const string& n) const {
+ return find(n)!=end();
+ }
+ const string& params_t::get_param(const string& n) const {
+ const_iterator i = find(n);
+ if(i==end())
+ throw failed_lookup(OPKELE_CP_ n+": no such parameter");
+ return i->second;
+ }
+ string& params_t::get_param(const string& n) {
+ iterator i = find(n);
+ if(i==end())
+ throw failed_lookup(OPKELE_CP_ n+": no such parameter");
+ return i->second;
+ }
+
+ void params_t::parse_keyvalues(const string& kv) {
+ clear();
+ string::size_type p = 0;
+ while(true) {
+ string::size_type co = kv.find(':',p);
+ if(co==string::npos)
+ break;
+ string::size_type nl = kv.find('\n',co+1);
+ if(nl==string::npos)
+ throw bad_input(OPKELE_CP_ "malformed input");
+ insert(value_type(kv.substr(p,co-p),kv.substr(co+1,nl-co-1)));
+ p = nl+1;
+ }
+ }
+
+ void params_t::sign(secret_t secret,string& sig,const string& slist,const char *prefix) const {
+ string kv;
+ string::size_type p = 0;
+ while(true) {
+ string::size_type co = slist.find(',',p);
+ string f = (co==string::npos)?slist.substr(p):slist.substr(p,co-p);
+ kv += f;
+ kv += ':';
+ if(prefix) f.insert(0,prefix);
+ kv += get_param(f);
+ kv += '\n';
+ if(co==string::npos)
+ break;
+ p = co+1;
+ }
+ unsigned int md_len = 0;
+ unsigned char *md = HMAC(
+ EVP_sha1(),
+ &(secret.front()),secret.size(),
+ (const unsigned char *)kv.data(),kv.length(),
+ 0,&md_len);
+ mimetic::Base64::Encoder b(0);
+ sig.erase();
+ mimetic::encode(
+ md,md+md_len, b,
+ back_insert_iterator<string>(sig) );
+ }
+
+ string params_t::append_query(const string& url,const char *prefix) const {
+ string rv = url;
+ bool p = true;
+ if(rv.find('?')==string::npos) {
+ rv += '?';
+ p = false;
+ }
+ for(const_iterator i=begin();i!=end();++i) {
+ if(p)
+ rv += '&';
+ else
+ p = true;
+ rv += prefix;
+ rv += i->first;
+ rv += '=';
+ rv += util::url_encode(i->second);
+ }
+ return rv;
+ }
+
+ ostream& operator << (ostream& o,const params_t& p) {
+ for(params_t::const_iterator i=p.begin();i!=p.end();++i)
+ o << i->first << ':' << i->second << '\n';
+ return o;
+ }
+
+}
diff --git a/lib/secret.cc b/lib/secret.cc
new file mode 100644
index 0000000..ae8a3c5
--- a/dev/null
+++ b/lib/secret.cc
@@ -0,0 +1,61 @@
+#include <algorithm>
+#include <functional>
+#include <opkele/types.h>
+#include <opkele/exception.h>
+#include <mimetic/mimetic.h>
+
+namespace opkele {
+ using namespace std;
+
+ template<class __a1,class __a2,class __r>
+ struct bitwise_xor : public binary_function<__a1,__a2,__r> {
+ __r operator() (const __a1& a1,const __a2& a2) const {
+ return a1^a2;
+ }
+ };
+
+ void secret_t::enxor_to_base64(const unsigned char *key_sha1,string& rv) const {
+ if(size()!=20)
+ throw bad_input(OPKELE_CP_ "wrong secret size");
+ vector<unsigned char> tmp;
+ transform(
+ begin(), end(),
+ key_sha1,
+ back_insert_iterator<vector<unsigned char> >(tmp),
+ bitwise_xor<unsigned char,unsigned char,unsigned char>() );
+ mimetic::Base64::Encoder b(0);
+ mimetic::encode(
+ tmp.begin(),tmp.end(), b,
+ back_insert_iterator<string>(rv) );
+ }
+
+ void secret_t::enxor_from_base64(const unsigned char *key_sha1,const string& b64) {
+ mimetic::Base64::Decoder b;
+ clear();
+ mimetic::decode(
+ b64.begin(),b64.end(), b,
+ back_insert_iterator<secret_t>(*this) );
+ transform(
+ begin(), end(),
+ key_sha1,
+ begin(),
+ bitwise_xor<unsigned char,unsigned char,unsigned char>() );
+ }
+
+ void secret_t::to_base64(string& rv) const {
+ if(size()!=20)
+ throw bad_input(OPKELE_CP_ "wrong secret size");
+ mimetic::Base64::Encoder b(0);
+ mimetic::encode(
+ begin(),end(), b,
+ back_insert_iterator<string>(rv) );
+ }
+
+ void secret_t::from_base64(const string& b64) {
+ mimetic::Base64::Decoder b;
+ mimetic::decode(
+ b64.begin(),b64.end(), b,
+ back_insert_iterator<secret_t>(*this) );
+ }
+
+}
diff --git a/lib/server.cc b/lib/server.cc
new file mode 100644
index 0000000..51d4554
--- a/dev/null
+++ b/lib/server.cc
@@ -0,0 +1,169 @@
+#include <vector>
+#include <openssl/sha.h>
+#include <openssl/hmac.h>
+#include <mimetic/mimetic.h>
+#include <opkele/util.h>
+#include <opkele/exception.h>
+#include <opkele/server.h>
+#include <opkele/data.h>
+
+namespace opkele {
+ using namespace std;
+
+ void server_t::associate(const params_t& pin,params_t& pout) {
+ util::dh_t dh;
+ util::bignum_t c_pub;
+ unsigned char key_sha1[SHA_DIGEST_LENGTH];
+ enum {
+ sess_cleartext,
+ sess_dh_sha1
+ } st = sess_cleartext;
+ if(
+ pin.has_param("openid.session_type")
+ && pin.get_param("openid.session_type")=="DH-SHA1" ) {
+ /* TODO: fallback to cleartext in case of exceptions here? */
+ if(!(dh = DH_new()))
+ throw exception_openssl(OPKELE_CP_ "failed to DH_new()");
+ c_pub = util::base64_to_bignum(pin.get_param("openid.dh_consumer_public"));
+ if(pin.has_param("openid.dh_modulus"))
+ dh->p = util::base64_to_bignum(pin.get_param("openid.dh_modulus"));
+ else
+ dh->p = util::dec_to_bignum(data::_default_p);
+ if(pin.has_param("openid.dh_gen"))
+ dh->g = util::base64_to_bignum(pin.get_param("openid.dh_gen"));
+ else
+ dh->g = util::dec_to_bignum(data::_default_g);
+ if(!DH_generate_key(dh))
+ throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()");
+ vector<unsigned char> ck(DH_size(dh));
+ int cklen = DH_compute_key(&(ck.front()),c_pub,dh);
+ if(cklen<0)
+ throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()");
+ ck.resize(cklen);
+ // OpenID algorithm requires extra zero in case of set bit here
+ if(ck[0]&0x80) ck.insert(ck.begin(),1,0);
+ SHA1(&(ck.front()),ck.size(),key_sha1);
+ st = sess_dh_sha1;
+ }
+ assoc_t assoc = alloc_assoc(mode_associate);
+ time_t now = time(0);
+ pout.clear();
+ pout["assoc_type"] = assoc->assoc_type();
+ pout["assoc_handle"] = assoc->handle();
+ /* TODO: eventually remove deprecated stuff */
+ pout["issued"] = util::time_to_w3c(now);
+ pout["expiry"] = util::time_to_w3c(now+assoc->expires_in());
+ pout["expires_in"] = util::long_to_string(assoc->expires_in());
+ secret_t secret = assoc->secret();
+ switch(st) {
+ case sess_dh_sha1:
+ pout["session_type"] = "DH-SHA1";
+ pout["dh_server_public"] = util::bignum_to_base64(dh->pub_key);
+ secret.enxor_to_base64(key_sha1,pout["enc_mac_key"]);
+ break;
+ default:
+ secret.to_base64(pout["mac_key"]);
+ break;
+ }
+ }
+
+ void server_t::checkid_immediate(const params_t& pin,string& return_to,params_t& pout) {
+ checkid_(mode_checkid_immediate,pin,return_to,pout);
+ }
+
+ void server_t::checkid_setup(const params_t& pin,string& return_to,params_t& pout) {
+ checkid_(mode_checkid_setup,pin,return_to,pout);
+ }
+
+ void server_t::checkid_(mode_t mode,const params_t& pin,string& return_to,params_t& pout) {
+ if(mode!=mode_checkid_immediate && mode!=mode_checkid_setup)
+ throw bad_input(OPKELE_CP_ "invalid checkid_* mode");
+ assoc_t assoc;
+ try {
+ assoc = retrieve_assoc(pin.get_param("openid.assoc_handle"));
+ }catch(failed_lookup& fl) {
+ // no handle specified or no valid handle found, going dumb
+ assoc = alloc_assoc(mode_checkid_setup);
+ }
+ string trust_root;
+ try {
+ trust_root = pin.get_param("openid.trust_root");
+ }catch(failed_lookup& fl) { }
+ string identity = pin.get_param("openid.identity");
+ return_to = pin.get_param("openid.return_to");
+ validate(*assoc,pin,identity,trust_root);
+ pout.clear();
+ pout["mode"] = "id_res";
+ pout["assoc_handle"] = assoc->handle();
+ if(pin.has_param("openid.assoc_handle") && assoc->stateless())
+ pout["invalidate_handle"] = pin.get_param("openid.assoc_handle");
+ pout["identity"] = identity;
+ pout["return_to"] = return_to;
+ /* TODO: eventually remove deprecated stuff */
+ time_t now = time(0);
+ pout["issued"] = util::time_to_w3c(now);
+ pout["valid_to"] = util::time_to_w3c(now+120);
+ pout["exipres_in"] = "120";
+ pout.sign(assoc->secret(),pout["sig"],pout["signed"]="mode,identity,return_to");
+ }
+
+ void server_t::check_authentication(const params_t& pin,params_t& pout) {
+ vector<unsigned char> sig;
+ mimetic::Base64::Decoder b;
+ const string& sigenc = pin.get_param("openid.sig");
+ mimetic::decode(
+ sigenc.begin(),sigenc.end(), b,
+ back_insert_iterator<vector<unsigned char> >(sig));
+ assoc_t assoc;
+ try {
+ assoc = retrieve_assoc(pin.get_param("openid.assoc_handle"));
+ }catch(failed_lookup& fl) {
+ throw failed_assertion(OPKELE_CP_ "invalid handle or handle not specified");
+ }
+ if(!assoc->stateless())
+ throw stateful_handle(OPKELE_CP_ "will not do check_authentication on a stateful handle");
+ const string& slist = pin.get_param("openid.signed");
+ string kv;
+ string::size_type p =0;
+ while(true) {
+ string::size_type co = slist.find(',',p);
+ string f = (co==string::npos)?slist.substr(p):slist.substr(p,co-p);
+ kv += f;
+ kv += ':';
+ if(f=="mode")
+ kv += "id_res";
+ else {
+ f.insert(0,"openid.");
+ kv += pin.get_param(f);
+ }
+ kv += '\n';
+ if(co==string::npos)
+ break;
+ p = co+1;
+ }
+ secret_t secret = assoc->secret();
+ unsigned int md_len = 0;
+ unsigned char *md = HMAC(
+ EVP_sha1(),
+ &(secret.front()),secret.size(),
+ (const unsigned char *)kv.data(),kv.length(),
+ 0,&md_len);
+ pout.clear();
+ if(sig.size()==md_len && !memcmp(&(sig.front()),md,md_len)) {
+ pout["is_valid"]="true";
+ pout["lifetime"]="60"; /* TODO: eventually remove deprecated stuff */
+ }else{
+ pout["is_valid"]="false";
+ pout["lifetime"]="0"; /* TODO: eventually remove deprecated stuff */
+ }
+ if(pin.has_param("openid.invalidate_handle")) {
+ string h = pin.get_param("openid.invalidate_handle");
+ try {
+ assoc_t assoc = retrieve_assoc(h);
+ }catch(invalid_handle& ih) {
+ pout["invalidate_handle"] = h;
+ }catch(failed_lookup& fl) { }
+ }
+ }
+
+}
diff --git a/lib/util.cc b/lib/util.cc
new file mode 100644
index 0000000..1e7335c
--- a/dev/null
+++ b/lib/util.cc
@@ -0,0 +1,138 @@
+#include <errno.h>
+#include <cassert>
+#include <vector>
+#include <string>
+#include <mimetic/mimetic.h>
+#include <curl/curl.h>
+#include "opkele/util.h"
+#include "opkele/exception.h"
+
+namespace opkele {
+ using namespace std;
+
+ namespace util {
+
+ /*
+ * big numerics
+ */
+
+ BIGNUM *base64_to_bignum(const string& b64) {
+ vector<unsigned char> bin;
+ mimetic::Base64::Decoder b;
+ mimetic::decode(
+ b64.begin(),b64.end(), b,
+ back_insert_iterator<vector<unsigned char> >(bin) );
+ BIGNUM *rv = BN_bin2bn(&(bin.front()),bin.size(),0);
+ if(!rv)
+ throw failed_conversion(OPKELE_CP_ "failed to BN_bin2bn()");
+ return rv;
+ }
+
+ BIGNUM *dec_to_bignum(const string& dec) {
+ BIGNUM *rv = 0;
+ if(!BN_dec2bn(&rv,dec.c_str()))
+ throw failed_conversion(OPKELE_CP_ "failed to BN_dec2bn()");
+ return rv;
+ }
+
+ string bignum_to_base64(const BIGNUM *bn) {
+ vector<unsigned char> bin(BN_num_bytes(bn));
+ int l = BN_bn2bin(bn,&(bin.front()));
+ string rv;
+ mimetic::Base64::Encoder b(0);
+ mimetic::encode(
+ bin.begin(),bin.begin()+l, b,
+ back_insert_iterator<string>(rv) );
+ return rv;
+ }
+
+ /*
+ * w3c times
+ */
+
+ string time_to_w3c(time_t t) {
+ struct tm tm_t;
+ if(!gmtime_r(&t,&tm_t))
+ throw failed_conversion(OPKELE_CP_ "failed to BN_dec2bn()");
+ char rv[25];
+ if(!strftime(rv,sizeof(rv)-1,"%Y-%m-%dT%H:%M:%SZ",&tm_t))
+ throw failed_conversion(OPKELE_CP_ "failed to strftime()");
+ return rv;
+ }
+
+ time_t w3c_to_time(const string& w) {
+ struct tm tm_t;
+ memset(&tm_t,0,sizeof(tm_t));
+ if(
+ sscanf(
+ w.c_str(),
+ "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ &tm_t.tm_year,&tm_t.tm_mon,&tm_t.tm_mday,
+ &tm_t.tm_hour,&tm_t.tm_min,&tm_t.tm_sec
+ ) != 6 )
+ throw failed_conversion(OPKELE_CP_ "failed to sscanf()");
+ tm_t.tm_mon--;
+ tm_t.tm_year-=1900;
+ time_t rv = mktime(&tm_t);
+ if(rv==(time_t)-1)
+ throw failed_conversion(OPKELE_CP_ "failed to mktime()");
+ return rv;
+ }
+
+ /*
+ *
+ */
+
+ string canonicalize_url(const string& url) {
+ string rv = url;
+ // strip leading and trailing spaces
+ string::size_type i = rv.find_first_not_of(" \t\r\n");
+ if(i==string::npos)
+ throw bad_input(OPKELE_CP_ "empty URL");
+ if(i)
+ rv.erase(0,i);
+ i = rv.find_last_not_of(" \t\r\n");
+ assert(i!=string::npos);
+ if(i<(rv.length()-1))
+ rv.erase(i+1);
+ // add missing http://
+ i = rv.find("://");
+ if(i==string::npos) { // primitive. but do we need more?
+ rv.insert(0,"http://");
+ i = sizeof("http://")-1;
+ }else{
+ i += sizeof("://")-1;
+ }
+ if(rv.find('/',i)==string::npos)
+ rv += '/';
+ return rv;
+ }
+
+ string url_encode(const string& str) {
+ char * t = curl_escape(str.c_str(),str.length());
+ if(!t)
+ throw failed_conversion(OPKELE_CP_ "failed to curl_escape()");
+ string rv(t);
+ curl_free(t);
+ return rv;
+ }
+
+ string long_to_string(long l) {
+ char rv[32];
+ int r=snprintf(rv,sizeof(rv),"%ld",l);
+ if(r<0 || r>=sizeof(rv))
+ throw failed_conversion(OPKELE_CP_ "failed to snprintf()");
+ return rv;
+ }
+
+ long string_to_long(const string& s) {
+ char *endptr = 0;
+ long rv = strtol(s.c_str(),&endptr,10);
+ if((!endptr) || endptr==s.c_str())
+ throw failed_conversion(OPKELE_CP_ "failed to strtol()");
+ return rv;
+ }
+
+ }
+
+}
diff --git a/libopkele.pc.in b/libopkele.pc.in
new file mode 100644
index 0000000..60bca34
--- a/dev/null
+++ b/libopkele.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libopkele
+Description: C++ implementation of OpenID protocol
+Version: @VERSION@
+Requires: openssl @KONFORKA_KONFORKA@
+Cflags: -I${includedir} @LIBCURL_CPPFLAGS@ @PCREPP_CFLAGS@
+Libs: -L${libdir} -lopkele @LIBCURL@ @PCREPP_LIBS@ @MIMETIC_LIBS@