libopkele-2.0.4+git20140305.9651b55/000077500000000000000000000000001273462535700160165ustar00rootroot00000000000000libopkele-2.0.4+git20140305.9651b55/.gitignore000066400000000000000000000002721273462535700200070ustar00rootroot00000000000000/configure Makefile.in /Doxyfile /config.log /config.h /INSTALL /NEWS Makefile /config.status /stamp-h1 /config.h.in /autom4te.cache /libopkele.pc /aclocal.m4 /aclocal.d /aux.d /libtool libopkele-2.0.4+git20140305.9651b55/AUTHORS000066400000000000000000000005601273462535700170670ustar00rootroot00000000000000Klever dissected: Michael 'hacker' Krelin Leonid Ivanov Thanks to: Brian Muller of mod_auth_openid project for suggestions, bug reports, testing and actually making use of the library. Joseph Smarr of plaxo.com for robustness enhancements and making use of my work. libopkele-2.0.4+git20140305.9651b55/COPYING000066400000000000000000000020771273462535700170570ustar00rootroot00000000000000Copyright (c) 2005-2009 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. libopkele-2.0.4+git20140305.9651b55/ChangeLog000066400000000000000000000000001273462535700175560ustar00rootroot00000000000000libopkele-2.0.4+git20140305.9651b55/Doxyfile.in000066400000000000000000001457001273462535700201400ustar00rootroot00000000000000# Doxyfile 1.5.2 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file that # follow. The default is UTF-8 which is also the encoding used for all text before # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = @PACKAGE@ # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @VERSION@ # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = @builddir@/doxydox # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = include # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = include # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = YES # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = NO # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @srcdir@/include/opkele/ \ @srcdir@/lib/ # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default # input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = *.h \ *.cc # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the output. # The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 2 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = YES #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = YES # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to # produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to # specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = @HAVE_DOT@ # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = @DOT@ # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen will always # show the root nodes and its direct children regardless of this setting. DOT_GRAPH_MAX_NODES = 50 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO libopkele-2.0.4+git20140305.9651b55/Makefile.am000066400000000000000000000010351273462535700200510ustar00rootroot00000000000000SUBDIRS=include lib test EXTRA_DIST= NEWS NEWS.xml NEWS.xsl ACLOCAL_AMFLAGS=-I aclocal.d pkgconfigdir=${libdir}/pkgconfig pkgconfig_DATA=libopkele.pc 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 ISSUEFILES = $$(find ${top_srcdir} -type f '(' \ -name '*.cc' -or -name '*.h' \ ')' ) \ ${top_srcdir}/configure.ac issues: todo fixme xxx todo fixme xxx: @grep --color=auto -in '$@:' ${ISSUEFILES} || true libopkele-2.0.4+git20140305.9651b55/NEWS.xml000066400000000000000000000070121273462535700173140ustar00rootroot00000000000000 added attribute exchange and oauth openid extensions contributed by Joseph Smarr of Plaxo removed legacy compatibility code and dependency on pcre minor build fixes and improvements Fixed an URI normalization bug misnormalizing URIs with a single-character trailing component build improvements Handling of unknown encodings during discovery Discovery robustness improvements Workaround for OPs (e.g. livejournal.com) breaking specs Build fixes and improvements Compile-time fixes and improvements Portability improvements for FreeBSD Really suppress debugging message from htmltidy when --disable-debug is in effect minor bugfixes thread-safety improvements OpenID 2.0 support Major rewrite of the whole thing Support for XRDS (YADIS and XRI/inames) discovery Sheerly improved html-based discovery (only code using new, 2.0-enabled classes benefits from it) Deprecation of the old api Added sample RP and OP implementations Require expat xml stream parser library Require htmltidy library Require tr1/memory (shared_ptr) support - either modern gcc or boost library code cleanup for stricter compiler more robustness improvements in links discovery removed dependency on pcre c++ bindings, because there are few of them and not everyone likes all of them minor build improvements fixed canonicalization procedure to be specs-compliant. Note, that the old consumer_t::canonicalize is now called consumer_t::normalize and the canonicalize memeber is now virtual to allow caching layer, not static robustness improvement in handling associations expiry minor documentation updates open id server invalid signature bugfix A few robustness improvements and optimizations More liberal key/values messages parsing Changed unusable --with-pcre++ configure option to --with-pcrepp Fixed a bug in curl errors handling added --disable-ssl-verify-host and --disable-ssl-verify-peer options to configure to alter default implementation of consumer's retrieve_links behaviour Build fix that eliminates the need to pass --disable-konforka in the absence of it. OpenID simple registration extension implementation OpenID extensions framework Canonicalization bugfix Slightly improved interoperability with buggy implementations Initial release libopkele-2.0.4+git20140305.9651b55/NEWS.xsl000066400000000000000000000011371273462535700173240ustar00rootroot00000000000000 - libopkele-2.0.4+git20140305.9651b55/README000066400000000000000000000000001273462535700166640ustar00rootroot00000000000000libopkele-2.0.4+git20140305.9651b55/acinclude.d/000077500000000000000000000000001273462535700201675ustar00rootroot00000000000000libopkele-2.0.4+git20140305.9651b55/acinclude.d/libcurl.m4000066400000000000000000000217561273462535700221000ustar00rootroot00000000000000# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION], # [ACTION-IF-YES], [ACTION-IF-NO]) # ---------------------------------------------------------- # David Shaw May-09-2006 # # 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 guess what protocols are available, # or use curl_version_info to figure it out at runtime. 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_FEATURE_IDN],[Defined if libcurl supports IDN]) AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI]) AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM]) 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_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]) AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP]) 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 LIBCURL_CPPFLAGS="-I$withval/include" _libcurl_ldflags="-L$withval/lib" AC_PATH_PROG([_libcurl_config],[curl-config],["$withval/bin"], ["$withval/bin"]) else AC_PATH_PROG([_libcurl_config],[curl-config]) fi 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` # This is so silly, but Apple actually has a bug in their # curl-config script. Fixed in Tiger, but there are still # lots of Panther installs around. case "${host}" in powerpc-apple-darwin7*) LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'` ;; esac 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-"$_libcurl_ldflags -lcurl"} AC_CACHE_CHECK([whether libcurl is usable], [libcurl_cv_lib_curl_usable], [ _libcurl_save_cppflags=$CPPFLAGS CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" _libcurl_save_libs=$LIBS LIBS="$LIBCURL $LIBS" AC_LINK_IFELSE(AC_LANG_PROGRAM([#include ],[ /* 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 LIBS=$_libcurl_save_libs unset _libcurl_save_cppflags unset _libcurl_save_libs ]) if test $libcurl_cv_lib_curl_usable = yes ; then # Does curl_free() exist in this version of libcurl? # If not, fake it with free() _libcurl_save_cppflags=$CPPFLAGS CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" _libcurl_save_libs=$LIBS LIBS="$LIBS $LIBCURL" AC_CHECK_FUNC(curl_free,, AC_DEFINE(curl_free,free, [Define curl_free() as free() if our version of curl lacks curl_free.])) CPPFLAGS=$_libcurl_save_cppflags LIBS=$_libcurl_save_libs unset _libcurl_save_cppflags unset _libcurl_save_libs 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 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 else unset LIBCURL unset LIBCURL_CPPFLAGS 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 unset _libcurl_ldflags 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 libopkele-2.0.4+git20140305.9651b55/acinclude.m4000066400000000000000000000121421273462535700202070ustar00rootroot00000000000000dnl 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 AC_DEFINE: HAVE_PCRE PCRE_VERSION dnl env: HAVE_PCRE=yes|no 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 ]) 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 AC_DEFINE: HAVE_PCREPP PCREPP_VERSION dnl env: HAVE_PCREPP=yes|no 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([pcrepp], AC_HELP_STRING([--with-pcrepp=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 ]) dnl AC_CHECK_SHAREDPTR(NS,HEADER[,ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]]) AC_DEFUN([AC_CHECK_SHAREDPTR],[ AC_LANG_PUSH([C++]) AC_MSG_CHECKING([for $1::shared_ptr<> in $2]) AC_COMPILE_IFELSE([ #include <$2> int main(int c,char**v) { $1::shared_ptr spi(new int(0)); return *spi; } ],[ AC_MSG_RESULT([found]) $3 ],[ AC_MSG_RESULT([not found]) $4 ]) AC_LANG_POP([C++]) ]) m4_include([acinclude.d/libcurl.m4]) libopkele-2.0.4+git20140305.9651b55/autogen.bash000077500000000000000000000005661273462535700203310ustar00rootroot00000000000000#!/bin/bash tool_libtoolize="$(type -P glibtoolize || type -P libtoolize)" if test -z "$tool_libtoolize" ; then echo "Failed to find libtoolize." ; exit 1; fi (test -d aux.d || mkdir aux.d) \ && (test -d aclocal.d || mkdir aclocal.d) \ && "$tool_libtoolize" -f \ && aclocal -I aclocal.d \ && autoheader \ && automake -a \ && (autoconf || autoconf) \ && ./configure "$@" libopkele-2.0.4+git20140305.9651b55/autoregen.bash000066400000000000000000000002021273462535700206400ustar00rootroot00000000000000#!/bin/bash eval bash autogen.bash $(./config.status --version | grep '^ with options "'|sed -e 's/^[^"]\+"//' -e 's/"$//') "$@" libopkele-2.0.4+git20140305.9651b55/configure.ac000066400000000000000000000172771273462535700203220ustar00rootroot00000000000000AC_INIT([libopkele], [2.0.4], [libopkele-bugs@klever.net]) AC_CONFIG_SRCDIR([include/opkele/opkele-config.h]) AC_CONFIG_HEADERS([config.h include/opkele/acconfig.h]) AC_CONFIG_MACRO_DIR([aclocal.d]) AC_CONFIG_AUX_DIR([aux.d]) AM_INIT_AUTOMAKE([dist-bzip2]) AC_PROG_INSTALL AC_PROG_CXX AC_PROG_CC AC_PROG_LIBTOOL PKG_PROG_PKG_CONFIG AC_HEADER_STDC AC_CHECK_FUNCS([timegm]) AC_CHECK_HEADERS([ext/algorithm.h]) AC_PATH_PROG([XSLTPROC],[xsltproc],[true]) AC_MSG_CHECKING([for source tree version]) if headrev=$(cd $srcdir && git rev-parse --verify HEAD 2>/dev/null) ; then PACKAGE_SRC_VERSION="$(cd $srcdir && git describe --tags $headrev)" test "$PACKAGE_SRC_VERSION" = "$PACKAGE_VERSION" \ -o "${PACKAGE_SRC_VERSION#${PACKAGE_VERSION}-}" != "$PACKAGE_SRC_VERSION" || PACKAGE_SRC_VERSION="${PACKAGE_VERSION}:${PACKAGE_SRC_VERSION}" ( cd $srcdir && git diff-index $headrev | read dirt ) && PACKAGE_SRC_VERSION="${PACKAGE_SRC_VERSION}-dirty" else PACKAGE_SRC_VERSION="$PACKAGE_VERSION" fi AC_MSG_RESULT([$PACKAGE_SRC_VERSION]) AC_SUBST([PACKAGE_SRC_VERSION]) AC_DEFINE_UNQUOTED([PACKAGE_SRC_VERSION],["$PACKAGE_SRC_VERSION"],[more or less precise source tree version]) tr1_mem_std="false" tr1_mem_boost="false" AC_CHECK_SHAREDPTR(std::tr1,tr1/memory,[ tr1_mem_std=true ]) AC_CHECK_SHAREDPTR(boost,boost/shared_ptr.hpp,[ tr1_mem_boost=true ]) tr1_mem="" AC_ARG_WITH([tr1-memory], AC_HELP_STRING([--with-tr1-memory=],[select tr1/memory (shared_ptr<>) implementation to use]), [ tr1_mem="$withval" ] ) AC_MSG_CHECKING([for tr1/memory implementation to use]) test -z "$tr1_mem" && $tr1_mem_std && tr1_mem=std test -z "$tr1_mem" && $tr1_mem_boost && tr1_mem=boost if test -z "$tr1_mem" ; then AC_MSG_RESULT([none found]) else AC_MSG_RESULT([$tr1_mem]) fi case "$tr1_mem" in std) $tr1_mem_std || AC_MSG_ERROR([std implementation requested, but not found]) OPKELE_TR1_MEM_NS=std::tr1 OPKELE_TR1_MEM_HEADER=tr1/memory ;; boost) $tr1_mem_boost || AC_MSG_ERROR([boost implementation requested, but not found]) OPKELE_TR1_MEM_NS=boost OPKELE_TR1_MEM_HEADER=boost/shared_ptr.hpp ;; *) AC_MSG_ERROR([no shared_ptr<> implementation found]) ;; esac AC_SUBST([OPKELE_TR1_MEM_NS]) AC_SUBST([OPKELE_TR1_MEM_HEADER]) AC_MSG_CHECKING([for deprecated attribute support]) AC_COMPILE_IFELSE([ int __attribute__((deprecated)) deprecated_function(); ],[ AC_MSG_RESULT([yes]) AC_DEFINE([OPKELE_DEPRECATE],[__attribute__((deprecated))],[deprecated function attribute]) ],[ AC_MSG_RESULT([no]) AC_DEFINE([OPKELE_DEPRECATE],,[deprecated function attribute]) ] ) AC_LANG_PUSH([C++]) AC_MSG_CHECKING([for abi::__cxa_demangle]) AC_COMPILE_IFELSE([ #include using namespace std; #include int main(int c,char **v) { int dstat; char *demangled = abi::__cxa_demangle(typeid(dstat).name(),0,0,&dstat); return 0; } ],[ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_DEMANGLE],,[defined if abi::__cxa_demangle is available]) ],[ AC_MSG_RESULT([no]) ] ) AC_LANG_POP([C++]) PKG_CHECK_MODULES([OPENSSL],[openssl],,[ 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_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]) ],[true]) fi 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_CHECK_HEADER([expat.h],[ AC_CHECK_LIB([expat],[XML_ParserCreate],[ EXPAT_LIBS=-lexpat EXPAT_CFLAGS= AC_SUBST([EXPAT_LIBS]) AC_SUBST([EXPAT_CFLAGS]) ],[ AC_MSG_ERROR([no required expat library. get one from http://expat.sourceforge.net/]) ]) ],[ AC_MSG_ERROR([no required expat library. get one from http://expat.sourceforge.net/]) ]) AC_CHECK_HEADERS([tidy.h tidy/tidy.h],[ test -z "$TIDY_LIBS" && AC_CHECK_LIB([tidy],[tidyParseBuffer],[ TIDY_LIBS=-ltidy TIDY_CFLAGS= AC_SUBST([TIDY_LIBS]) AC_SUBST([TIDY_CFLAGS]) ],[ AC_MSG_ERROR([no required htmltidy library found. get one from http://tidy.sourceforge.net/]) ]) ],[ test -z "$TIDY_LIBS" -a "$ac_header" = "tidy/tidy.h" \ && AC_MSG_ERROR([no required htmltidy library found. get one from http://tidy.sourceforge.net/]) ]) PKG_CHECK_MODULES([SQLITE3],[sqlite3],[have_sqlite3=true],[have_sqlite3=false]) AM_CONDITIONAL([HAVE_SQLITE3],[$have_sqlite3]) PKG_CHECK_MODULES([KINGATE],[kingate-plaincgi],[have_kingate=true],[have_kingate=false]) AM_CONDITIONAL([HAVE_KINGATE],[$have_kingate]) PKG_CHECK_MODULES([UUID],[uuid],[have_uuid=true],[have_uuid=false]) AM_CONDITIONAL([HAVE_UUID],[$have_uuid]) if $have_uuid ; then AC_DEFINE([HAVE_LIBUUID],,[defined in presence of libuuid]) AC_SUBST([UUID_UUID],[uuid]) fi curl_ssl_verify_host="true" AC_ARG_ENABLE([ssl-verify-host], AC_HELP_STRING([--disable-ssl-verify-host],[disable cURL cert/host relationships verification]), [ test "${enableval}" = "no" && curl_ssl_verify_host="false" ] ) ${curl_ssl_verify_host} || AC_DEFINE([DISABLE_CURL_SSL_VERIFYHOST],,[defined if cURL is not to verify cert/host]) curl_ssl_verify_peer="true" AC_ARG_ENABLE([ssl-verify-peer], AC_HELP_STRING([--disable-ssl-verify-peer],[disable cURL cert validity verification]), [ test "${enableval}" = "no" && curl_ssl_verify_peer="false" ] ) ${curl_ssl_verify_peer} || AC_DEFINE([DISABLE_CURL_SSL_VERIFYPEER],,[defined if cURL is not to verify cert validity]) postels_law=true AC_ARG_ENABLE([postels-law], AC_HELP_STRING([--disable-postels-law],[Be strict, do not adhere to Postel's Law ("be conservative in what you do, be liberal in what you accept from others", RFC 793)]), [ test "${enableval}" = "no" && postels_law=false ] ) $postels_law && AC_DEFINE([POSTELS_LAW],,[defined if we want to adhere to Postel's Law]) AC_DEFINE_UNQUOTED([OPKELE_SRC_DIR],["$PWD"],[source directory]) nitpick=false AC_ARG_ENABLE([nitpicking], AC_HELP_STRING([--enable-nitpicking],[make compiler somewhat overly fastidious about the code it deals with]), [ test "$enableval" = "no" || nitpick=true ] ) if $nitpick ; then CPP_NITPICK="-pedantic -Wall -Wextra -Wundef -Wshadow \ -Wunsafe-loop-optimizations -Wconversion -Wmissing-format-attribute \ -Wredundant-decls -ansi" # -Wlogical-op -Wmissing-noreturn C_NITPICK="$CPP_NITPICK" CXX_NITPICK="$C_NITPICK" CPPFLAGS="$CPPFLAGS $CPP_NITPICK" CFLAGS="$CFLAGS $C_NITPICK" CXXFLAGS="$CXXFLAGS $CXX_NITPICK" fi ndebug=true AC_ARG_ENABLE([debug], AC_HELP_STRING([--enable-debug],[enable debugging code]), [ test "$enableval" = "no" || ndebug=false ] ) if $ndebug ; then CPPFLAGS_DEBUG="-DNDEBUG" else CPPFLAGS_DEBUG="" fi AC_SUBST([CPPFLAGS_DEBUG]) xri_proxy_url="https://xri.net/" AC_MSG_CHECKING([for XRI resolver proxy]) AC_ARG_ENABLE([xri-proxy], AC_HELP_STRING([--with-xri-proxy=url],[set xri proxy for use when resolving xri identities, default is https://xri.net/]), [ xri_proxy_url="$withval" ] ) AC_MSG_RESULT([$xri_proxy_url]) AC_DEFINE_UNQUOTED([XRI_PROXY_URL],["$xri_proxy_url"],[XRI proxy resolver URL]) AC_CONFIG_FILES([ Makefile libopkele.pc Doxyfile include/Makefile include/opkele/tr1-mem.h lib/Makefile test/Makefile ]) AC_OUTPUT libopkele-2.0.4+git20140305.9651b55/include/000077500000000000000000000000001273462535700174415ustar00rootroot00000000000000libopkele-2.0.4+git20140305.9651b55/include/.gitignore000066400000000000000000000000251273462535700214260ustar00rootroot00000000000000Makefile.in Makefile libopkele-2.0.4+git20140305.9651b55/include/Makefile.am000066400000000000000000000012051273462535700214730ustar00rootroot00000000000000NODIST_HEADERS_ = \ opkele/acconfig.h \ opkele/tr1-mem.h nobase_include_HEADERS = \ opkele/opkele-config.h \ opkele/types.h \ opkele/association.h \ opkele/exception.h \ opkele/extension.h \ opkele/sreg.h \ opkele/extension_chain.h \ opkele/uris.h \ opkele/basic_rp.h opkele/prequeue_rp.h \ opkele/iterator.h \ opkele/basic_op.h opkele/verify_op.h \ opkele/util.h \ opkele/ax.h opkele/oauth_ext.h \ ${NODIST_HEADERS_} noinst_HEADERS = \ opkele/data.h \ opkele/curl.h opkele/expat.h opkele/tidy.h \ opkele/util-internal.h \ opkele/debug.h \ opkele/discovery.h dist-hook: rm -f $(addprefix ${distdir}/,${NODIST_HEADERS_}) libopkele-2.0.4+git20140305.9651b55/include/opkele/000077500000000000000000000000001273462535700207205ustar00rootroot00000000000000libopkele-2.0.4+git20140305.9651b55/include/opkele/.gitignore000066400000000000000000000000361273462535700227070ustar00rootroot00000000000000acconfig.h tr1-mem.h stamp-h2 libopkele-2.0.4+git20140305.9651b55/include/opkele/acconfig.h.in000066400000000000000000000002111273462535700232410ustar00rootroot00000000000000 /* defined in presence of konforka library */ #undef OPKELE_HAVE_KONFORKA /* deprecated function attribute */ #undef OPKELE_DEPRECATE libopkele-2.0.4+git20140305.9651b55/include/opkele/association.h000066400000000000000000000033771273462535700234170ustar00rootroot00000000000000#ifndef __OPKELE_ASSOCIATION_H #define __OPKELE_ASSOCIATION_H #include #include /** * @file * @brief reference implementation of association_t */ 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) { } virtual string server() const { return _server; } virtual string handle() const { return _handle; } virtual string assoc_type() const { return _assoc_type; } virtual secret_t secret() const { return _secret; } virtual int expires_in() const { return _expires-time(0); } virtual bool stateless() const { return _stateless; } virtual bool is_expired() const { return _expires namespace opkele { /** * OpenID attribute exchange extension implementation * http://openid.net/specs/openid-attribute-exchange-1_0.html */ class ax_t : public extension_t { public: /** special "count" value for add_attribute to request fetching "as many values as possible". */ static const int UNLIMITED_COUNT = -1; /** * Optional URL for receiving future attribute updates. * Set it before checkid_setup to send up the URL; read it after id_res to get it back. */ std::string update_url; /** * Consumer constructor. */ ax_t() : alias_count(0) { } /** Adds an attribute to request during checkid_setup. */ void add_attribute(const char *uri, bool required, const char *alias = NULL, int count = 1); /** Returns an attribute fetched for the given type-uri during id_res. */ std::string get_attribute(const char *uri, int index = 0); /** Returns the number of values fetched for the given type-uri during id_res. */ size_t get_attribute_count(const char *uri); virtual void rp_checkid_hook(basic_openid_message& om); virtual void rp_id_res_hook(const basic_openid_message& om, const basic_openid_message& sp); virtual void op_checkid_hook(const basic_openid_message& inm); virtual void op_id_res_hook(basic_openid_message& oum); virtual void checkid_hook(basic_openid_message& om); virtual void id_res_hook(const basic_openid_message& om, const basic_openid_message& sp); virtual void checkid_hook(const basic_openid_message& inm, basic_openid_message& oum); /** * Function called after parsing sreg request to set up response * fields. The default implementation tries to send as much fields * as we have. The function is supposed to set the data and * fields_response. * @see fields_response * @param inm incoming openid message * @param oum outgoing openid message */ virtual void setup_response(const basic_openid_message& inm, basic_openid_message& oum); virtual void setup_response(); protected: /** Stores attributes to request fetching during checkid_setup. */ struct ax_attr_t { std::string uri; std::string alias; bool required; int count; }; std::vector attrs; unsigned int alias_count; // auto-incr counter for auto-named aliases /** Stores results from fetch response during id_res. */ std::map > response_attrs; }; } #endif /* __OPKELE_AX_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/basic_op.h000066400000000000000000000160061273462535700226530ustar00rootroot00000000000000#ifndef __OPKELE_BASIC_OP_H #define __OPKELE_BASIC_OP_H #include #include #include namespace opkele { using std::string; /** * Implementation of basic OP functionality */ class basic_OP { public: /** * The request mode for the request being processed */ mode_t mode; /** * association used in transaction. reset in case of dumb operation */ assoc_t assoc; /** * true if the request is openid2 request */ bool openid2; /** * The return_to RP endpoint */ string return_to; /** * The realm we authenticate for */ string realm; /** * Claimed identifier */ string claimed_id; /** * The OP-Local identifier */ string identity; /** * The invalidate handle for the reply request */ string invalidate_handle; virtual ~basic_OP() { } void reset_vars(); /** * @name Request information access * Setting and retrieval of the information pertaining to the request being processed * @{ */ /** * Check if the RP expects us to get back to them. * @return true if RP supplied return_to URL */ bool has_return_to() const; /** * Find out where the RP is waiting for us. * @return the return_to URL supplied * @throw no_return_to if no return_to is supplied with the request */ const string& get_return_to() const; /** * Find out what realm we are authenticating user for * @return the realm */ const string& get_realm() const; /** * Check if request is about identity * @return true if so */ bool has_identity() const; /** * Get claimed identifier supplied with the request * @return claimed identifier * @throw non_identity if request is not about identity */ const string& get_claimed_id() const; /** * Get the identity (OP-Local identifier) being confirmed * @return identity * @throw non_identity if request is not about identity */ const string& get_identity() const; /** * Is identifier supposed to be selected on our side? * @return true if identity is a special identifier select URI */ bool is_id_select() const; /** * Select the identity for identifier select request * @param cid claimed identifier * @param lid local identifier */ void select_identity(const string& cid,const string& lid); /** * Set claimed identifier (for instance if it's supposed to have * fragment part) * @param cid claimed identifier */ void set_claimed_id(const string& cid); /** * @} */ /** @name OpenID operations * @{ */ /** * Establish association with RP * @param oum reply message * @param inm request message */ basic_openid_message& associate( basic_openid_message& oum, const basic_openid_message& inm); /** * Parse the checkid_* request. The function parses input message, * retrieves the information needed for further processing, * verifies what can be verified at this stage. * @param inm incoming OpenID message * @param ext extension/chain of extensions supported */ void checkid_(const basic_openid_message& inm,extension_t *ext=0); /** * Build and sign a positive assertion message * @param om outpu OpenID message * @param ext extension/chain of extensions supported * @return reference to om */ basic_openid_message& id_res(basic_openid_message& om, extension_t *ext=0); /** * Build a 'cancel' negative assertion * @param om output OpenID message * @return reference to om */ basic_openid_message& cancel(basic_openid_message& om); /** * Build an 'error' reply * @param om output OpenID message * @param error a human-readable message indicating the cause * @param contact contact address for the server administrator (can be empty) * @param reference a reference token (can be empty) * @return reference to om */ basic_openid_message& error(basic_openid_message& om, const string& error,const string& contact, const string& reference ); /** * Build a setup_needed reply to checkid_immediate request * @param oum output OpenID message * @param inm incoming OpenID request being processed * @return reference to oum */ basic_openid_message& setup_needed( basic_openid_message& oum,const basic_openid_message& inm); /** * Process check_authentication request * @param oum output OpenID message * @param inm incoming request * @return reference to oum */ basic_openid_message& check_authentication( basic_openid_message& oum,const basic_openid_message& inm); /** * @} */ /** * Verify return_to url. The default implementation checks whether * return_to URI matches the realm * @throw bad_realm in case of invalid realm * @throw bad_return_to if return_to doesn't match the realm * @see verify_OP::verify_return_to() */ virtual void verify_return_to(); /** * @name Global persistent store API * These functions are related to the associations with RPs storage * and retrieval and nonce management. * @{ */ /** * Allocate association. * @param type association type * @param kl association key length * @param sl true if the association is stateless * @return association object */ virtual assoc_t alloc_assoc(const string& type,size_t kl,bool sl) = 0; /** * Retrieve valid unexpired association * @param handle association handle * @return association object */ virtual assoc_t retrieve_assoc(const string& handle) = 0; /** * Allocate nonce. * @param nonce input-output parameter containing timestamp part of * the nonce on input * @param sl true if the nonce is * @return reference to nonce * @throw failed_lookup if no such valid unexpired association * could be retrieved */ virtual string& alloc_nonce(string& nonce) = 0; /** * Check nonce validity * @param nonce nonce to check * @return true if nonce found and isn't yet invalidated */ virtual bool check_nonce(const string& nonce) = 0; /** * Invalidate nonce * @param nonce nonce to check */ virtual void invalidate_nonce(const string& nonce) = 0; /** * @} */ /** * @name Site particulars API * @{ */ /** * Query the absolute URL of the op endpoint * @return fully qualified url of the OP endpoint */ virtual const string get_op_endpoint() const = 0; /** * @} */ }; } #endif /* __OPKELE_BASIC_OP_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/basic_rp.h000066400000000000000000000163131273462535700226570ustar00rootroot00000000000000#ifndef __OPKELE_BASIC_RP_H #define __OPKELE_BASIC_RP_H #include #include #include namespace opkele { using std::string; class basic_RP { public: /** * Claimed identifier from a parsed id_res message. */ string claimed_id; /** * OP-Local identifier from a parsed id_res message. */ string identity; virtual ~basic_RP() { } void reset_vars(); /** * @name Assertion information retrieval * Retrieval of the information passed with openid message * @{ */ /** * Find out if the assertion is about identity * @return true if so */ bool has_identity() const; /** * Get claimed identifier supplied with the request * @return claimed identifier * @throw non_identity if request is not about identity */ const string& get_claimed_id() const; /** * Get the identity (OP-Local identifier) confirmed * @return identity * @throw non_identity if request is not about identity */ const string& get_identity() const; /** * @} */ /** * @name Global persistent store API * These are functions related to the associations with OP storage * and retrieval and nonce records. They provide an interface to * the persistent storage which is shared by all sessions. If the * implementor prefers the dumb mode instead, the function should * throw dumb_RP exception instead. * @see opkele::dumb_RP * @{ */ /** * Store association and return allocated association object. * @param OP OP endpoint * @param handle association handle * @param type association type * @param secret association secret * @params expires_in the number of seconds association expires in * @return the association object * @throw dumb_RP for dumb RP */ virtual assoc_t store_assoc( const string& OP,const string& handle, const string& type,const secret_t& secret, int expires_in) = 0; /** * Find valid unexpired association with an OP. * @param OP OP endpoint URL * @return association found * @throw failed_lookup if no association found * @throw dumb_RP for dumb RP */ virtual assoc_t find_assoc( const string& OP) = 0; /** * Retrieve valid association handle for an OP by handle. * @param OP OP endpoint URL * @param handle association handle * @return association found * @throw failed_lookup if no association found * @throw dumb_RP for dumb RP */ virtual assoc_t retrieve_assoc( const string& OP,const string& handle) = 0; /** * Invalidate association with OP * @param OP OP endpoint URL * @param handle association handle * @throw dumb_RP for dumb RP */ virtual void invalidate_assoc(const string& OP,const string& handle) = 0; /** * Check the nonce validity. That is, check that we haven't * accepted request with this nonce from this OP, yet. May involve * cutting off by the timestamp and checking the rest against the * store of seen nonces. * @param OP OP endpoint URL * @param nonce nonce value * @throw id_res_bad_nonce if the nonce is not to be accepted, i.e. * either too old or seen. */ virtual void check_nonce(const string& OP,const string& nonce) = 0; /** * @} */ /** * @name Session persistent store API * @{ */ /** * Retrieve OpenID endpoint being currently used for * authentication. If there is no endpoint available, throw a * no_endpoint exception. * @return reference to the service endpoint object * @see next_endpoint * @throw no_endpoint if no endpoint available */ virtual const openid_endpoint_t& get_endpoint() const = 0; /** * Advance to the next endpoint to try. * @see get_endpoint() * @throw no_endpoint if there are no more endpoints */ virtual void next_endpoint() = 0; /** * @} */ /** * @name Site particulars API * @{ */ /** * Return an absolute URL of the page being processed, includining * query parameters. It is used to validate return_to URL on * positive assertions. * @return fully qualified url of the page being processed. */ virtual const string get_this_url() const = 0; /** * @} */ /** * @name OpenID actions * @{ */ /** * Initiates authentication session, doing discovery, normalization * and whatever implementor wants to do at this point. * @param usi User-supplied identity */ virtual void initiate(const string& usi) = 0; /** * Prepare checkid_request. * @param rv reference to the openid message to prepare * @param mode checkid_setup or checkid_immediate * @param return_to the URL OP should redirect to after completion * @param realm authentication realm to pass to OP * @param ext pointer to extension to use in request preparation * @return reference to the openid message */ basic_openid_message& checkid_( basic_openid_message& rv, mode_t mode, const string& return_to,const string& realm, extension_t *ext=0); /** * Verify assertion at the end of round-trip. * @param om incoming openid message * @param ext pointer to extention to use in parsing assertion * @throw id_res_setup if checkid_immediate request could not be * completed * @throw id_res_cancel if authentication request was canceled * @throw id_res_mismatch in case of signature mismatch * @throw id_res_bad_return_to if return_to url seems to be * tampered with * @throw id_res_unauthorized if OP is not authorized to make * assertions regarding the identity */ void id_res(const basic_openid_message& om,extension_t *ext=0); /** * Establish association with OP * @param OP OP to establish association with * @throw dumb_RP if for a dumb RP */ virtual assoc_t associate(const string& OP); /** * Check authentication with OP and invalidate handle if requested * and confirmed * @param OP OP to check with * @param om message to check * @throw failed_check_authentication if OP fails to confirm * authenticity of the assertion */ void check_authentication(const string& OP,const basic_openid_message& om); /** * @} */ /** * @name Miscellanea * @{ */ /** * Verify OP authority. Return normally if OP is authorized to make * an assertion, throw an exception otherwise. * @param OP OP endpoint * @param claimed_id claimed identity * @param identity OP-Local identifier * @throw id_res_unauthorized if OP is not authorized to make * assertion regarding this identity. */ virtual void verify_OP(const string& OP, const string& claimed_id,const string& identity) const = 0; /** * @} */ }; } #endif /* __OPKELE_BASIC_RP_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/curl.h000066400000000000000000000043301273462535700220360ustar00rootroot00000000000000#ifndef __OPKELE_CURL_H #define __OPKELE_CURL_H #include #include #include #include namespace opkele { using std::min; using std::string; namespace util { class curl_slist_t { public: curl_slist *_s; curl_slist_t() : _s(0) { } curl_slist_t(curl_slist *s) : _s(s) { } virtual ~curl_slist_t() throw(); curl_slist_t& operator=(curl_slist *s); operator const curl_slist*(void) const { return _s; } operator curl_slist*(void) { return _s; } void append(const char *str); void append(const string& str) { append(str.c_str()); } }; class curl_t { public: CURL *_c; curl_t() : _c(0) { } curl_t(CURL *c) : _c(c) { } virtual ~curl_t() throw(); curl_t& operator=(CURL *c); operator const CURL*(void) const { return _c; } operator CURL*(void) { return _c; } CURLcode misc_sets(); template inline CURLcode easy_setopt(CURLoption o,PT p) { assert(_c); return curl_easy_setopt(_c,o,p); } inline CURLcode easy_setopt(CURLoption o,const curl_slist_t& p) { assert(_c); return curl_easy_setopt(_c,o,(const curl_slist*)p); } CURLcode easy_perform() { assert(_c); return curl_easy_perform(_c); } template inline CURLcode easy_getinfo(CURLINFO i,IT p) { assert(_c); return curl_easy_getinfo(_c,i,p); } static inline CURL *easy_init() { return curl_easy_init(); } virtual size_t write(void* /* p */,size_t /* s */,size_t /* nm */) { return 0; } CURLcode set_write(); virtual int progress(double /* dlt */,double /* dln*/ ,double /* ult */,double /* uln */) { return 0; } CURLcode set_progress(); virtual size_t header(void* /* p */,size_t s,size_t nm) { return s*nm; } CURLcode set_header(); }; template class curl_fetch_string_t : public curl_t { public: curl_fetch_string_t(CURL *c) : curl_t(c) { } ~curl_fetch_string_t() throw() { } string response; size_t write(void *p,size_t size,size_t nmemb) { size_t bytes = size*nmemb; size_t get = min(lim-response.length(),bytes); response.append((const char *)p,get); return get; } }; typedef curl_fetch_string_t<16384> curl_pick_t; } } #endif /* __OPKELE_CURL_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/data.h000066400000000000000000000005641273462535700220070ustar00rootroot00000000000000#ifndef __OPKELE_DATA_H #define __OPKELE_DATA_H /** * @brief the main opkele namespace */ namespace opkele { /** * @brief internal data opkele namespace */ namespace data { extern const char *_default_p; extern const char *_default_g; extern const char *_iname_leaders; extern const char *_whitespace_chars; } } #endif /* __OPKELE_DATA_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/debug.h000066400000000000000000000004211273462535700221540ustar00rootroot00000000000000#ifndef __OPKELE_DEBUG_H #define __OPKELE_DEBUG_H #ifdef NDEBUG #define D_(x) ((void)0) #define DOUT_(x) ((void)0) #else /* NDEBUG */ #define D_(x) x #include #define DOUT_(x) std::clog << x << std::endl #endif /* NDEBUG */ #endif /* __OPKELE_DEBUG_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/discovery.h000066400000000000000000000045211273462535700231020ustar00rootroot00000000000000#ifndef __OPKELE_DISCOVERY_H #define __OPKELE_DISCOVERY_H #include #include namespace opkele { using std::string; namespace xrd { struct priority_compare { inline bool operator()(long a,long b) const { return (a<0) ? false : (b<0) ? true : (a class priority_map : public multimap { typedef multimap map_type; public: inline _DT& add(long priority,const _DT& d) { return this->insert(typename map_type::value_type(priority,d))->second; } bool has_value(const _DT& d) const { for(typename map_type::const_iterator i=this->begin();i!=this->end();++i) if(i->second==d) return true; return false; } }; typedef priority_map canonical_ids_t; typedef priority_map local_ids_t; typedef set types_t; struct uri_t { string uri; string append; uri_t() { } uri_t(const string& u) : uri(u) { } uri_t(const string& u,const string& a) : uri(u), append(a) { } }; typedef priority_map uris_t; class service_t { public: types_t types; uris_t uris; local_ids_t local_ids; string provider_id; void clear() { types.clear(); uris.clear(); local_ids.clear(); provider_id.clear(); } }; typedef priority_map services_t; class XRD_t { public: time_t expires; canonical_ids_t canonical_ids; local_ids_t local_ids; services_t services; string provider_id; void clear() { expires = 0; canonical_ids.clear(); local_ids.clear(); services.clear(); provider_id.clear(); } bool empty() const { return canonical_ids.empty() && local_ids.empty() && services.empty(); } }; } typedef openid_endpoint_output_iterator endpoint_discovery_iterator; string idiscover( endpoint_discovery_iterator oi, const string& identity); void yadiscover( endpoint_discovery_iterator oi, const string& yurl, const char **types, bool redirs=false); struct idiscovery_t { bool xri_identity; string normalized_id; string canonicalized_id; xrd::XRD_t xrd; idiscovery_t() { } void clear() { normalized_id.clear(); canonicalized_id.clear(); xrd.clear(); } }; } #endif /* __OPKELE_DISCOVERY_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/exception.h000066400000000000000000000213231273462535700230700ustar00rootroot00000000000000#ifndef __OPKELE_EXCEPTION_H #define __OPKELE_EXCEPTION_H /** * @file * @brief opkele exceptions */ #include #include #ifdef OPKELE_HAVE_KONFORKA # include /** * 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, /** * open function-try-block */ # define OPKELE_FUNC_TRY try /** * the simple rethrow of konforka-based exception */ # define OPKELE_RETHROW catch(konforka::exception& e) { e.see(CODEPOINT); throw; } #else /* OPKELE_HAVE_KONFORKA */ # include # include /** * 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 opening function-try-block */ # define OPKELE_FUNC_TRY /** * 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 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); # else /* OPKELE_HAVE_KONFORKA */ string _what; explicit exception(const string& w); virtual ~exception() throw(); virtual const char * what() const throw(); # 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) { } }; /** * thrown if the association has expired before it could've been verified. */ class id_res_expired_on_delivery : public id_res_failed { public: id_res_expired_on_delivery(OPKELE_E_PARS) : id_res_failed(OPKELE_E_CONS) { } }; /** * thown when the user cancelled authentication process. */ class id_res_cancel : public id_res_failed { public: id_res_cancel(OPKELE_E_PARS) : id_res_failed(OPKELE_E_CONS) { } }; /** * thrown in case of nonce reuse or otherwise imperfect nonce. */ class id_res_bad_nonce : public id_res_failed { public: id_res_bad_nonce(OPKELE_E_PARS) : id_res_failed(OPKELE_E_CONS) { } }; /** * thrown if return_to didn't pass verification */ class id_res_bad_return_to : public id_res_failed { public: id_res_bad_return_to(OPKELE_E_PARS) : id_res_failed(OPKELE_E_CONS) { } }; /** * thrown if OP isn't authorized to make an assertion */ class id_res_unauthorized : public id_res_failed { public: id_res_unauthorized(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() { } }; /** * htmltidy related error occured */ class exception_tidy : public exception { public: int _rc; exception_tidy(OPKELE_E_PARS); exception_tidy(OPKELE_E_PARS,int r); ~exception_tidy() throw() { } }; /** * exception thrown in case of failed discovery */ class failed_discovery : public exception { public: failed_discovery(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * unsuccessfull xri resolution */ class failed_xri_resolution : public failed_discovery { public: long _code; failed_xri_resolution(OPKELE_E_PARS,long _c=-1) : failed_discovery(OPKELE_E_CONS), _code(_c) { } }; /** * not implemented (think pure virtual) member function executed, signfies * programmer error */ class not_implemented : public exception { public: not_implemented(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * internal error, indicates internal libopkele problem */ class internal_error : public exception { public: internal_error(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown in case of unsupported parameter encountered (e.g. unsupported * association type). */ class unsupported : public exception { public: unsupported(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown by associations store related functions in case of dumb RP. */ class dumb_RP : public exception { public: dumb_RP(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown by endpoint-queue related function if endpoint is being * accessed but there's no endpoint available. */ class no_endpoint : public exception { public: no_endpoint(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown while processing OpenID request in OP. Signifies invalid realm */ class bad_realm : public exception { public: bad_realm(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown when attempting to retrieve return_to of one-way request */ class no_return_to : public exception { public: no_return_to(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown when querying identity of non-identity related request */ class non_identity : public exception { public: non_identity(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; /** * thrown if return_to URL doesn't match realm */ class bad_return_to : public exception { public: bad_return_to(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; } #endif /* __OPKELE_EXCEPTION_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/expat.h000066400000000000000000000055041273462535700222160ustar00rootroot00000000000000#ifndef __OPKELE_EXPAT_H #define __OPKELE_EXPAT_H #include #include namespace opkele { namespace util { class expat_t { public: XML_Parser _x; expat_t() : _x(0) { } expat_t(XML_Parser x) : _x(x) { } virtual ~expat_t() throw(); expat_t& operator=(XML_Parser x); operator XML_Parser(void) const { return _x; } operator XML_Parser(void) { return _x; } inline bool parse(const char *s,int len,bool final=false) { assert(_x); return XML_Parse(_x,s,len,final); } virtual int unknown_encoding(const XML_Char * /* n */,XML_Encoding * /* i */) { return XML_STATUS_ERROR; } void set_unknown_encoding_handler(); virtual void start_element(const XML_Char * /* n */,const XML_Char ** /* a */) { } virtual void end_element(const XML_Char * /* n */) { } void set_element_handler(); virtual void character_data(const XML_Char * /* s */,int /* l */) { } void set_character_data_handler(); virtual void processing_instruction(const XML_Char * /* t */,const XML_Char * /* d */) { } void set_processing_instruction_handler(); virtual void comment(const XML_Char * /* d */) { } void set_comment_handler(); virtual void start_cdata_section() { } virtual void end_cdata_section() { } void set_cdata_section_handler(); virtual void default_handler(const XML_Char * /* s */,int /* l */) { } void set_default_handler(); void set_default_handler_expand(); virtual void start_namespace_decl(const XML_Char * /* p */,const XML_Char * /* u */) { } virtual void end_namespace_decl(const XML_Char * /* p */) { } void set_namespace_decl_handler(); inline enum XML_Error get_error_code() { assert(_x); return XML_GetErrorCode(_x); } static inline const XML_LChar *error_string(XML_Error c) { return XML_ErrorString(c); } inline long get_current_byte_index() { assert(_x); return XML_GetCurrentByteIndex(_x); } inline int get_current_line_number() { assert(_x); return XML_GetCurrentLineNumber(_x); } inline int get_current_column_number() { assert(_x); return XML_GetCurrentColumnNumber(_x); } inline void set_user_data() { assert(_x); XML_SetUserData(_x,this); } inline bool set_base(const XML_Char *b) { assert(_x); return XML_SetBase(_x,b); } inline const XML_Char *get_base() { assert(_x); return XML_GetBase(_x); } inline int get_specified_attribute_count() { assert(_x); return XML_GetSpecifiedAttributeCount(_x); } inline bool set_param_entity_parsing(enum XML_ParamEntityParsing c) { assert(_x); return XML_SetParamEntityParsing(_x,c); } inline static XML_Parser parser_create(const XML_Char *e=0) { return XML_ParserCreate(e); } inline static XML_Parser parser_create_ns(const XML_Char *e=0,XML_Char s='\t') { return XML_ParserCreateNS(e,s); } }; } } #endif /* __OPKELE_EXPAT_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/extension.h000066400000000000000000000034201273462535700231040ustar00rootroot00000000000000#ifndef __OPKELE_EXTENSION_H #define __OPKELE_EXTENSION_H /** * @file * @brief extensions framework basics */ #include #include namespace opkele { /** * OpenID extension hooks base class */ class extension_t { public: virtual ~extension_t() { } /** * hook called by RP before submitting the message to OP. * @param om openid message to be submit */ virtual void rp_checkid_hook(basic_openid_message& om); /** * hook called by RP after verifying information received from OP. * @param om openid message received * @param sp signed part of the message */ virtual void rp_id_res_hook(const basic_openid_message& om, const basic_openid_message& sp); /** * hook called by OP after parsing incoming message * @param inm message received from RP */ virtual void op_checkid_hook(const basic_openid_message& inm); /** * hook called by OP before signing the reply to RP * @param oum message to be sent to RP */ virtual void op_id_res_hook(basic_openid_message& oum); /** * @name deprecated hooks, used by the deprecated consumer_t and * server_t implementations * @{ */ virtual void checkid_hook(basic_openid_message& om) OPKELE_DEPRECATE; virtual void id_res_hook(const basic_openid_message& om, const basic_openid_message& sp) OPKELE_DEPRECATE; virtual void checkid_hook(const basic_openid_message& inm,basic_openid_message& oum); /** * @} */ /** * Casts the object to pointer to itself. For convenient passing * of pointer. */ operator extension_t*(void) { return this; } }; } #endif /* __OPKELE_EXTENSION_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/extension_chain.h000066400000000000000000000023551273462535700242540ustar00rootroot00000000000000#ifndef __OPKELE_EXTENSION_CHAIN_H #define __OPKELE_EXTENSION_CHAIN_H /** * @file * @brief extension chain extension */ #include #include namespace opkele { using std::list; /** * OpenID extensions chain used to combine extensions, it is actually an * stl list of pointers to extensions. */ class extension_chain_t : public extension_t, public list { public: /** * Default constructor creates an empty chain */ extension_chain_t() { } /** * Create extension chain with a single extension in it */ extension_chain_t(extension_t *e) { push_back(e); } virtual void rp_checkid_hook(basic_openid_message& om); virtual void rp_id_res_hook(const basic_openid_message& om, const basic_openid_message& sp); virtual void op_checkid_hook(const basic_openid_message& inm); virtual void op_id_res_hook(basic_openid_message& oum); virtual void checkid_hook(basic_openid_message& om); virtual void id_res_hook(const basic_openid_message& om,const basic_openid_message& sp); virtual void checkid_hook(const basic_openid_message& inm,basic_openid_message& oum); }; } #endif /* __OPKELE_EXTENSION_CHAIN_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/iterator.h000066400000000000000000000156011273462535700227250ustar00rootroot00000000000000#ifndef __OPKELE_ITERATOR_H #define __OPKELE_ITERATOR_H #include #include namespace opkele { namespace util { using std::iterator; using std::forward_iterator_tag; using std::output_iterator_tag; template class basic_output_iterator_proxy_impl : public iterator { public: virtual ~basic_output_iterator_proxy_impl() { } virtual basic_output_iterator_proxy_impl* dup() const = 0; basic_output_iterator_proxy_impl& operator*() { return *this; }; virtual basic_output_iterator_proxy_impl& operator=(const T& x) = 0; }; template class output_iterator_proxy_impl : public basic_output_iterator_proxy_impl { public: IT i; output_iterator_proxy_impl(const IT& _i) : i(_i) { } basic_output_iterator_proxy_impl* dup() const { return new output_iterator_proxy_impl(i); } basic_output_iterator_proxy_impl& operator=(const T& x) { (*i) = x; return *this; } }; template class output_iterator_proxy : public iterator { public: basic_output_iterator_proxy_impl *I; template output_iterator_proxy(const IT& i) : I(new output_iterator_proxy_impl(i)) { } output_iterator_proxy(const output_iterator_proxy& x) : I(x.I->dup()) { } ~output_iterator_proxy() { delete I; } output_iterator_proxy& operator=(const output_iterator_proxy& x) { delete I; I = x.I->dup(); } output_iterator_proxy& operator*() { return *this; } output_iterator_proxy& operator=(const T& x) { (**I) = x; return *this; } output_iterator_proxy& operator++() { return *this; } output_iterator_proxy& operator++(int) { return *this; } }; template class basic_forward_iterator_proxy_impl : public iterator { public: virtual ~basic_forward_iterator_proxy_impl() { } virtual basic_forward_iterator_proxy_impl* dup() const = 0; virtual bool operator==(const basic_forward_iterator_proxy_impl& x) const = 0; virtual bool operator!=(const basic_forward_iterator_proxy_impl& x) const { return !((*this)==x); } virtual TR operator*() const = 0; virtual TP operator->() const = 0; virtual void advance() = 0; }; template class forward_iterator_proxy_impl : public basic_forward_iterator_proxy_impl { public: IT i; forward_iterator_proxy_impl(const IT& _i) : i(_i) { } virtual basic_forward_iterator_proxy_impl* dup() const { return new forward_iterator_proxy_impl(i); } virtual bool operator==(const basic_forward_iterator_proxy_impl& x) const { return i==static_cast*>(&x)->i; } virtual bool operator!=(const basic_forward_iterator_proxy_impl& x) const { return i!=static_cast*>(&x)->i; } virtual typename IT::reference operator*() const { return *i; } virtual typename IT::pointer operator->() const { return i.operator->(); } virtual void advance() { ++i; } }; template class forward_iterator_proxy : public iterator { public: basic_forward_iterator_proxy_impl *I; template forward_iterator_proxy(const IT& i) : I(new forward_iterator_proxy_impl(i)) { } forward_iterator_proxy(const forward_iterator_proxy& x) : I(x.I->dup()) { } ~forward_iterator_proxy() { delete I; } forward_iterator_proxy& operator=(const forward_iterator_proxy& x) { delete I; I = x.I->dup(); return *this; } bool operator==(const forward_iterator_proxy& x) const { return (*I)==(*(x.I)); } bool operator!=(const forward_iterator_proxy& x) const { return (*I)!=(*(x.I)); } TR operator*() const { return **I; } TP operator->() const { return I->operator->(); } forward_iterator_proxy& operator++() { I->advance(); return *this; } forward_iterator_proxy& operator++(int) { forward_iterator_proxy rv(*this); I->advance(); return rv; } }; template class basic_filterator : public iterator< typename IT::iterator_category, typename IT::value_type, typename IT::difference_type, typename IT::pointer, typename IT::reference> { public: IT it; IT ei; bool empty; basic_filterator() : empty(true) { } basic_filterator(const IT& _bi,const IT& _ei) : it(_bi), ei(_ei) { empty = (it==ei); } basic_filterator(const basic_filterator& x) : it(x.it), ei(x.ei), empty(x.empty) { } virtual ~basic_filterator() { } bool operator==(const basic_filterator& x) const { return empty?x.empty:(it==x.it); } bool operator!=(const basic_filterator& x) const { return empty!=x.empty || it!=x.it; } typename IT::reference operator*() const { assert(!empty); return *it; } typename IT::pointer operator->() const { assert(!empty); return it.operator->(); } basic_filterator& operator++() { bool found = false; for(++it;!(it==ei || (found=is_interesting()));++it) ; if(!found) empty=true; return *this; } void prepare() { bool found = false; for(;!(it==ei || (found=is_interesting()));++it) ; if(!found) empty = true; } virtual bool is_interesting() const = 0; }; template class map_keys_iterator : public iterator< typename IT::iterator_category, T,void,TP,TR> { public: typedef map_keys_iterator self_type; IT it; IT ei; bool empty; map_keys_iterator() : empty(true) { } map_keys_iterator(const IT& _bi, const IT& _ei) : it(_bi), ei(_ei) { empty = (it==ei); } map_keys_iterator(const self_type& x) : it(x.it), ei(x.ei), empty(x.empty) { } bool operator==(const self_type& x) const { return empty?x.empty:(it==x.it); } bool operator!=(const self_type& x) const { return empty!=x.empty || it!=x.it; } TR operator*() const { assert(!empty); return it->first; } TP operator->() const { assert(!empty); return &(it->first); } self_type& operator++() { assert(!empty); empty=((++it)==ei); return *this; } self_type operator++(int) { self_type rv(*this); ++(*this); return rv; } }; } } #endif /* __OPKELE_ITERATOR_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/oauth_ext.h000066400000000000000000000031311273462535700230670ustar00rootroot00000000000000#ifndef __OPKELE_OAUTH_EXT_H #define __OPKELE_OAUTH_EXT_H /** * @file * @brief OAuth extension */ #include namespace opkele { /** * OpenID OAuth extension * http://step2.googlecode.com/svn/spec/openid_oauth_extension/latest/openid_oauth_extension.html */ class oauth_ext_t : public extension_t { public: std::string m_consumer, m_scope, m_request_token; oauth_ext_t(const char *consumer = "", const char *scope = "") : m_consumer(consumer), m_scope(scope) { } virtual void rp_checkid_hook(basic_openid_message& om); virtual void rp_id_res_hook(const basic_openid_message& om, const basic_openid_message& sp); virtual void op_checkid_hook(const basic_openid_message& inm); virtual void op_id_res_hook(basic_openid_message& oum); virtual void checkid_hook(basic_openid_message& om); virtual void id_res_hook(const basic_openid_message& om, const basic_openid_message& sp); virtual void checkid_hook(const basic_openid_message& inm, basic_openid_message& oum); /** * Function called after parsing sreg request to set up response * fields. The default implementation tries to send as much fields * as we have. The function is supposed to set the data and * fields_response. * @see fields_response * @param inm incoming openid message * @param oum outgoing openid message */ virtual void setup_response(const basic_openid_message& inm, basic_openid_message& oum); virtual void setup_response(); }; } #endif /* __OPKELE_OAUTH_EXT_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/opkele-config.h000066400000000000000000000002071273462535700236120ustar00rootroot00000000000000#ifndef __OPKELE_OPKELE_CONFIG_H #define __OPKELE_OPKELE_CONFIG_H #include "opkele/acconfig.h" #endif /* __OPKELE_OPKELE_CONFIG_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/prequeue_rp.h000066400000000000000000000052261273462535700234320ustar00rootroot00000000000000#ifndef __OPKELE_RP_H #define __OPKELE_RP_H #include #include #include #include namespace opkele { using std::string; using std::set; using std::iterator; using std::output_iterator_tag; /** * discovery-enabled RP implementation, prequeueing discovered endpoints */ class prequeue_RP : public basic_RP { public: /** * @name Session persistent store API * @{ */ /** * Called before queueing discovered endpoints. Typically happens * while initiating authentication session. * @see queue_endpoint() * @see end_queueing() */ virtual void begin_queueing() { } /** * Used to queue discovered endpoint. It is implementors * responsibility to store the endpoint wherever he choses to store * it. * @param oep the endpoint to queue * @see begin_queueing() * @see end_queueing() */ virtual void queue_endpoint(const openid_endpoint_t& oep) = 0; /** * Called after all discovered endpoints were queued. Implementor * may chose to use this virtual to commit endpoints queue to * persistent store. * @see begin_queueing() * @see queue_endpoint() */ virtual void end_queueing() { } /** * Used to store normalized id when initiating request. * The default implementation does nothing, because implementor * doesn't have to care. * @param nid normalized id * @see get_normalzied_id() */ virtual void set_normalized_id(const string& nid); /** * Return the normalized id previously set by set_normalized_id(). * Provided for the sake of completeness because default * implementation doesn't use it. * @return the normalized identity */ virtual const string get_normalized_id() const; /** * @} */ /** * @name Actions * @{ */ /** * In addition to base class implementation it does endpoints * discovery and queueing * @param usi User-suppled identifier */ void initiate(const string& usi); /** * @} */ void verify_OP(const string& OP, const string& claimed_id,const string& identity) const; /** * Perform full discovery on identity * @param it iterator used for feeding discovered endpoints back to caller * @param id user supplied identity * @returns normalized identity (canonical identifier can be found in endpoints) */ virtual const string discover(openid_endpoint_output_iterator it,const string& id) const; }; } #endif /* __OPKELE_RP_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/sreg.h000066400000000000000000000126341273462535700220370ustar00rootroot00000000000000#ifndef __OPKELE_SREG_H #define __OPKELE_SREG_H /** * @file * @brief Simple registration extension */ #include namespace opkele { using std::map; /** * OpenID simple registration extension implementation * http://openid.net/specs/openid-simple-registration-extension-1_0.html */ class sreg_t : public extension_t { public: /** * sreg fields enumeration */ enum fieldbit_t { /** * Any UTF-8 string that the End User wants to use as a nickname. */ field_nickname = 1, /** * The email address of the End User as specified in section 3.4.1 of [RFC2822] */ field_email = 2, /** * UTF-8 string free text representation of the End User's full name. */ field_fullname = 4, /** * The End User's date of birth as YYYY-MM-DD. Any values whose * representation uses fewer than the specified number of * digits should be zero-padded. The length of this value MUST * always be 10. If the End User user does not want to reveal * any particular component of this value, it MUST be set to * zero. * * For instance, if a End User wants to specify that his date * of birth is in 1980, but not the month or day, the value * returned SHALL be "1980-00-00". */ field_dob = 8, /** * Alias to field_dob */ field_birthdate = field_dob, /** * The End User's gender, "M" for male, "F" for female. */ field_gender = 16, /** * Alias to field_gender */ field_sex = field_gender, /** * UTF-8 string free text that SHOULD conform to the End User's * country's postal system. */ field_postcode = 32, /** * The End User's country of residence as specified by ISO3166 */ field_country = 64, /** * End User's preferred language as specified by ISO639 */ field_language = 128, /** * ASCII string from TimeZone database * * For example, "Europe/Paris" or "America/Los_Angeles". */ field_timezone = 256, /** * All fields bits combined */ fields_ALL = 511, /** * No fields */ fields_NONE = 0 }; /** * Bitmask for fields which, if absent from the response, will * prevent the Consumer from completing the registration without * End User interation. */ long fields_required; /** * Bitmask for fields that will be used by the Consumer, but whose * absence will not prevent the registration from completing. */ long fields_optional; /** * A URL which the Consumer provides to give the End User a place * to read about the how the profile data will be used. The * Identity Provider SHOULD display this URL to the End User if it * is given. */ string policy_url; /** * Bitmask for fields present in response */ long has_fields; /** * Container type for response fields values */ typedef map response_t; /** * Response contents */ response_t response; /** * Fields bitmask to send in response */ long fields_response; /** * Consumer constructor. * @param fr required fields * @see fields_required * @param fo optional fields * @see fields_optional * @param pu policy url * @see policy_url */ sreg_t(long fr=fields_NONE,long fo=fields_NONE,const string& pu="") : fields_required(fr), fields_optional(fo), policy_url(pu), has_fields(0) { } virtual void rp_checkid_hook(basic_openid_message& om); virtual void rp_id_res_hook(const basic_openid_message& om, const basic_openid_message& sp); virtual void op_checkid_hook(const basic_openid_message& inm); virtual void op_id_res_hook(basic_openid_message& oum); virtual void checkid_hook(basic_openid_message& om); virtual void id_res_hook(const basic_openid_message& om, const basic_openid_message& sp); virtual void checkid_hook(const basic_openid_message& inm, basic_openid_message& oum); /** * Check and see if we have value for some particular field. * @param fb field in question * @see fieldbit_t * @return true if the value is available */ bool has_field(fieldbit_t fb) const { return has_fields&fb; } /** * Retrieve the value for a field. * @param fb field in question * @see fieldbit_t * @return field value * @throw failed_lookup if no data avaialble */ const string& get_field(fieldbit_t fb) const; /** * Set the value for a field. * @param fb field in question * @see fieldbit_t * @param fv field value */ void set_field(fieldbit_t fb,const string& fv); /** * Remove the value for a field. * @param fb field in question * @see fieldbit_t */ void reset_field(fieldbit_t fb); /** * Reset field data */ void clear(); /** * Function called after parsing sreg request to set up response * fields. The default implementation tries to send as much fields * as we have. The function is supposed to set the data and * fields_response. * @see fields_response * @param inm incoming openid message * @param oum outgoing openid message */ virtual void setup_response(const basic_openid_message& inm, basic_openid_message& oum); virtual void setup_response(); }; } #endif /* __OPKELE_SREG_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/tidy.h000066400000000000000000000034451273462535700220500ustar00rootroot00000000000000#ifndef __OPKELE_TIDY_H #define __OPKELE_TIDY_H #include #ifdef HAVE_TIDY_H # include # include #elif HAVE_TIDY_TIDY_H # include # include #else # error "Don't know where to look for htmltidy headers" #endif namespace opkele { namespace util { class tidy_buf_t { public: TidyBuffer _x; tidy_buf_t() { tidyBufInit(&_x); } virtual ~tidy_buf_t() throw() { tidyBufFree(&_x); } inline operator const TidyBuffer&(void) const { return _x; } inline operator TidyBuffer&(void) { return _x; } inline operator const char*(void) const { return (const char*)_x.bp; } inline operator char*(void) { return (char*)_x.bp; } inline const char *c_str() const { return (const char*)_x.bp; } inline size_t size() const { return _x.size; } }; class tidy_doc_t { public: TidyDoc _x; tidy_doc_t() : _x(0) { } tidy_doc_t(TidyDoc x) : _x(x) { } virtual ~tidy_doc_t() throw() { if(_x) tidyRelease(_x); } tidy_doc_t& operator=(TidyDoc x) { if(_x) tidyRelease(_x); _x = x; return *this; } operator TidyDoc(void) const { return _x; } operator TidyDoc(void) { return _x; } inline bool opt_set(TidyOptionId o,bool v) { assert(_x); return tidyOptSetBool(_x,o,v?yes:no); } inline bool opt_set(TidyOptionId o,int v) { assert(_x); return tidyOptSetInt(_x,o,v); } inline int parse_string(const string& s) { assert(_x); return tidyParseString(_x,s.c_str()); } inline int clean_and_repair() { assert(_x); return tidyCleanAndRepair(_x); } inline int save_buffer(TidyBuffer& ob) { assert(_x); return tidySaveBuffer(_x,&ob); } static inline TidyDoc create() { return tidyCreate(); } }; } } #endif /* __OPKELE_TIDY_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/tr1-mem.h.in000066400000000000000000000002751273462535700227640ustar00rootroot00000000000000#ifndef __OPKELE_TR1_MEM_H #define __OPKELE_TR1_MEM_H #include <@OPKELE_TR1_MEM_HEADER@> namespace opkele { namespace tr1mem = @OPKELE_TR1_MEM_NS@; } #endif /* __OPKELE_TR1_MEM_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/types.h000066400000000000000000000150311273462535700222350ustar00rootroot00000000000000#ifndef __OPKELE_TYPES_H #define __OPKELE_TYPES_H /** * @file * @brief various types declarations */ #include #include #include #include #include #include #include #include #include namespace opkele { using std::vector; using std::string; using std::map; using std::ostream; using std::multimap; using std::set; using std::list; using std::iterator; using std::forward_iterator_tag; /** * the OpenID operation mode */ typedef enum _mode_t { mode_unknown = 0, mode_associate, mode_checkid_immediate, mode_checkid_setup, mode_check_association } mode_t; /** * the association secret container */ class secret_t : public vector { public: /** * xor the secret and hmac together and encode, using base64 * @param key_d pointer to the message digest * @param rv reference to the return value */ void enxor_to_base64(const unsigned char *key_d,string& rv) const; /** * decode base64-encoded secret and xor it with the message digest * @param key_d pointer to the message digest * @param b64 base64-encoded secret value */ void enxor_from_base64(const unsigned char *key_d,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: virtual ~association_t() { } /** * 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; /** * check whether the association is expired. * @return true if expired */ virtual bool is_expired() const = 0; }; /** * the shared_ptr<> for association_t object type */ typedef tr1mem::shared_ptr assoc_t; class basic_fields { public: typedef util::forward_iterator_proxy< string,const string&,const string* > fields_iterator; basic_fields() { } virtual ~basic_fields() { } basic_fields(const basic_fields& x); void copy_to(basic_fields& x) const; void append_to(basic_fields& x) const; virtual bool has_field(const string& n) const = 0; virtual const string& get_field(const string& n) const = 0; virtual fields_iterator fields_begin() const = 0; virtual fields_iterator fields_end() const = 0; virtual string append_query(const string& url,const char *pfx=0) const; virtual string query_string(const char *pfx=0) const; virtual void reset_fields(); virtual void set_field(const string& n,const string& v); virtual void reset_field(const string& n); }; class basic_openid_message : public basic_fields { public: basic_openid_message() { } basic_openid_message(const basic_openid_message& x); virtual bool has_ns(const string& uri) const; virtual string get_ns(const string& uri) const; virtual string append_query(const string& url,const char *pfx="openid.") const { return basic_fields::append_query(url,pfx); } virtual string query_string(const char *pfx="openid.") const { return basic_fields::query_string(pfx); } virtual void from_keyvalues(const string& kv); virtual void to_keyvalues(ostream& o) const; virtual void to_htmlhiddens(ostream& o,const char* pfx=0) const; void add_to_signed(const string& fields); string find_ns(const string& uri,const char *pfx) const; string allocate_ns(const string& uri,const char *pfx); }; class openid_message_t : public basic_openid_message, public map { public: openid_message_t() { } openid_message_t(const basic_openid_message& x) : basic_openid_message(x) { } bool has_field(const string& n) const; const string& get_field(const string& n) const; virtual fields_iterator fields_begin() const; virtual fields_iterator fields_end() const; void reset_fields(); void set_field(const string& n,const string& v); void reset_field(const string& n); }; /** * request/response parameters map */ class params_t : public openid_message_t { public: /** * check whether the parameter is present. * @param n the parameter name * @return true if yes */ bool has_param(const string& n) const { return has_field(n); } /** * 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 { return get_field(n); } /** * parse the OpenID key/value data. * @param kv the OpenID key/value data */ void parse_keyvalues(const string& kv) { from_keyvalues(kv); } string append_query(const string& url,const char *prefix="openid.") const; }; struct openid_endpoint_t { string uri; string claimed_id; string local_id; openid_endpoint_t() { } openid_endpoint_t(const string& u,const string& cid,const string& lid) : uri(u), claimed_id(cid), local_id(lid) { } bool operator==(const openid_endpoint_t& x) const { return uri==x.uri && local_id==x.local_id; } bool operator<(const openid_endpoint_t& x) const { int c; return (c=strcmp(uri.c_str(),x.uri.c_str())) ? (c<0) : (strcmp(local_id.c_str(),x.local_id.c_str())<0); } }; typedef util::output_iterator_proxy openid_endpoint_output_iterator; } #endif /* __OPKELE_TYPES_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/uris.h000066400000000000000000000016001273462535700220500ustar00rootroot00000000000000#ifndef __OPKELE_URIS_H #define __OPKELE_URIS_H #define NSURI_XRDS "xri://$xrds" #define NSURI_XRD "xri://$xrd*($v*2.0)" #define NSURI_OPENID10 "http://openid.net/xmlns/1.0" #define OIURI_OPENID20 "http://specs.openid.net/auth/2.0" #define OIURI_SREG10 "http://openid.net/sreg/1.0" #define OIURI_SREG11 "http://openid.net/extensions/sreg/1.1" #define OIURI_AX10 "http://openid.net/srv/ax/1.0" #define OIURI_OAUTH10 "http://specs.openid.net/extensions/oauth/1.0" #define STURI_OPENID10 "http://openid.net/signon/1.0" #define STURI_OPENID11 "http://openid.net/signon/1.1" #define STURI_OPENID20 "http://specs.openid.net/auth/2.0/signon" #define STURI_OPENID20_OP "http://specs.openid.net/auth/2.0/server" #define STURI_OPENID20_RT "http://specs.openid.net/auth/2.0/return_to" #define IDURI_SELECT20 "http://specs.openid.net/auth/2.0/identifier_select" #endif /* __OPKELE_URIS_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/util-internal.h000066400000000000000000000046771273462535700236760ustar00rootroot00000000000000#ifndef __OPKELE_UTIL_INTERNAL_H #define __OPKELE_UTIL_INTERNAL_H #include #include #include namespace opkele { namespace util { /** * Convenience class encapsulating SSL BIGNUM object for the purpose of * automatical freeing. */ 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; } }; /** * Convenience clas encapsulating SSL DH object for the purpose of * automatic freeing. */ 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; } }; /** * Convert base64-encoded SSL BIGNUM to internal representation. * @param b64 base64-encoded number * @return SSL BIGNUM * @throw failed_conversion in case of error */ BIGNUM *base64_to_bignum(const string& b64); /** * Convert decimal representation to SSL BIGNUM. * @param dec decimal representation * @return resulting BIGNUM * @throw failed_conversion in case of error */ BIGNUM *dec_to_bignum(const string& dec); /** * Convert SSL BIGNUM data to base64 encoded string. * @param bn BIGNUM * @return base64encoded string */ string bignum_to_base64(const BIGNUM *bn); string abi_demangle(const char* mn); class change_mode_message_proxy : public basic_openid_message { public: const basic_openid_message& x; const string& mode; change_mode_message_proxy(const basic_openid_message& xx,const string& m) : x(xx), mode(m) { } bool has_field(const string& n) const { return x.has_field(n); } const string& get_field(const string& n) const { return (n=="mode")?mode:x.get_field(n); } bool has_ns(const string& uri) const {return x.has_ns(uri); } string get_ns(const string& uri) const { return x.get_ns(uri); } fields_iterator fields_begin() const { return x.fields_begin(); } fields_iterator fields_end() const { return x.fields_end(); } }; } } #endif /* __OPKELE_UTIL_INTERNAL_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/util.h000066400000000000000000000061001273462535700220430ustar00rootroot00000000000000#ifndef __OPKELE_UTIL_H #define __OPKELE_UTIL_H #include #include #include #include namespace opkele { using std::string; using std::vector; /** * @brief opkele utils namespace */ namespace util { /** * Convert internal time representation to w3c format * @param t internal representation * @return w3c time * @throw failed_conversion in case of error */ string time_to_w3c(time_t t); /** * Convert W3C time representation to internal time_t * @param w w3c representation * @return converted time * @throw failed_conversion in case of error */ time_t w3c_to_time(const string& w); /** * Encode string to the representation suitable for using in URL * @param str string to encode * @return encoded string * @throw failed_conversion in case of failure */ string url_encode(const string& str); /** * Decode url-encoded string back to normal * @param str url-encoded string * @return decoded string * @throw failed_conversion in case of failure */ string url_decode(const string& str); /** * Make string suitable for using as x(ht)ml attribute. * @param str string to escape * @return escaped string */ string attr_escape(const string& str); /** * Convert number to string * @param l number * @return string representation * @throw failed_conversion in case of failure */ string long_to_string(long l); /** * Convert string to number * @param s string, containing the number * @return the number * @throw failed_conversion in case of failure */ long string_to_long(const string& s); /** * Encode binary data using base64. * @param data pointer to binary data * @param length length of data * @return encoded data */ string encode_base64(const void *data,size_t length); /** * Decode binary data from base64 representation. * @param data base64-encoded data * @param rv container for decoded binary */ void decode_base64(const string& data,vector& rv); /** * Normalize http(s) URI according to RFC3986, section 6. URI is * expected to have scheme: in front of it. * @param uri URI * @return normalized URI * @throw not_implemented in case of non-httpi(s) URI * @throw bad_input in case of malformed URI */ string rfc_3986_normalize_uri(const string& uri); string normalize_identifier(const string& usi,bool strip_fragment); /** * Match URI against realm * @param uri URI to match * @param realm realm to match against * @return true if URI matches realm */ bool uri_matches_realm(const string& uri,const string& realm); /** * Strip fragment part from URI * @param uri input/output parameter containing the URI * @return reference to uri */ string& strip_uri_fragment_part(string& uri); /** * Calculate signature and encode it using base64 * @param assoc association being used for signing * @param om openid message * @return base64 representation of the signature */ string base64_signature(const assoc_t& assoc,const basic_openid_message& om); } } #endif /* __OPKELE_UTIL_H */ libopkele-2.0.4+git20140305.9651b55/include/opkele/verify_op.h000066400000000000000000000010651273462535700230750ustar00rootroot00000000000000#ifndef __OPKELE_VERIFY_OP_H #define __OPKELE_VERIFY_OP_H #include namespace opkele { /** * The OP implementation that does discovery verification on RP */ class verify_OP : public basic_OP { public: /** * In addition to basic_OP::verify_return_to() functionality this * implementation does the discovery on RP to see if return_to matches * the realm * @throw bad_return_to in case we fail to discover corresponding * service endpoint */ void verify_return_to(); }; } #endif /* __OPKELE_VERIFY_OP_H */ libopkele-2.0.4+git20140305.9651b55/lib/000077500000000000000000000000001273462535700165645ustar00rootroot00000000000000libopkele-2.0.4+git20140305.9651b55/lib/.gitignore000066400000000000000000000000671273462535700205570ustar00rootroot00000000000000*.lo *.o Makefile.in libopkele.la .libs .deps Makefile libopkele-2.0.4+git20140305.9651b55/lib/Makefile.am000066400000000000000000000014661273462535700206270ustar00rootroot00000000000000lib_LTLIBRARIES = libopkele.la AM_CPPFLAGS = ${CPPFLAGS_DEBUG} DEFAULT_INCLUDES = -I${top_builddir} INCLUDES = \ -I${top_builddir}/include/ -I${top_srcdir}/include/ \ ${KONFORKA_CFLAGS} \ ${OPENSSL_CFLAGS} \ ${LIBCURL_CPPFLAGS} \ ${EXPAT_CFLAGS} ${TIDY_CFLAGS} libopkele_la_LIBADD = \ ${LIBCURL} \ ${EXPAT_LIBS} \ ${OPENSSL_LIBS} \ ${KONFORKA_LIBS} ${TIDY_LIBS} libopkele_la_SOURCES = \ params.cc \ util.cc \ secret.cc \ data.cc \ exception.cc \ extension.cc \ sreg.cc \ extension_chain.cc \ curl.cc expat.cc \ discovery.cc \ basic_rp.cc prequeue_rp.cc \ fields.cc message.cc \ basic_op.cc verify_op.cc \ ax.cc oauth_ext.cc libopkele_la_LDFLAGS = \ -version-info 3:0:0 libopkele-2.0.4+git20140305.9651b55/lib/ax.cc000066400000000000000000000103311273462535700175010ustar00rootroot00000000000000#include #include #include #include #include #include #include using namespace std; namespace opkele { void ax_t::add_attribute(const char *uri, bool required, const char *alias /* = NULL */, int count /* = 1 */) { assert(uri && *uri); assert(count != 0); ax_attr_t attr; attr.uri = uri; attr.required = required; attr.count = count; // if no alias is specified, generate one using an internal auto-incremented counter attr.alias = alias ? alias : string("attr") + opkele::util::long_to_string(++alias_count); attrs.push_back(attr); } void ax_t::rp_checkid_hook(basic_openid_message& om) { if (attrs.size() == 0) return; // not asking for any attributes string pfx = om.allocate_ns(OIURI_AX10,"ax"); om.set_field(pfx+".mode", "fetch_request"); // only supports fetch_request for now string required_fields, optional_fields; for (size_t i = 0; i < attrs.size(); i++) { // build up list of required/optional aliases if (attrs[i].required) required_fields += (required_fields.empty() ? "" : ",") + attrs[i].alias; else optional_fields += (optional_fields.empty() ? "" : ",") + attrs[i].alias; om.set_field(pfx+".type."+attrs[i].alias, attrs[i].uri); // only specify count if it's >1 or unlimited if (attrs[i].count == UNLIMITED_COUNT) { om.set_field(pfx+".count."+attrs[i].alias, "unlimited"); } else if (attrs[i].count > 1) { om.set_field(pfx+".count."+attrs[i].alias, opkele::util::long_to_string(attrs[i].count)); } } if (!required_fields.empty()) om.set_field(pfx+".required", required_fields); if (!optional_fields.empty()) om.set_field(pfx+".if_available", optional_fields); if (!update_url.empty()) om.set_field(pfx+".update_url", update_url); } void ax_t::checkid_hook(basic_openid_message& om) { rp_checkid_hook(om); } void ax_t::rp_id_res_hook(const basic_openid_message& om, const basic_openid_message& sp) { string pfx; try { pfx = om.find_ns(OIURI_AX10,"ax"); }catch(failed_lookup&) { return; } pfx += '.'; // first look at all aliases and generate an internal uri->alias map string fn; map aliases; for (basic_openid_message::fields_iterator it = sp.fields_begin(); it != sp.fields_end(); ++it) { fn = *it; string type_pfx = pfx; type_pfx += "type."; size_t pos = fn.find(type_pfx); if (pos == string::npos) continue; string alias = fn.substr(pos + type_pfx.size()); aliases[sp.get_field(fn)] = alias; } // now for each alias, pull out the count and value(s) and store uri->[value1, ...] for (map::iterator it = aliases.begin(); it != aliases.end(); ++it) { vector values; fn = pfx; fn += "count." + it->second; if (sp.has_field(fn)) { int count = opkele::util::string_to_long(sp.get_field(fn)); for (int i = 1; i <= count; i++) { fn = pfx; fn += "value." + it->second + "." + opkele::util::long_to_string(i); values.push_back(sp.get_field(fn)); } } else { fn = pfx; fn += "value." + it->second; values.push_back(sp.get_field(fn)); } response_attrs[it->first] = values; } fn = pfx; fn += "update_url"; if (sp.has_field(fn)) update_url = sp.get_field(fn); } string ax_t::get_attribute(const char *uri, int index /* = 0 */) { if (response_attrs.find(uri) == response_attrs.end()) return ""; return response_attrs[uri][index]; } size_t ax_t::get_attribute_count(const char *uri) { if (response_attrs.find(uri) == response_attrs.end()) return 0; return response_attrs[uri].size(); } void ax_t::id_res_hook(const basic_openid_message& om, const basic_openid_message& sp) { rp_id_res_hook(om,sp); } void ax_t::op_checkid_hook(const basic_openid_message& inm) { } void ax_t::op_id_res_hook(basic_openid_message& oum) { } void ax_t::checkid_hook(const basic_openid_message& inm, basic_openid_message& oum) { op_checkid_hook(inm); setup_response(inm,oum); op_id_res_hook(oum); } void ax_t::setup_response(const basic_openid_message& /* inm */,basic_openid_message& /* oum */) { setup_response(); } void ax_t::setup_response() { } } libopkele-2.0.4+git20140305.9651b55/lib/basic_op.cc000066400000000000000000000254271273462535700206640ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include namespace opkele { void basic_OP::reset_vars() { assoc.reset(); return_to.clear(); realm.clear(); claimed_id.clear(); identity.clear(); invalidate_handle.clear(); } bool basic_OP::has_return_to() const { return !return_to.empty(); } const string& basic_OP::get_return_to() const { if(return_to.empty()) throw no_return_to(OPKELE_CP_ "No return_to URL provided with request"); return return_to; } const string& basic_OP::get_realm() const { assert(!realm.empty()); return realm; } bool basic_OP::has_identity() const { return !identity.empty(); } const string& basic_OP::get_claimed_id() const { if(claimed_id.empty()) throw non_identity(OPKELE_CP_ "attempting to retrieve claimed_id of non-identity related request"); assert(!identity.empty()); return claimed_id; } const string& basic_OP::get_identity() const { if(identity.empty()) throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related request"); assert(!claimed_id.empty()); return identity; } bool basic_OP::is_id_select() const { return identity==IDURI_SELECT20; } void basic_OP::select_identity(const string& c,const string& i) { claimed_id = c; identity = i; } void basic_OP::set_claimed_id(const string& c) { claimed_id = c; } basic_openid_message& basic_OP::associate( basic_openid_message& oum, const basic_openid_message& inm) try { assert(inm.get_field("mode")=="associate"); util::dh_t dh; util::bignum_t c_pub; unsigned char key_digest[SHA256_DIGEST_LENGTH]; size_t d_len = 0; string sts = inm.get_field("session_type"); string ats = inm.get_field("assoc_type"); if(sts=="DH-SHA1" || sts=="DH-SHA256") { if(!(dh = DH_new())) throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); c_pub = util::base64_to_bignum(inm.get_field("dh_consumer_public")); try { dh->p = util::base64_to_bignum(inm.get_field("dh_modulus")); }catch(failed_lookup&) { dh->p = util::dec_to_bignum(data::_default_p); } try { dh->g = util::base64_to_bignum(inm.get_field("dh_gen")); }catch(failed_lookup&) { 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 ck(DH_size(dh)+1); unsigned char *ckptr = &(ck.front())+1; int cklen = DH_compute_key(ckptr,c_pub,dh); if(cklen<0) throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); if(cklen && (*ckptr)&0x80) { (*(--ckptr)) = 0; ++cklen; } if(sts=="DH-SHA1") { SHA1(ckptr,cklen,key_digest); d_len = SHA_DIGEST_LENGTH; }else if(sts=="DH-SHA256") { SHA256(ckptr,cklen,key_digest); d_len = SHA256_DIGEST_LENGTH; }else throw internal_error(OPKELE_CP_ "I thought I knew the session type"); }else throw unsupported(OPKELE_CP_ "Unsupported session_type"); assoc_t a; if(ats=="HMAC-SHA1") a = alloc_assoc(ats,SHA_DIGEST_LENGTH,false); else if(ats=="HMAC-SHA256") a = alloc_assoc(ats,SHA256_DIGEST_LENGTH,false); else throw unsupported(OPKELE_CP_ "Unsupported assoc_type"); oum.reset_fields(); oum.set_field("ns",OIURI_OPENID20); oum.set_field("assoc_type",a->assoc_type()); oum.set_field("assoc_handle",a->handle()); oum.set_field("expires_in",util::long_to_string(a->expires_in())); secret_t secret = a->secret(); if(sts=="DH-SHA1" || sts=="DH-SHA256") { if(d_len != secret.size()) throw bad_input(OPKELE_CP_ "Association secret and session MAC are not of the same size"); oum.set_field("session_type",sts); oum.set_field("dh_server_public",util::bignum_to_base64(dh->pub_key)); string b64; secret.enxor_to_base64(key_digest,b64); oum.set_field("enc_mac_key",b64); }else /* TODO: support cleartext over encrypted connection */ throw unsupported(OPKELE_CP_ "Unsupported session type"); return oum; } catch(unsupported& u) { oum.reset_fields(); oum.set_field("ns",OIURI_OPENID20); oum.set_field("error",u.what()); oum.set_field("error_code","unsupported-type"); oum.set_field("session_type","DH-SHA256"); oum.set_field("assoc_type","HMAC-SHA256"); return oum; } void basic_OP::checkid_(const basic_openid_message& inm, extension_t *ext) { reset_vars(); string modestr = inm.get_field("mode"); if(modestr=="checkid_setup") mode = mode_checkid_setup; else if(modestr=="checkid_immediate") mode = mode_checkid_immediate; else throw bad_input(OPKELE_CP_ "Invalid checkid_* mode"); try { assoc = retrieve_assoc(invalidate_handle=inm.get_field("assoc_handle")); invalidate_handle.clear(); }catch(failed_lookup&) { } try { openid2 = (inm.get_field("ns")==OIURI_OPENID20); }catch(failed_lookup&) { openid2 = false; } try { return_to = inm.get_field("return_to"); }catch(failed_lookup&) { } if(openid2) { try { realm = inm.get_field("realm"); if(realm.empty()) throw failed_lookup(OPKELE_CP_ "Empty realm doesn't count"); }catch(failed_lookup&) { try { realm = inm.get_field("trust_root"); if(realm.empty()) throw failed_lookup(OPKELE_CP_ "Empty trust_root doesn't count"); }catch(failed_lookup&) { if(return_to.empty()) throw bad_input(OPKELE_CP_ "Both realm and return_to are unset"); realm = return_to; } } }else{ try { realm = inm.get_field("trust_root"); if(realm.empty()) throw failed_lookup(OPKELE_CP_ "Empty trust_root doesn't count"); }catch(failed_lookup&) { if(return_to.empty()) throw bad_input(OPKELE_CP_ "Both realm and return_to are unset"); realm = return_to; } } try { identity = inm.get_field("identity"); try { claimed_id = inm.get_field("claimed_id"); }catch(failed_lookup&) { if(openid2) throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent"); claimed_id = identity; } }catch(failed_lookup&) { if(openid2 && inm.has_field("claimed_id")) throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent"); } verify_return_to(); if(ext) ext->op_checkid_hook(inm); } basic_openid_message& basic_OP::id_res(basic_openid_message& om, extension_t *ext) { assert(!return_to.empty()); assert(!is_id_select()); if(!assoc) { assoc = alloc_assoc("HMAC-SHA256",SHA256_DIGEST_LENGTH,true); } time_t now = time(0); struct tm gmt; gmtime_r(&now,&gmt); char w3timestr[24]; if(!strftime(w3timestr,sizeof(w3timestr),"%Y-%m-%dT%H:%M:%SZ",&gmt)) throw failed_conversion(OPKELE_CP_ "Failed to build time string for nonce" ); om.set_field("ns",OIURI_OPENID20); om.set_field("mode","id_res"); om.set_field("op_endpoint",get_op_endpoint()); string ats = "ns,mode,op_endpoint,return_to,response_nonce," "assoc_handle,signed"; if(!identity.empty()) { om.set_field("identity",identity); om.set_field("claimed_id",claimed_id); ats += ",identity,claimed_id"; } om.set_field("return_to",return_to); string nonce = w3timestr; om.set_field("response_nonce",alloc_nonce(nonce)); if(!invalidate_handle.empty()) { om.set_field("invalidate_handle",invalidate_handle); ats += ",invalidate_handle"; } om.set_field("assoc_handle",assoc->handle()); om.add_to_signed(ats); if(ext) ext->op_id_res_hook(om); om.set_field("sig",util::base64_signature(assoc,om)); return om; } basic_openid_message& basic_OP::cancel(basic_openid_message& om) { assert(!return_to.empty()); om.set_field("ns",OIURI_OPENID20); om.set_field("mode","cancel"); return om; } basic_openid_message& basic_OP::error(basic_openid_message& om, const string& err,const string& contact, const string& reference ) { assert(!return_to.empty()); om.set_field("ns",OIURI_OPENID20); om.set_field("mode","error"); om.set_field("error",err); if(!contact.empty()) om.set_field("contact",contact); if(!reference.empty()) om.set_field("reference",reference); return om; } basic_openid_message& basic_OP::setup_needed( basic_openid_message& oum,const basic_openid_message& inm) { assert(mode==mode_checkid_immediate); assert(!return_to.empty()); if(openid2) { oum.set_field("ns",OIURI_OPENID20); oum.set_field("mode","setup_needed"); }else{ oum.set_field("mode","id_res"); static const string setupmode = "checkid_setup"; oum.set_field("user_setup_url", util::change_mode_message_proxy(inm,setupmode) .append_query(get_op_endpoint())); } return oum; } basic_openid_message& basic_OP::check_authentication( basic_openid_message& oum, const basic_openid_message& inm) try { assert(inm.get_field("mode")=="check_authentication"); oum.reset_fields(); oum.set_field("ns",OIURI_OPENID20); bool o2; try { o2 = (inm.get_field("ns")==OIURI_OPENID20); }catch(failed_lookup&) { o2 = false; } string nonce; if(o2) { try { if(!check_nonce(nonce = inm.get_field("response_nonce"))) throw failed_check_authentication(OPKELE_CP_ "Invalid nonce"); }catch(failed_lookup&) { throw failed_check_authentication(OPKELE_CP_ "No nonce provided with check_authentication request"); } } try { assoc = retrieve_assoc(inm.get_field("assoc_handle")); if(!assoc->stateless()) throw failed_check_authentication(OPKELE_CP_ "Will not do check_authentication on a stateful handle"); }catch(failed_lookup&) { throw failed_check_authentication(OPKELE_CP_ "No assoc_handle or invalid assoc_handle specified with check_authentication request"); } static const string idresmode = "id_res"; try { if(util::base64_signature(assoc,util::change_mode_message_proxy(inm,idresmode))!=inm.get_field("sig")) throw failed_check_authentication(OPKELE_CP_ "Signature mismatch"); }catch(failed_lookup&) { throw failed_check_authentication(OPKELE_CP_ "failed to calculate signature"); } oum.set_field("is_valid","true"); try { string h = inm.get_field("invalidate_handle"); try { assoc_t ih = retrieve_assoc(h); }catch(invalid_handle& ih) { oum.set_field("invalidate_handle",h); }catch(failed_lookup& ih) { oum.set_field("invalidate_handle",h); } }catch(failed_lookup&) { } if(o2) { assert(!nonce.empty()); invalidate_nonce(nonce); } return oum; }catch(failed_check_authentication& ) { oum.set_field("is_valid","false"); return oum; } void basic_OP::verify_return_to() { if(realm.find('#')!=string::npos) throw opkele::bad_realm(OPKELE_CP_ "authentication realm contains URI fragment"); if(!util::uri_matches_realm(return_to,realm)) throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match realm"); } } libopkele-2.0.4+git20140305.9651b55/lib/basic_rp.cc000066400000000000000000000257401273462535700206650ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include namespace opkele { void basic_RP::reset_vars() { claimed_id.clear(); identity.clear(); } const string& basic_RP::get_claimed_id() const { if(claimed_id.empty()) throw non_identity(OPKELE_CP_ "attempting to retreive claimed_id of non-identity assertion"); assert(!identity.empty()); return claimed_id; } const string& basic_RP::get_identity() const { if(identity.empty()) throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related assertion"); assert(!claimed_id.empty()); return identity; } static void dh_get_secret( secret_t& secret, const basic_openid_message& om, const char *exp_assoc, const char *exp_sess, util::dh_t& dh, size_t d_len, unsigned char *(*d_fun)(const unsigned char*,size_t,unsigned char*), size_t exp_s_len) try { if(om.get_field("assoc_type")!=exp_assoc || om.get_field("session_type")!=exp_sess) throw bad_input(OPKELE_CP_ "Unexpected associate response"); util::bignum_t s_pub = util::base64_to_bignum(om.get_field("dh_server_public")); vector ck(DH_size(dh)+1); unsigned char *ckptr = &(ck.front())+1; int cklen = DH_compute_key(ckptr,s_pub,dh); if(cklen<0) throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); if(cklen && (*ckptr)&0x80) { (*(--ckptr))=0; ++cklen; } assert(d_len<=SHA256_DIGEST_LENGTH); unsigned char key_digest[SHA256_DIGEST_LENGTH]; secret.enxor_from_base64((*d_fun)(ckptr,cklen,key_digest),om.get_field("enc_mac_key")); if(secret.size()!=exp_s_len) throw bad_input(OPKELE_CP_ "Secret length isn't consistent with association type"); }catch(opkele::failed_lookup& ofl) { throw bad_input(OPKELE_CP_ "Incoherent response from OP"); } OPKELE_RETHROW static void direct_request(basic_openid_message& oum,const basic_openid_message& inm,const string& OP) { util::curl_pick_t curl = util::curl_pick_t::easy_init(); if(!curl) throw exception_curl(OPKELE_CP_ "failed to initialize curl"); string request = inm.query_string(); CURLcode r; (r=curl.misc_sets()) || (r=curl.easy_setopt(CURLOPT_URL,OP.c_str())) || (r=curl.easy_setopt(CURLOPT_POST,1)) || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) || (r=curl.set_write()); if(r) throw exception_curl(OPKELE_CP_ "failed to set curly options",r); if( (r=curl.easy_perform()) ) throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); oum.from_keyvalues(curl.response); } assoc_t basic_RP::associate(const string& OP) { 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()"); openid_message_t req; req.set_field("ns",OIURI_OPENID20); req.set_field("mode","associate"); req.set_field("dh_modulus",util::bignum_to_base64(dh->p)); req.set_field("dh_gen",util::bignum_to_base64(dh->g)); req.set_field("dh_consumer_public",util::bignum_to_base64(dh->pub_key)); openid_message_t res; req.set_field("assoc_type","HMAC-SHA256"); req.set_field("session_type","DH-SHA256"); secret_t secret; int expires_in; try { direct_request(res,req,OP); dh_get_secret( secret, res, "HMAC-SHA256", "DH-SHA256", dh, SHA256_DIGEST_LENGTH, SHA256, SHA256_DIGEST_LENGTH ); expires_in = util::string_to_long(res.get_field("expires_in")); }catch(exception&) { try { req.set_field("assoc_type","HMAC-SHA1"); req.set_field("session_type","DH-SHA1"); direct_request(res,req,OP); dh_get_secret( secret, res, "HMAC-SHA1", "DH-SHA1", dh, SHA_DIGEST_LENGTH, SHA1, SHA_DIGEST_LENGTH ); expires_in = util::string_to_long(res.get_field("expires_in")); }catch(bad_input&) { throw dumb_RP(OPKELE_CP_ "OP failed to supply an association"); } } return store_assoc( OP, res.get_field("assoc_handle"), res.get_field("assoc_type"), secret, expires_in ); } basic_openid_message& basic_RP::checkid_( basic_openid_message& rv, mode_t mode, const string& return_to,const string& realm, extension_t *ext) { rv.reset_fields(); rv.set_field("ns",OIURI_OPENID20); if(mode==mode_checkid_immediate) rv.set_field("mode","checkid_immediate"); else if(mode==mode_checkid_setup) rv.set_field("mode","checkid_setup"); else throw bad_input(OPKELE_CP_ "unknown checkid_* mode"); if(realm.empty() && return_to.empty()) throw bad_input(OPKELE_CP_ "At least one of realm and return_to must be non-empty"); if(!realm.empty()) { rv.set_field("realm",realm); rv.set_field("trust_root",realm); } if(!return_to.empty()) rv.set_field("return_to",return_to); const openid_endpoint_t& ep = get_endpoint(); rv.set_field("claimed_id",ep.claimed_id); rv.set_field("identity",ep.local_id); try { rv.set_field("assoc_handle",find_assoc(ep.uri)->handle()); }catch(dumb_RP& drp) { }catch(failed_lookup& fl) { try { rv.set_field("assoc_handle",associate(ep.uri)->handle()); }catch(dumb_RP& drp) { } } OPKELE_RETHROW if(ext) ext->rp_checkid_hook(rv); return rv; } class signed_part_message_proxy : public basic_openid_message { public: const basic_openid_message& x; set signeds; signed_part_message_proxy(const basic_openid_message& xx) : x(xx) { const string& slist = x.get_field("signed"); 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); signeds.insert(f); if(co==string::npos) break; p = co+1; } } bool has_field(const string& n) const { return signeds.find(n)!=signeds.end() && x.has_field(n); } const string& get_field(const string& n) const { if(signeds.find(n)==signeds.end()) throw failed_lookup(OPKELE_CP_ "The field isn't known to be signed"); return x.get_field(n); } fields_iterator fields_begin() const { return signeds.begin(); } fields_iterator fields_end() const { return signeds.end(); } }; static void parse_query(const string& u,string::size_type q, map& p) { if(q==string::npos) return; assert(u[q]=='?'); ++q; string::size_type l = u.size(); while(qam) { p[""] = u.substr(q,eq-q); }else{ p[u.substr(q,eq-q)] = u.substr(eq+1,am-eq-1); } q = ++am; } } } void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) { reset_vars(); bool o2 = om.has_field("ns") && om.get_field("ns")==OIURI_OPENID20 && om.has_field("op_endpoint") && !om.get_field("op_endpoint").empty(); if( (!o2) && om.has_field("user_setup_url")) throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided", om.get_field("user_setup_url")); string m = om.get_field("mode"); if(o2 && m=="setup_needed") throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided"); if(m=="cancel") throw id_res_cancel(OPKELE_CP_ "authentication cancelled"); bool go_dumb=false; try { string OP = o2 ?om.get_field("op_endpoint") :get_endpoint().uri; assoc_t assoc = retrieve_assoc( OP,om.get_field("assoc_handle")); if(om.get_field("sig")!=util::base64_signature(assoc,om)) throw id_res_mismatch(OPKELE_CP_ "signature mismatch"); }catch(dumb_RP& drp) { go_dumb=true; }catch(failed_lookup& e) { go_dumb=true; } OPKELE_RETHROW if(go_dumb) { try { string OP = o2 ?om.get_field("op_endpoint") :get_endpoint().uri; check_authentication(OP,om); }catch(failed_check_authentication& fca) { throw id_res_failed(OPKELE_CP_ "failed to check_authentication()"); } OPKELE_RETHROW } signed_part_message_proxy signeds(om); if(o2) { check_nonce(om.get_field("op_endpoint"), om.get_field("response_nonce")); static const char *mustsign[] = { "op_endpoint", "return_to", "response_nonce", "assoc_handle", "claimed_id", "identity" }; for(size_t ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) { if(om.has_field(mustsign[ms]) && !signeds.has_field(mustsign[ms])) throw bad_input(OPKELE_CP_ string("Field '")+mustsign[ms]+"' is not signed against the specs"); } if( ( (om.has_field("claimed_id")?1:0) ^ (om.has_field("identity")?1:0) )&1 ) throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent"); string turl = util::rfc_3986_normalize_uri(get_this_url()); util::strip_uri_fragment_part(turl); string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to")); util::strip_uri_fragment_part(rurl); string::size_type tq = turl.find('?'), rq = rurl.find('?'); if( ((tq==string::npos)?turl:turl.substr(0,tq)) != ((rq==string::npos)?rurl:rurl.substr(0,rq)) ) throw id_res_bad_return_to(OPKELE_CP_ "return_to url doesn't match request url"); map tp; parse_query(turl,tq,tp); map rp; parse_query(rurl,rq,rp); for(map::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) { map::const_iterator tpi = tp.find(rpi->first); if(tpi==tp.end()) throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to is missing from the request"); if(tpi->second!=rpi->second) throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to doesn't match the request"); } if(om.has_field("claimed_id")) { claimed_id = om.get_field("claimed_id"); identity = om.get_field("identity"); verify_OP( om.get_field("op_endpoint"), claimed_id, identity ); } }else{ claimed_id = get_endpoint().claimed_id; /* TODO: check if this is the identity we asked for */ identity = om.get_field("identity"); } if(ext) ext->rp_id_res_hook(om,signeds); } void basic_RP::check_authentication(const string& OP, const basic_openid_message& om){ openid_message_t res; static const string checkauthmode = "check_authentication"; direct_request(res,util::change_mode_message_proxy(om,checkauthmode),OP); if(res.has_field("is_valid")) { if(res.get_field("is_valid")=="true") { if(res.has_field("invalidate_handle")) invalidate_assoc(OP,res.get_field("invalidate_handle")); return; } } throw failed_check_authentication( OPKELE_CP_ "failed to verify response"); } } libopkele-2.0.4+git20140305.9651b55/lib/curl.cc000066400000000000000000000044141273462535700200430ustar00rootroot00000000000000#include #include #include "config.h" namespace opkele { namespace util { curl_slist_t::~curl_slist_t() throw() { if(_s) curl_slist_free_all(_s); } curl_slist_t& curl_slist_t::operator=(curl_slist *s) { if(_s) curl_slist_free_all(_s); _s = s; return *this; } void curl_slist_t::append(const char *str) { curl_slist *s = curl_slist_append(_s,str); if(!s) throw opkele::exception(OPKELE_CP_ "failed to curl_slist_append()"); _s=s; } curl_t::~curl_t() throw() { if(_c) curl_easy_cleanup(_c); } curl_t& curl_t::operator=(CURL *c) { if(_c) curl_easy_cleanup(_c); _c = c; return *this; } CURLcode curl_t::misc_sets() { assert(_c); CURLcode r; (r=easy_setopt(CURLOPT_FOLLOWLOCATION,1)) || (r=easy_setopt(CURLOPT_MAXREDIRS,5)) || (r=easy_setopt(CURLOPT_DNS_CACHE_TIMEOUT,120)) || (r=easy_setopt(CURLOPT_DNS_USE_GLOBAL_CACHE,1)) || (r=easy_setopt(CURLOPT_USERAGENT,PACKAGE_NAME "/" PACKAGE_SRC_VERSION)) || (r=easy_setopt(CURLOPT_TIMEOUT,20)) #ifdef DISABLE_CURL_SSL_VERIFYHOST || (r=easy_setopt(CURLOPT_SSL_VERIFYHOST,0)) #endif #ifdef DISABLE_CURL_SSL_VERIFYPEER || (r=easy_setopt(CURLOPT_SSL_VERIFYPEER,0)) #endif ; return r; } static size_t _write(void *p,size_t s,size_t nm,void *stream) { return ((curl_t*)stream)->write(p,s,nm); } CURLcode curl_t::set_write() { assert(_c); CURLcode r; (r = easy_setopt(CURLOPT_WRITEDATA,this)) || (r = easy_setopt(CURLOPT_WRITEFUNCTION,_write)); return r; } static int _progress(void *cp,double dlt,double dln,double ult,double uln) { return ((curl_t*)cp)->progress(dlt,dln,ult,uln); } CURLcode curl_t::set_progress() { assert(_c); CURLcode r; (r = easy_setopt(CURLOPT_PROGRESSDATA,this)) || (r = easy_setopt(CURLOPT_PROGRESSFUNCTION,_progress)) || (r = easy_setopt(CURLOPT_NOPROGRESS,0)); return r; } static size_t _header(void *p,size_t s,size_t nm,void *stream) { return ((curl_t*)stream)->header(p,s,nm); } CURLcode curl_t::set_header() { assert(_c); CURLcode r; (r = easy_setopt(CURLOPT_HEADERDATA,this)) || (r=easy_setopt(CURLOPT_HEADERFUNCTION,_header)); return r; } } } libopkele-2.0.4+git20140305.9651b55/lib/data.cc000066400000000000000000000010241273462535700200010ustar00rootroot00000000000000#include namespace opkele { namespace data { const char *_default_p = "155172898181473697471232257763715539915724801966915404479707795314057629378541917580651227423698188993727816152646631438561595825688188889951272158842675419950341258706556549803580104870537681476726513255747040765857479291291572334510643245094715007229621094194349783925984760375594985848253359305585439638443"; const char *_default_g = "2"; const char *_iname_leaders = "=@+$!("; const char *_whitespace_chars = " \t\r\n"; } } libopkele-2.0.4+git20140305.9651b55/lib/discovery.cc000066400000000000000000000435241273462535700211120ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include "config.h" #include #define XRDS_HEADER "X-XRDS-Location" #define CT_HEADER "Content-Type" namespace opkele { using std::list; using xrd::XRD_t; using xrd::service_t; /* TODO: the whole discovery thing needs cleanup and optimization due to * many changes of concept. */ static const size_t max_html = 16384; static const struct service_type_t { const char *uri; const char *forceid; } op_service_types[] = { { STURI_OPENID20_OP, IDURI_SELECT20 }, { STURI_OPENID20, 0 }, { STURI_OPENID11, 0 }, { STURI_OPENID10, 0 } }; enum { st_index_1 = 2, st_index_2 = 1 }; static inline bool is_qelement(const XML_Char *n,const char *qen) { return !strcasecmp(n,qen); } static inline bool is_element(const XML_Char *n,const char *en) { if(!strcasecmp(n,en)) return true; int nl = strlen(n), enl = strlen(en); if( (nl>=(enl+1)) && n[nl-enl-1]=='\t' && !strcasecmp(&n[nl-enl],en) ) return true; return false; } static long element_priority(const XML_Char **a) { for(;*a;++a) if(!strcasecmp(*(a++),"priority")) { long rv; return (sscanf(*a,"%ld",&rv)==1)?rv:-1; } return -1; } /* TODO: ideally all attributes should be * retrieved in one run */ static const char *element_attr(const XML_Char **a, const char *at) { for(;*a;++a) if(!strcasecmp(*(a++),at)) { return *a; } return 0; } class idigger_t : public util::curl_t, public util::expat_t { public: string xri_proxy; enum { xmode_html = 1, xmode_xrd = 2, xmode_cid = 4, xmode_noredirs = 8 }; int xmode; string xrds_location; string http_content_type; service_t html_openid1; service_t html_openid2; string cdata_buf; long status_code; string status_string; typedef list pt_stack_t; pt_stack_t pt_stack; int skipping; bool parser_choked; string save_html; XRD_t *xrd; service_t *xrd_service; string* cdata; idigger_t() : util::curl_t(easy_init()), util::expat_t(0), xri_proxy(XRI_PROXY_URL) { CURLcode r; (r=misc_sets()) || (r=set_write()) || (r=set_header()) ; if(r) throw exception_curl(OPKELE_CP_ "failed to set curly options",r); } ~idigger_t() throw() { } void yadiscover(endpoint_discovery_iterator oi,const string& yurl,const char **types,bool redirs) { idiscovery_t idis; idis.xri_identity = false; discover_at(idis,yurl,xmode_html|xmode_xrd|(redirs?0:xmode_noredirs)); if(!xrds_location.empty()) { idis.clear(); discover_at(idis,xrds_location,xmode_xrd); } idis.normalized_id = idis.canonicalized_id = yurl; service_type_t st = { 0, 0 }; for(st.uri=*types;*types;st.uri=*(++types)) queue_endpoints(oi,idis,&st); } string discover(endpoint_discovery_iterator& oi,const string& identity) { string rv; idiscovery_t idis; string::size_type fsc = identity.find_first_not_of(data::_whitespace_chars); if(fsc==string::npos) throw bad_input(OPKELE_CP_ "whitespace-only identity"); string::size_type lsc = identity.find_last_not_of(data::_whitespace_chars); assert(lsc!=string::npos); if(!strncasecmp(identity.c_str()+fsc,"xri://",sizeof("xri://")-1)) fsc += sizeof("xri://")-1; if((fsc+1)>=lsc) throw bad_input(OPKELE_CP_ "not a character of importance in identity"); string id(identity,fsc,lsc-fsc+1); idis.clear(); if(strchr(data::_iname_leaders,id[0])) { /* TODO: further normalize xri identity? Like folding case * or whatever... */ rv = id; set cids; for(const struct service_type_t *st=op_service_types; st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) { idis.clear(); discover_at( idis, xri_proxy + util::url_encode(id)+ "?_xrd_t="+util::url_encode(st->uri)+ "&_xrd_r=application/xrd%2Bxml" ";sep=true;refs=true", xmode_xrd ); if(status_code==241) continue; if(status_code!=100) throw failed_xri_resolution(OPKELE_CP_ "XRI resolution failed with '"+status_string+"' message" ", while looking for SEP with type '"+st->uri+"'", status_code); if(idis.xrd.canonical_ids.empty()) throw opkele::failed_discovery(OPKELE_CP_ "No CanonicalID for XRI identity found"); string cid = idis.xrd.canonical_ids.begin()->second; if(cids.find(cid)==cids.end()) { cids.insert(cid); idis.clear(); discover_at( idis, xri_proxy + util::url_encode(id)+ "?_xrd_t="+util::url_encode(st->uri)+ "&_xrd_r=application/xrd%2Bxml" ";sep=true;refs=true", xmode_xrd ); if(status_code==241) continue; if(status_code!=100) throw failed_xri_resolution(OPKELE_CP_ "XRI resolution failed with '"+status_string+"' message" ", while looking for SEP with type '"+st->uri+"'" " on canonical id", status_code); } idis.canonicalized_id = cid; idis.normalized_id = rv; idis.xri_identity = true; queue_endpoints(oi,idis,st); } }else{ idis.xri_identity = false; if(id.find("://")==string::npos) id.insert(0,"http://"); string::size_type fp = id.find('#'); if(fp!=string::npos) { string::size_type qp = id.find('?'); if(qp==string::npos || qpfp) id.erase(fp,qp-fp); } rv = idis.normalized_id = util::rfc_3986_normalize_uri(id); discover_at(idis,id,xmode_html|xmode_xrd); const char * eu = 0; CURLcode r = easy_getinfo(CURLINFO_EFFECTIVE_URL,&eu); if(r) throw exception_curl(OPKELE_CP_ "failed to get CURLINFO_EFFECTIVE_URL",r); string cid = util::strip_uri_fragment_part( idis.canonicalized_id = util::rfc_3986_normalize_uri(eu) ); if(xrds_location.empty()) { if(idis.xrd.empty()) html2xrd(oi,idis); else{ for(const service_type_t *st=op_service_types; st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) queue_endpoints(oi,idis,st); } }else{ idis.clear(); idis.canonicalized_id = cid; discover_at(idis,xrds_location,xmode_xrd); if(idis.xrd.empty()) html2xrd(oi,idis); else{ for(const service_type_t *st=op_service_types; st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) queue_endpoints(oi,idis,st); } } } return rv; } void discover_at(idiscovery_t& idis,const string& url,int xm) { CURLcode r = easy_setopt(CURLOPT_MAXREDIRS, (xm&xmode_noredirs)?0:5); if(r) throw exception_curl(OPKELE_CP_ "failed to set curly maxredirs option"); if( (r=easy_setopt(CURLOPT_URL,url.c_str())) ) throw exception_curl(OPKELE_CP_ "failed to set curly urlie",r); http_content_type.clear(); xmode = xm; prepare_to_parse(); if(xmode&xmode_html) { xrds_location.clear(); save_html.clear(); save_html.reserve(max_html); } xrd = &idis.xrd; r = easy_perform(); if(r && r!=CURLE_WRITE_ERROR) throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); if(!parser_choked) { parse(0,0,true); }else if(xmode&xmode_html){ /* TODO: do not bother if we've seen xml */ try { util::tidy_doc_t td = util::tidy_doc_t::create(); if(!td) throw exception_tidy(OPKELE_CP_ "failed to create htmltidy document"); #ifdef NDEBUG td.opt_set(TidyQuiet,true); td.opt_set(TidyShowWarnings,false); #else /* NDEBUG */ td.opt_set(TidyQuiet,false); td.opt_set(TidyShowWarnings,true); #endif /* NDEBUG */ td.opt_set(TidyForceOutput,true); td.opt_set(TidyXhtmlOut,true); td.opt_set(TidyDoctypeMode,TidyDoctypeOmit); td.opt_set(TidyMark,false); td.opt_set(TidyNumEntities,true); if(td.parse_string(save_html)<=0) throw exception_tidy(OPKELE_CP_ "tidy failed to parse document"); if(td.clean_and_repair()<=0) throw exception_tidy(OPKELE_CP_ "tidy failed to clean and repair"); util::tidy_buf_t tide; if(td.save_buffer(tide)<=0) throw exception_tidy(OPKELE_CP_ "tidy failed to save buffer"); prepare_to_parse(); parse(tide.c_str(),tide.size(),true); }catch(exception_tidy& et) { } } save_html.clear(); } void prepare_to_parse() { (*(expat_t*)this) = parser_create_ns(); set_user_data(); set_element_handler(); set_character_data_handler(); set_unknown_encoding_handler(); if(xmode&xmode_html) { html_openid1.clear(); html_openid2.clear(); parser_choked = false; } cdata = 0; xrd_service = 0; skipping = 0; pt_stack.clear(); status_code = 100; status_string.clear(); } void html2xrd(endpoint_discovery_iterator& oi,idiscovery_t& id) { XRD_t& x = id.xrd; if(!html_openid2.uris.empty()) { html_openid2.types.insert(STURI_OPENID20); x.services.add(-1,html_openid2); queue_endpoints(oi,id,&op_service_types[st_index_2]); } if(!html_openid1.uris.empty()) { html_openid1.types.insert(STURI_OPENID11); x.services.add(-1,html_openid1); queue_endpoints(oi,id,&op_service_types[st_index_1]); } } size_t write(void *p,size_t s,size_t nm) { /* TODO: limit total size */ size_t bytes = s*nm; const char *inbuf = (const char*)p; if(xmode&xmode_html) { size_t mbts = save_html.capacity()-save_html.size(); size_t bts = 0; if(mbts>0) { bts = (bytes>mbts)?mbts:bytes; save_html.append(inbuf,bts); } if(skipping<0) return bts; } if(skipping<0) return 0; bool rp = parse(inbuf,bytes,false); if(!rp) { parser_choked = true; skipping = -1; if(!(xmode&xmode_html)) bytes = 0; } return bytes; } size_t header(void *p,size_t s,size_t nm) { size_t bytes = s*nm; const char *h = (const char*)p; const char *colon = (const char*)memchr(p,':',bytes); const char *space = (const char*)memchr(p,' ',bytes); if(space && ( (!colon) || space0 && isspace(*hv);++hv,--rb) ; while(rb>0 && isspace(hv[rb-1])) --rb; if(rb) { if( (hnl>=sizeof(XRDS_HEADER)) && !strncasecmp(h,XRDS_HEADER":", sizeof(XRDS_HEADER)) ) { xrds_location.assign(hv,rb); }else if( (hnl>=sizeof(CT_HEADER)) && !strncasecmp(h,CT_HEADER":", sizeof(CT_HEADER)) ) { const char *sc = (const char*)memchr( hv,';',rb); http_content_type.assign(hv,sc?(sc-hv):rb); } } } return curl_t::header(p,s,nm); } void start_element(const XML_Char *n,const XML_Char **a) { if(skipping<0) return; if(skipping) { if(xmode&xmode_html) html_start_element(n,a); ++skipping; return; } if(pt_stack.empty()) { if(is_qelement(n,NSURI_XRDS "\tXRDS")) return; if(is_qelement(n,NSURI_XRD "\tXRD")) { assert(xrd); xrd->clear(); pt_stack.push_back(n); }else if(xmode&xmode_html) { html_start_element(n,a); }else{ skipping = -1; } }else{ int pt_s = pt_stack.size(); if(pt_s==1) { if(is_qelement(n,NSURI_XRD "\tCanonicalID")) { assert(xrd); cdata = &(xrd->canonical_ids.add(element_priority(a),string())); }else if(is_qelement(n,NSURI_XRD "\tLocalID")) { assert(xrd); cdata = &(xrd->local_ids.add(element_priority(a),string())); }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { assert(xrd); cdata = &(xrd->provider_id); }else if(is_qelement(n,NSURI_XRD "\tService")) { assert(xrd); xrd_service = &(xrd->services.add(element_priority(a), service_t())); pt_stack.push_back(n); }else if(is_qelement(n,NSURI_XRD "\tStatus")) { for(;*a;) { if(!strcasecmp(*(a++),"code")) { if(sscanf(*(a++),"%ld",&status_code)==1 && status_code!=100) { cdata = &status_string; pt_stack.push_back(n); break; } }else ++a; } }else if(is_qelement(n,NSURI_XRD "\tExpires")) { assert(xrd); cdata_buf.clear(); cdata = &cdata_buf; }else if(xmode&xmode_html) { html_start_element(n,a); }else{ skipping = 1; } }else if(pt_s==2) { if(is_qelement(pt_stack.back().c_str(), NSURI_XRD "\tService")) { if(is_qelement(n,NSURI_XRD "\tType")) { assert(xrd); assert(xrd_service); cdata_buf.clear(); cdata = &cdata_buf; }else if(is_qelement(n,NSURI_XRD "\tURI")) { assert(xrd); assert(xrd_service); const char *append = element_attr(a,"append"); xrd::uri_t& uri = xrd_service->uris.add(element_priority(a),xrd::uri_t("",append?append:"")); cdata = &uri.uri; }else if(is_qelement(n,NSURI_XRD "\tLocalID") || is_qelement(n,NSURI_OPENID10 "\tDelegate") ) { assert(xrd); assert(xrd_service); cdata = &(xrd_service->local_ids.add(element_priority(a),string())); }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { assert(xrd); assert(xrd_service); cdata = &(xrd_service->provider_id); }else{ skipping = 1; } }else skipping = 1; }else if(xmode&xmode_html) { html_start_element(n,a); }else{ skipping = 1; } } } void end_element(const XML_Char *n) { if(skipping<0) return; if(skipping) { --skipping; return; } if(is_qelement(n,NSURI_XRD "\tType")) { if(xrd && xrd_service) { assert(cdata==&cdata_buf); xrd_service->types.insert(cdata_buf); } }else if(is_qelement(n,NSURI_XRD "\tService")) { if(!(xrd && xrd_service)) { skipping = -1; }else{ assert(!pt_stack.empty()); assert(pt_stack.back()==(NSURI_XRD "\tService")); pt_stack.pop_back(); xrd_service = 0; } }else if(is_qelement(n,NSURI_XRD "\tStatus")) { if(!xrd) { skipping=-1; }else{ if(is_qelement(pt_stack.back().c_str(),n)) { assert(cdata==&status_string); pt_stack.pop_back(); if(status_code!=100) skipping = -1; } } }else if(is_qelement(n,NSURI_XRD "\tExpires")) { if(!xrd) { skipping=-1; }else{ xrd->expires = util::w3c_to_time(cdata_buf); } }else if(is_qelement(n,NSURI_XRD "\tXRD")) { assert(!pt_stack.empty()); assert(pt_stack.back()==(NSURI_XRD "\tXRD")); pt_stack.pop_back(); }else if((xmode&xmode_html) && is_element(n,"head")) { skipping = -1; } cdata = 0; } void character_data(const XML_Char *s,int l) { if(skipping) return; if(cdata) cdata->append(s,l); } void html_start_element(const XML_Char *n,const XML_Char **a) { if(is_element(n,"meta")) { bool heq = false; string l; for(;*a;a+=2) { if(!( strcasecmp(a[0],"http-equiv") || strcasecmp(a[1],XRDS_HEADER) )) heq = true; else if(!strcasecmp(a[0],"content")) l.assign(a[1]); } if(heq) xrds_location = l; }else if(is_element(n,"link")) { string rels; string href; for(;*a;a+=2) { if( !strcasecmp(a[0],"rel") ) { rels.assign(a[1]); }else if( !strcasecmp(a[0],"href") ) { const char *ns = a[1]; for(;*ns && isspace(*ns);++ns) ; href.assign(ns); string::size_type lns=href.find_last_not_of(data::_whitespace_chars); href.erase(lns+1); } } for(string::size_type ns=rels.find_first_not_of(data::_whitespace_chars); ns!=string::npos; ns=rels.find_first_not_of(data::_whitespace_chars,ns)) { string::size_type s = rels.find_first_of(data::_whitespace_chars,ns); string rel; if(s==string::npos) { rel.assign(rels,ns,string::npos); ns = string::npos; }else{ rel.assign(rels,ns,s-ns); ns = s; } if(rel=="openid.server") html_openid1.uris.add(-1,xrd::uri_t(href)); else if(rel=="openid.delegate") html_openid1.local_ids.add(-1,href); else if(rel=="openid2.provider") html_openid2.uris.add(-1,xrd::uri_t(href)); else if(rel=="openid2.local_id") html_openid2.local_ids.add(-1,href); } }else if(is_element(n,"body")) { skipping = -1; } } void queue_endpoints(endpoint_discovery_iterator& oi, const idiscovery_t &id, const service_type_t *st) { openid_endpoint_t ep; ep.claimed_id = id.canonicalized_id; for(xrd::services_t::const_iterator isvc=id.xrd.services.begin(); isvc!=id.xrd.services.end(); ++isvc) { const xrd::service_t svc = isvc->second; if(svc.types.find(st->uri)==svc.types.end()) continue; for(xrd::uris_t::const_iterator iu=svc.uris.begin();iu!=svc.uris.end();++iu) { ep.uri = iu->second.uri; if(id.xri_identity) { if(iu->second.append=="qxri") { ep.uri += id.normalized_id; } /* TODO: else handle other append attribute values */ } if(st->forceid) { ep.local_id = ep.claimed_id = st->forceid; *(oi++) = ep; }else{ if(svc.local_ids.empty()) { ep.local_id = ep.claimed_id; *(oi++) = ep; }else{ for(xrd::local_ids_t::const_iterator ilid=svc.local_ids.begin(); ilid!=svc.local_ids.end(); ++ilid) { ep.local_id = ilid->second; *(oi++) = ep; } } } } } } int unknown_encoding(const XML_Char* /* n */,XML_Encoding *i) { for(unsigned int ii=0;ii < sizeof(i->map)/sizeof(i->map[0]);++ii) i->map[ii] = ii; i->convert = 0; i->release = 0; return XML_STATUS_OK; } }; string idiscover(endpoint_discovery_iterator oi,const string& identity) { idigger_t idigger; return idigger.discover(oi,identity); } void yadiscover(endpoint_discovery_iterator oi,const string& yurl,const char **types,bool redirs) try { idigger_t idigger; idigger.yadiscover(oi,yurl,types,redirs); }catch(exception_curl& ec) { if(redirs || ec._error!=CURLE_TOO_MANY_REDIRECTS) throw; } } libopkele-2.0.4+git20140305.9651b55/lib/exception.cc000066400000000000000000000024611273462535700210740ustar00rootroot00000000000000#include #include #include #include namespace opkele { # ifndef OPKELE_HAVE_KONFORKA exception::exception(const string& w) : _what(w) { DOUT_("throwing exception(\""< namespace opkele { namespace util { expat_t::~expat_t() throw() { if(_x) XML_ParserFree(_x); } expat_t& expat_t::operator=(XML_Parser x) { if(_x) XML_ParserFree(_x); _x = x; return *this; } static void _start_element(void* ud,const XML_Char *n,const XML_Char **a) { ((expat_t*)ud)->start_element(n,a); } static void _end_element(void *ud,const XML_Char *n) { ((expat_t*)ud)->end_element(n); } void expat_t::set_element_handler() { assert(_x); XML_SetElementHandler(_x,_start_element,_end_element); } static void _character_data(void *ud,const XML_Char *s,int l) { ((expat_t*)ud)->character_data(s,l); } void expat_t::set_character_data_handler() { assert(_x); XML_SetCharacterDataHandler(_x,_character_data); } static void _processing_instruction(void *ud,const XML_Char *t,const XML_Char *d) { ((expat_t*)ud)->processing_instruction(t,d); } void expat_t::set_processing_instruction_handler() { assert(_x); XML_SetProcessingInstructionHandler(_x,_processing_instruction); } static void _comment(void *ud,const XML_Char *d) { ((expat_t*)ud)->comment(d); } void expat_t::set_comment_handler() { assert(_x); XML_SetCommentHandler(_x,_comment); } static void _start_cdata_section(void *ud) { ((expat_t*)ud)->start_cdata_section(); } static void _end_cdata_section(void *ud) { ((expat_t*)ud)->end_cdata_section(); } void expat_t::set_cdata_section_handler() { assert(_x); XML_SetCdataSectionHandler(_x,_start_cdata_section,_end_cdata_section); } static void _default_handler(void *ud,const XML_Char *s,int l) { ((expat_t*)ud)->default_handler(s,l); } void expat_t::set_default_handler() { assert(_x); XML_SetDefaultHandler(_x,_default_handler); } void expat_t::set_default_handler_expand() { assert(_x); XML_SetDefaultHandlerExpand(_x,_default_handler); } static void _start_namespace_decl(void *ud,const XML_Char *p,const XML_Char *u) { ((expat_t*)ud)->start_namespace_decl(p,u); } static void _end_namespace_decl(void *ud,const XML_Char *p) { ((expat_t*)ud)->end_namespace_decl(p); } void expat_t::set_namespace_decl_handler() { assert(_x); XML_SetNamespaceDeclHandler(_x,_start_namespace_decl,_end_namespace_decl); } static int _unknown_encoding(void *ehd,const XML_Char *n,XML_Encoding *i) { return ((expat_t*)ehd)->unknown_encoding(n,i); } void expat_t::set_unknown_encoding_handler() { assert(_x); XML_SetUnknownEncodingHandler(_x,_unknown_encoding,this); } } } libopkele-2.0.4+git20140305.9651b55/lib/extension.cc000066400000000000000000000022421273462535700211070ustar00rootroot00000000000000#include #include namespace opkele { void extension_t::rp_checkid_hook(basic_openid_message&) { throw not_implemented(OPKELE_CP_ "RP checkid_* hook not implemented"); } void extension_t::rp_id_res_hook(const basic_openid_message&, const basic_openid_message&) { throw not_implemented(OPKELE_CP_ "RP id_res hook not implemented"); } void extension_t::op_checkid_hook(const basic_openid_message&) { throw not_implemented(OPKELE_CP_ "OP checkid_* hook not implemented"); } void extension_t::op_id_res_hook(basic_openid_message&) { throw not_implemented(OPKELE_CP_ "OP id_res hook not implemented"); } void extension_t::checkid_hook(basic_openid_message&) { throw not_implemented(OPKELE_CP_ "deprecated consumer checkid_* hook not implemented"); } void extension_t::id_res_hook(const basic_openid_message&, const basic_openid_message&) { throw not_implemented(OPKELE_CP_ "deprecated consumer id_res hook not implemented"); } void extension_t::checkid_hook(const basic_openid_message&,basic_openid_message&) { throw not_implemented(OPKELE_CP_ "deprecated server checkid hook not implemented"); } } libopkele-2.0.4+git20140305.9651b55/lib/extension_chain.cc000066400000000000000000000022311273462535700222470ustar00rootroot00000000000000#include #include namespace opkele { void extension_chain_t::rp_checkid_hook(basic_openid_message& om) { for(iterator i=begin();i!=end();++i) (*i)->rp_checkid_hook(om); } void extension_chain_t::rp_id_res_hook(const basic_openid_message& om, const basic_openid_message& sp) { for(iterator i=begin();i!=end();++i) (*i)->rp_id_res_hook(om,sp); } void extension_chain_t::op_checkid_hook(const basic_openid_message& inm) { for(iterator i=begin();i!=end();++i) (*i)->op_checkid_hook(inm); } void extension_chain_t::op_id_res_hook(basic_openid_message& oum) { for(iterator i=begin();i!=end();++i) (*i)->op_id_res_hook(oum); } void extension_chain_t::checkid_hook(basic_openid_message& om){ for(iterator i=begin();i!=end();++i) (*i)->checkid_hook(om); } void extension_chain_t::id_res_hook(const basic_openid_message& om, const basic_openid_message& sp) { for(iterator i=begin();i!=end();++i) (*i)->id_res_hook(om,sp); } void extension_chain_t::checkid_hook(const basic_openid_message& inm, basic_openid_message& oum) { for(iterator i=begin();i!=end();++i) (*i)->checkid_hook(inm,oum); } } libopkele-2.0.4+git20140305.9651b55/lib/fields.cc000066400000000000000000000044331273462535700203450ustar00rootroot00000000000000#include #include #include #include namespace opkele { using std::for_each; using std::unary_function; struct __om_copier : public unary_function { public: const basic_fields& from; basic_fields& to; __om_copier(basic_fields& t,const basic_fields& f) : from(f), to(t) { } result_type operator()(argument_type f) { to.set_field(f,from.get_field(f)); } }; basic_fields::basic_fields(const basic_fields& x) { x.copy_to(*this); } void basic_fields::copy_to(basic_fields& x) const { x.reset_fields(); for_each(fields_begin(),fields_end(), __om_copier(x,*this) ); } void basic_fields::append_to(basic_fields& x) const { for_each(fields_begin(),fields_end(), __om_copier(x,*this) ); } struct __om_query_builder : public unary_function { public: const basic_fields& om; bool first; string& rv; const char *pfx; __om_query_builder(const char *p,string& r,const basic_fields& m) : om(m), first(true), rv(r), pfx(p) { for_each(om.fields_begin(),om.fields_end(),*this); } __om_query_builder(const char *p,string& r,const basic_fields& m,const string& u) : om(m), first(true), rv(r), pfx(p) { rv = u; if(rv.find('?')==string::npos) rv += '?'; else first = false; for_each(om.fields_begin(),om.fields_end(),*this); } result_type operator()(argument_type f) { if(first) first = false; else rv += '&'; if(pfx) rv += pfx; rv+= f; rv += '='; rv += util::url_encode(om.get_field(f)); } }; string basic_fields::append_query(const string& url,const char *pfx) const { string rv; return __om_query_builder(pfx,rv,*this,url).rv; } string basic_fields::query_string(const char *pfx) const { string rv; return __om_query_builder(pfx,rv,*this).rv; } void basic_fields::reset_fields() { throw not_implemented(OPKELE_CP_ "reset_fields() not implemented"); } void basic_fields::set_field(const string&,const string&) { throw not_implemented(OPKELE_CP_ "set_field() not implemented"); } void basic_fields::reset_field(const string&) { throw not_implemented(OPKELE_CP_ "reset_field() not implemented"); } } libopkele-2.0.4+git20140305.9651b55/lib/message.cc000066400000000000000000000127221273462535700205230ustar00rootroot00000000000000#include #include #include #include #include #include #include "config.h" namespace opkele { using std::input_iterator_tag; using std::unary_function; struct __om_ns_finder : public unary_function { public: const basic_openid_message& om; const string& uri; __om_ns_finder(const basic_openid_message& m, const string& u) : om(m), uri(u) { } result_type operator()(argument_type f) { return (!strncmp(f.c_str(),"ns.",sizeof("ns.")-1)) && om.get_field(f)==uri ; } }; bool basic_openid_message::has_ns(const string& uri) const { fields_iterator ei = fields_end(); fields_iterator i = find_if(fields_begin(),fields_end(), __om_ns_finder(*this,uri)); return !(i==ei); } string basic_openid_message::get_ns(const string& uri) const { fields_iterator ei = fields_end(); fields_iterator i = find_if(fields_begin(),fields_end(), __om_ns_finder(*this,uri)); if(i==ei) throw failed_lookup(OPKELE_CP_ string("failed to find namespace ")+uri); return i->substr(3); } void basic_openid_message::from_keyvalues(const string& kv) { reset_fields(); string::size_type p = 0; while(true) { string::size_type co = kv.find(':',p); if(co==string::npos) break; #ifndef POSTELS_LAW string::size_type nl = kv.find('\n',co+1); if(nl==string::npos) throw bad_input(OPKELE_CP_ "malformed input"); if(nl>co) set_field(kv.substr(p,co-p),kv.substr(co+1,nl-co-1)); p = nl+1; #else /* POSTELS_LAW */ string::size_type lb = kv.find_first_of("\r\n",co+1); if(lb==string::npos) { set_field(kv.substr(p,co-p),kv.substr(co+1)); break; } if(lb>co) set_field(kv.substr(p,co-p),kv.substr(co+1,lb-co-1)); string::size_type nolb = kv.find_first_not_of("\r\n",lb); if(nolb==string::npos) break; p = nolb; #endif /* POSTELS_LAW */ } } struct __om_kv_outputter : public unary_function { public: const basic_openid_message& om; ostream& os; __om_kv_outputter(const basic_openid_message& m,ostream& s) : om(m), os(s) { } result_type operator()(argument_type f) { os << f << ':' << om.get_field(f) << '\n'; } }; void basic_openid_message::to_keyvalues(ostream& o) const { for_each(fields_begin(),fields_end(),__om_kv_outputter(*this,o)); } struct __om_html_outputter : public unary_function { public: const basic_openid_message& om; ostream& os; const char *pfx; __om_html_outputter(const basic_openid_message& m,ostream& s,const char *p=0) : om(m), os(s), pfx(p) { } result_type operator()(argument_type f) { os << ""; } }; void basic_openid_message::to_htmlhiddens(ostream& o,const char* pfx) const { for_each(fields_begin(),fields_end(),__om_html_outputter(*this,o,pfx)); } void basic_openid_message::add_to_signed(const string& fields) { string::size_type fnc = fields.find_first_not_of(","); if(fnc==string::npos) throw bad_input(OPKELE_CP_ "Trying to add nothing in particular to the list of signed fields"); string signeds; try { signeds = get_field("signed"); string::size_type lnc = signeds.find_last_not_of(","); if(lnc==string::npos) signeds.assign(fields,fnc,fields.size()-fnc); else{ string::size_type ss = signeds.size(); if(lnc==(ss-1)) { signeds+= ','; signeds.append(fields,fnc,fields.size()-fnc); }else{ if(lnc<(ss-2)) signeds.replace(lnc+2,ss-lnc-2, fields,fnc,fields.size()-fnc); else signeds.append(fields,fnc,fields.size()-fnc); } } }catch(failed_lookup&) { signeds.assign(fields,fnc,fields.size()-fnc); } set_field("signed",signeds); } string basic_openid_message::find_ns(const string& uri,const char *pfx) const { try { return get_ns(uri); }catch(failed_lookup&) { return pfx; } } string basic_openid_message::allocate_ns(const string& uri,const char *pfx) { if(!has_field("ns")) return pfx; if(has_ns(uri)) throw bad_input(OPKELE_CP_ "OpenID message already contains namespace"); string rv = pfx; if(has_field("ns."+rv)) { string::reference c=rv[rv.length()]; for(c='a';c<='z' && has_field("ns."+rv);++c) ; if(c=='z') throw exception(OPKELE_CP_ "Failed to allocate namespace"); } set_field("ns."+rv,uri); return rv; } bool openid_message_t::has_field(const string& n) const { return find(n)!=end(); } const string& openid_message_t::get_field(const string& n) const { const_iterator i=find(n); if(i==end()) throw failed_lookup(OPKELE_CP_ n+": no such field"); return i->second; } openid_message_t::fields_iterator openid_message_t::fields_begin() const { return util::map_keys_iterator(begin(),end()); } openid_message_t::fields_iterator openid_message_t::fields_end() const { return util::map_keys_iterator(end(),end()); } void openid_message_t::reset_fields() { clear(); } void openid_message_t::set_field(const string& n,const string& v) { (*this)[n]=v; } void openid_message_t::reset_field(const string& n) { erase(n); } } libopkele-2.0.4+git20140305.9651b55/lib/oauth_ext.cc000066400000000000000000000040411273462535700210720ustar00rootroot00000000000000#include #include #include #include namespace opkele { using std::find; void oauth_ext_t::rp_checkid_hook(basic_openid_message& om) { string pfx = om.allocate_ns(OIURI_OAUTH10,"oauth"); //required: openid.oauth.consumer=www.plaxo.com //optional: openid.oauth.scope=http://www.google.com/m8/feeds/ if (m_consumer.empty()) throw bad_input(OPKELE_CP_ "Required consumer key is missing from OAuth extension"); om.set_field(pfx+".consumer", m_consumer); if (!m_scope.empty()) om.set_field(pfx+".scope", m_scope); } void oauth_ext_t::checkid_hook(basic_openid_message& om) { rp_checkid_hook(om); } void oauth_ext_t::rp_id_res_hook(const basic_openid_message& om, const basic_openid_message& sp) { string pfx; try { pfx = om.get_ns(OIURI_OAUTH10); }catch(failed_lookup&) { return; } pfx += '.'; //required: openid.oauth.request_token=abcdefg //optional: openid.oauth.consumer=www.plaxo.com //optional: openid.oauth.scope=http://www.google.com/m8/feeds/ string fn; fn = pfx + "request_token"; if (sp.has_field(fn)) { m_request_token = sp.get_field(fn); } else throw bad_input(OPKELE_CP_ "Missing required response field: "+fn); fn = pfx + "consumer"; if (sp.has_field(fn)) { m_consumer = sp.get_field(fn); } fn = pfx + "scope"; if (sp.has_field(fn)) { m_scope = sp.get_field(fn); } } void oauth_ext_t::id_res_hook(const basic_openid_message& om, const basic_openid_message& sp) { rp_id_res_hook(om,sp); } void oauth_ext_t::op_checkid_hook(const basic_openid_message& inm) { } void oauth_ext_t::op_id_res_hook(basic_openid_message& oum) { } void oauth_ext_t::checkid_hook(const basic_openid_message& inm, basic_openid_message& oum) { op_checkid_hook(inm); setup_response(inm,oum); op_id_res_hook(oum); } void oauth_ext_t::setup_response(const basic_openid_message& /* inm */,basic_openid_message& /* oum */) { setup_response(); } void oauth_ext_t::setup_response() { } } libopkele-2.0.4+git20140305.9651b55/lib/params.cc000066400000000000000000000011441273462535700203560ustar00rootroot00000000000000#include #include #include #include #include #include "config.h" namespace opkele { using namespace std; 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(fields_iterator i=fields_begin();i!=fields_end();++i) { if(p) rv += '&'; else p = true; if(prefix) rv += prefix; rv += *i; rv += '='; rv += util::url_encode(get_field(*i)); } return rv; } } libopkele-2.0.4+git20140305.9651b55/lib/prequeue_rp.cc000066400000000000000000000046311273462535700214330ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include namespace opkele { class __OP_verifier_good_input : public exception { public: __OP_verifier_good_input(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; class OP_verifier : public iterator { public: const string& OP; const string& id; OP_verifier(const string& o,const string& i) : OP(o), id(i) { } OP_verifier& operator*() { return *this; } OP_verifier& operator=(const openid_endpoint_t& oep) { if(oep.uri==OP) { if(oep.claimed_id==IDURI_SELECT20 || oep.local_id==IDURI_SELECT20 ) throw bad_input(OPKELE_CP_ "claimed_id is an OP-Id"); if(oep.local_id==id) throw __OP_verifier_good_input(OPKELE_CP_ "Found corresponding endpoint"); } return *this; } OP_verifier& operator++() { return *this; } OP_verifier& operator++(int) { return *this; } }; void prequeue_RP::verify_OP(const string& OP,const string& _claimed_id,const string& id) const { try { discover(OP_verifier(OP,id),_claimed_id); throw id_res_unauthorized(OPKELE_CP_ "OP is not authorized to make an assertion regarding the identity"); }catch(__OP_verifier_good_input& ovgi) { } } class endpoint_queuer : public iterator { public: prequeue_RP& rp; endpoint_queuer(prequeue_RP& r) : rp(r) { } endpoint_queuer& operator*() { return *this; } endpoint_queuer& operator=(const openid_endpoint_t& oep) { rp.queue_endpoint(oep); return *this; } endpoint_queuer& operator++() { return *this; } endpoint_queuer& operator++(int) { return *this; } }; void prequeue_RP::initiate(const string& usi) { begin_queueing(); set_normalized_id( discover(endpoint_queuer(*this),usi) ); end_queueing(); } void prequeue_RP::set_normalized_id(const string&) { } const string prequeue_RP::get_normalized_id() const { throw not_implemented(OPKELE_CP_ "get_normalized_id() is not implemented"); } const string prequeue_RP::discover(openid_endpoint_output_iterator it, const string& id) const { return idiscover(it,id); } } libopkele-2.0.4+git20140305.9651b55/lib/secret.cc000066400000000000000000000021651273462535700203640ustar00rootroot00000000000000#include #include #include #include #include namespace opkele { using namespace std; template struct bitwise_xor : public binary_function<__a1,__a2,__r> { __r operator() (const __a1& a1,const __a2& a2) const { return (__r)(a1^a2); } }; void secret_t::enxor_to_base64(const unsigned char *key_d,string& rv) const { vector tmp; transform( begin(), end(), key_d, back_insert_iterator >(tmp), bitwise_xor() ); rv = util::encode_base64(&(tmp.front()),tmp.size()); } void secret_t::enxor_from_base64(const unsigned char *key_d,const string& b64) { clear(); util::decode_base64(b64,*this); transform( begin(), end(), key_d, begin(), bitwise_xor() ); } void secret_t::to_base64(string& rv) const { rv = util::encode_base64(&(front()),size()); } void secret_t::from_base64(const string& b64) { util::decode_base64(b64,*this); } } libopkele-2.0.4+git20140305.9651b55/lib/sreg.cc000066400000000000000000000105741273462535700200420ustar00rootroot00000000000000#include #include #include #include namespace opkele { using std::find; static const struct _sreg_field { const char *fieldname; sreg_t::fieldbit_t fieldbit; } fields[] = { { "nickname", sreg_t::field_nickname }, { "email", sreg_t::field_email }, { "fullname", sreg_t::field_fullname }, { "dob", sreg_t::field_dob }, { "gender", sreg_t::field_gender }, { "postcode", sreg_t::field_postcode }, { "country", sreg_t::field_country }, { "language", sreg_t::field_language }, { "timezone", sreg_t::field_timezone } }; # define fields_BEGIN fields # define fields_END &fields[sizeof(fields)/sizeof(*fields)] typedef const struct _sreg_field *fields_iterator; bool operator==(const struct _sreg_field& fd,const string& fn) { return fd.fieldname==fn; } void sreg_t::rp_checkid_hook(basic_openid_message& om) { string fr, fo; for(fields_iterator f=fields_BEGIN;ffieldbit&fields_required) { if(!fr.empty()) fr+=","; fr += f->fieldname; } if(f->fieldbit&fields_optional) { if(!fo.empty()) fo+=","; fo += f->fieldname; } } string pfx = om.allocate_ns(OIURI_SREG11,"sreg"); if(!fr.empty()) om.set_field(pfx+".required",fr); if(!fo.empty()) om.set_field(pfx+".optional",fo); if(!policy_url.empty()) om.set_field(pfx+".policy_url",policy_url); } void sreg_t::checkid_hook(basic_openid_message& om) { rp_checkid_hook(om); } void sreg_t::rp_id_res_hook(const basic_openid_message& om, const basic_openid_message& sp) { clear(); string pfx; try { pfx = om.find_ns(OIURI_SREG11,"sreg"); }catch(failed_lookup&) { try { pfx = om.find_ns(OIURI_SREG10,"sreg"); }catch(failed_lookup&) { return; } } pfx += '.'; for(fields_iterator f=fields_BEGIN;ffieldname; if(!sp.has_field(fn)) continue; has_fields |= f->fieldbit; response[f->fieldbit]=sp.get_field(fn); } } void sreg_t::id_res_hook(const basic_openid_message& om, const basic_openid_message& sp) { rp_id_res_hook(om,sp); } const string& sreg_t::get_field(fieldbit_t fb) const { response_t::const_iterator i = response.find(fb); if(i==response.end()) throw failed_lookup(OPKELE_CP_ "no field data available"); return i->second; } void sreg_t::set_field(fieldbit_t fb,const string& fv) { response[fb] = fv; has_fields |= fb; } void sreg_t::reset_field(fieldbit_t fb) { has_fields &= ~fb; response.erase(fb); } void sreg_t::clear() { has_fields = 0; response.clear(); } static long fields_list_to_bitmask(string& fl) { long rv = 0; while(!fl.empty()) { string::size_type co = fl.find(','); string fn; if(co==string::npos) { fn = fl; fl.erase(); }else{ fn = fl.substr(0,co); fl.erase(0,co+1); } fields_iterator f = find(fields_BEGIN,fields_END,fn); if(f!=fields_END) rv |= f->fieldbit; } return rv; } void sreg_t::op_checkid_hook(const basic_openid_message& inm) { string ins = inm.find_ns(OIURI_SREG11,"sreg"); fields_optional = 0; fields_required = 0; policy_url.erase(); fields_response = 0; try { string fl = inm.get_field(ins+".required"); fields_required = fields_list_to_bitmask(fl); }catch(failed_lookup&) { } try { string fl = inm.get_field(ins+".optional"); fields_optional = fields_list_to_bitmask(fl); }catch(failed_lookup&) { } try { policy_url = inm.get_field(ins+".policy_url"); }catch(failed_lookup&) { } } void sreg_t::op_id_res_hook(basic_openid_message& oum) { string ons = oum.allocate_ns(OIURI_SREG11,"sreg"); fields_response &= has_fields; string signeds = "ns."+ons; for(fields_iterator f=fields_BEGIN;ffieldbit&fields_response)) continue; signeds +=','; string pn = ons; pn += '.'; pn += f->fieldname; signeds += pn; oum.set_field(pn,get_field(f->fieldbit)); } oum.add_to_signed(signeds); } void sreg_t::checkid_hook(const basic_openid_message& inm, basic_openid_message& oum) { op_checkid_hook(inm); setup_response(inm,oum); op_id_res_hook(oum); } void sreg_t::setup_response(const basic_openid_message& /* inm */,basic_openid_message& /* oum */) { setup_response(); } void sreg_t::setup_response() { fields_response = (fields_required|fields_optional)&has_fields; } } libopkele-2.0.4+git20140305.9651b55/lib/util.cc000066400000000000000000000341641273462535700200600ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEMANGLE # include #endif namespace opkele { using namespace std; namespace util { /* * base64 */ string encode_base64(const void *data,size_t length) { BIO *b64 = 0, *bmem = 0; try { b64 = BIO_new(BIO_f_base64()); if(!b64) throw exception_openssl(OPKELE_CP_ "failed to BIO_new() base64 encoder"); BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL); bmem = BIO_new(BIO_s_mem()); BIO_set_flags(b64,BIO_CLOSE); if(!bmem) throw exception_openssl(OPKELE_CP_ "failed to BIO_new() memory buffer"); BIO_push(b64,bmem); if(((size_t)BIO_write(b64,data,length))!=length) throw exception_openssl(OPKELE_CP_ "failed to BIO_write()"); if(BIO_flush(b64)!=1) throw exception_openssl(OPKELE_CP_ "failed to BIO_flush()"); char *rvd; long rvl = BIO_get_mem_data(bmem,&rvd); string rv(rvd,rvl); BIO_free_all(b64); return rv; }catch(...) { if(b64) BIO_free_all(b64); throw; } } void decode_base64(const string& data,vector& rv) { BIO *b64 = 0, *bmem = 0; rv.clear(); try { bmem = BIO_new_mem_buf((void*)data.data(),data.size()); if(!bmem) throw exception_openssl(OPKELE_CP_ "failed to BIO_new_mem_buf()"); b64 = BIO_new(BIO_f_base64()); if(!b64) throw exception_openssl(OPKELE_CP_ "failed to BIO_new() base64 decoder"); BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL); BIO_push(b64,bmem); unsigned char tmp[512]; size_t rb = 0; while((rb=BIO_read(b64,tmp,sizeof(tmp)))>0) rv.insert(rv.end(),tmp,&tmp[rb]); BIO_free_all(b64); }catch(...) { if(b64) BIO_free_all(b64); throw; } } /* * big numerics */ BIGNUM *base64_to_bignum(const string& b64) { vector bin; decode_base64(b64,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 bin(BN_num_bytes(bn)+1); unsigned char *binptr = &(bin.front())+1; int l = BN_bn2bin(bn,binptr); if(l && (*binptr)&0x80){ (*(--binptr)) = 0; ++l; } return encode_base64(binptr,l); } /* * 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; } #ifndef HAVE_TIMEGM static time_t timegm(struct tm *t) { char *tz = getenv("TZ"); setenv("TZ","",1); tzset(); time_t rv = mktime(t); if(tz) setenv("TZ",tz,1); else unsetenv("TZ"); tzset(); return rv; } # define timegm opkele::util::timegm #endif /* HAVE_TIMEGM */ time_t w3c_to_time(const string& w) { int fraction; 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 ) && ( sscanf( w.c_str(), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", &tm_t.tm_year,&tm_t.tm_mon,&tm_t.tm_mday, &tm_t.tm_hour,&tm_t.tm_min,&tm_t.tm_sec, &fraction ) != 7 ) ) throw failed_conversion(OPKELE_CP_ "failed to sscanf()"); tm_t.tm_mon--; tm_t.tm_year-=1900; time_t rv = timegm(&tm_t); if(rv==(time_t)-1) throw failed_conversion(OPKELE_CP_ "failed to gmtime()"); return rv; } /* * */ static inline bool isrfc3986unreserved(int c) { if(c<'-') return false; if(c<='.') return true; if(c<'0') return false; if(c<='9') return true; if(c<'A') return false; if(c<='Z') return true; if(c<'_') return false; if(c=='_') return true; if(c<'a') return false; if(c<='z') return true; if(c=='~') return true; return false; } struct __url_encoder : public unary_function { public: string& rv; __url_encoder(string& r) : rv(r) { } result_type operator()(argument_type c) { if(isrfc3986unreserved(c)) rv += c; else{ char tmp[4]; snprintf(tmp,sizeof(tmp),"%%%02X", (c&0xff)); rv += tmp; } } }; string url_encode(const string& str) { string rv; for_each(str.begin(),str.end(), __url_encoder(rv)); return rv; } string url_decode(const string& str) { string rv; back_insert_iterator ii(rv); char tmp[3]; tmp[2] = 0; for(string::const_iterator i=str.begin(),ie=str.end(); i!=ie;++i) { switch(*i) { case '+': *(ii++) = ' '; break; case '%': if((++i)==ie) throw failed_conversion(OPKELE_CP_ "trailing percent in the url-encoded string"); tmp[0] = *i; if((++i)==ie) throw failed_conversion(OPKELE_CP_ "not enough hexadecimals after the percent sign in url-encoded string"); tmp[1] = *i; if(!(isxdigit(tmp[0]) && isxdigit(tmp[1]))) throw failed_conversion(OPKELE_CP_ "non-hex follows percent in url-encoded string"); *(ii++) = (char)strtol(tmp,0,16); break; default: *(ii++) = *i; break; } } return rv; } string attr_escape(const string& str) { static const char *unsafechars = "<>&\n\"'"; string rv; string::size_type p=0; while(true) { string::size_type us = str.find_first_of(unsafechars,p); if(us==string::npos) { if(p!=str.length()) rv.append(str,p,str.length()-p); return rv; } rv.append(str,p,us-p); rv += "&#"; rv += long_to_string((long)str[us]); rv += ';'; p = us+1; } } string long_to_string(long l) { char rv[32]; int r=snprintf(rv,sizeof(rv),"%ld",l); if(r<0 || r>=(int)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; } /* * Normalize URL according to the rules, described in rfc 3986, section 6 * * - uppercase hex triplets (e.g. %ab -> %AB) * - lowercase scheme and host * - decode %-encoded characters, specified as unreserved in rfc 3986, section 2.3, * that is - [:alpha:][:digit:]._~- * - remove dot segments * - remove empty and default ports * - if there's no path component, add '/' */ string rfc_3986_normalize_uri(const string& uri) { string rv; string::size_type ns = uri.find_first_not_of(data::_whitespace_chars); if(ns==string::npos) throw bad_input(OPKELE_CP_ "Can't normalize empty URI"); string::size_type colon = uri.find(':',ns); if(colon==string::npos) throw bad_input(OPKELE_CP_ "No scheme specified in URI"); transform( uri.begin()+ns, uri.begin()+colon+1, back_inserter(rv), ::tolower ); bool s; string::size_type ul = uri.find_last_not_of(data::_whitespace_chars)+1; if(ul <= (colon+3)) throw bad_input(OPKELE_CP_ "Unexpected end of URI being normalized encountered"); if(uri[colon+1]!='/' || uri[colon+2]!='/') throw bad_input(OPKELE_CP_ "Unexpected input in URI being normalized after scheme component"); if(rv=="http:") s = false; else if(rv=="https:") s = true; else{ /* TODO: support more schemes. e.g. xri. How do we normalize * xri? */ rv.append(uri,colon+1,ul-colon-1); return rv; } rv += "//"; string::size_type interesting = uri.find_first_of(":/#?",colon+3); if(interesting==string::npos) { transform( uri.begin()+colon+3,uri.begin()+ul, back_inserter(rv), ::tolower ); rv += '/'; return rv; } transform( uri.begin()+colon+3,uri.begin()+interesting, back_inserter(rv), ::tolower ); bool qf = false; char ic = uri[interesting]; if(ic==':') { string::size_type ni = uri.find_first_of("/#?%",interesting+1); const char *nptr = uri.data()+interesting+1; char *eptr = 0; long port = strtol(nptr,&eptr,10); if( (port>0) && (port<65535) && port!=(s?443:80) ) { char tmp[8]; snprintf(tmp,sizeof(tmp),":%ld",port); rv += tmp; } if(ni==string::npos) { rv += '/'; return rv; } interesting = ni; }else if(ic!='/') { rv += '/'; rv += ic; qf = true; ++interesting; } string::size_type n = interesting; char tmp[3] = { 0,0,0 }; stack psegs; psegs.push(rv.length()); string pseg; for(;n=ul) throw bad_input(OPKELE_CP_ "Unexpected end of URI encountered while parsing percent-encoded character"); tmp[0] = uri[n++]; tmp[1] = uri[n++]; if(!( isxdigit(tmp[0]) && isxdigit(tmp[1]) )) throw bad_input(OPKELE_CP_ "Invalid percent-encoded character in URI being normalized"); int cc = strtol(tmp,0,16); if( isalpha(cc) || isdigit(cc) || strchr("._~-",cc) ) pseg += (char)cc; else{ pseg += '%'; pseg += (char)toupper(tmp[0]); pseg += (char)toupper(tmp[1]); } }else if(qf) { rv += pseg; rv += c; pseg.clear(); }else if(n>=ul || strchr("?/#",c)) { if( (unsafe!=string::npos && pseg.empty()) || pseg==".") { }else if(pseg=="..") { if(psegs.size()>1) { rv.resize(psegs.top()); psegs.pop(); } }else{ psegs.push(rv.length()); if(c!='/') { pseg += c; qf = true; } rv += '/'; rv += pseg; } if(c=='/' && (n>=ul || strchr("?#",uri[n])) ) { rv += '/'; if(n mp = mismatch( nrealm.c_str()+pr,nrealm.c_str()+lr, nu.c_str()+pu); if( (*(mp.first-1))!='/' && !strchr("/?#",*mp.second) ) return false; return true; } string abi_demangle(const char *mn) { #ifndef HAVE_DEMANGLE return mn; #else /* !HAVE_DEMANGLE */ int dstat; char *demangled = abi::__cxa_demangle(mn,0,0,&dstat); if(dstat) return mn; string rv = demangled; free(demangled); return rv; #endif /* !HAVE_DEMANGLE */ } string base64_signature(const assoc_t& assoc,const basic_openid_message& om) { const string& slist = om.get_field("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 += ':'; kv += om.get_field(f); kv += '\n'; if(co==string::npos) break; p = co+1; } const secret_t& secret = assoc->secret(); const EVP_MD *evpmd; const string& at = assoc->assoc_type(); if(at=="HMAC-SHA256") evpmd = EVP_sha256(); else if(at=="HMAC-SHA1") evpmd = EVP_sha1(); else throw unsupported(OPKELE_CP_ "unknown association type"); unsigned int md_len = 0; unsigned char md[SHA256_DIGEST_LENGTH]; HMAC(evpmd, &(secret.front()),secret.size(), (const unsigned char*)kv.data(),kv.length(), md,&md_len); return encode_base64(md,md_len); } string normalize_identifier(const string& usi,bool strip_fragment) { if(usi.empty()) return usi; string rv; string::size_type fsc = usi.find_first_not_of(data::_whitespace_chars); if(fsc==string::npos) return rv; string::size_type lsc = usi.find_last_not_of(data::_whitespace_chars); assert(lsc!=string::npos); if(!strncasecmp(usi.c_str()+fsc,"xri://",sizeof("xri://")-1)) fsc += sizeof("xri://")-1; if( (fsc+1) >= lsc ) return rv; rv.assign(usi,fsc,lsc-fsc+1); if(strchr(data::_iname_leaders,rv[0])) { /* TODO: further normalize xri identity, fold case or * whatever... */ }else{ if(rv.find("://")==string::npos) rv.insert(0,"http://"); if(strip_fragment) { string::size_type fp = rv.find('#'); if(fp!=string::npos) { string::size_type qp = rv.find('?'); if(qp==string::npos || qpfp) rv.erase(fp,qp-fp); } } rv = rfc_3986_normalize_uri(rv); } return rv; } } } libopkele-2.0.4+git20140305.9651b55/lib/verify_op.cc000066400000000000000000000027601273462535700211020ustar00rootroot00000000000000#include #include #include #include #include namespace opkele { using std::output_iterator_tag; class __RP_verifier_good_input : public exception { public: __RP_verifier_good_input(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; class RP_verifier : public iterator { public: const string& return_to; int seen; RP_verifier(const string& rt) : return_to(rt), seen(0) { } RP_verifier& operator*() { return *this; } RP_verifier& operator=(const openid_endpoint_t& oep) { if(util::uri_matches_realm(return_to,oep.uri)) throw __RP_verifier_good_input(OPKELE_CP_ "Found matching realm"); return *this; } RP_verifier& operator++() { ++seen; return *this; } RP_verifier& operator++(int) { ++seen; return *this; } }; void verify_OP::verify_return_to() { basic_OP::verify_return_to(); try { RP_verifier rpv(return_to); string drealm = realm; string::size_type csss = drealm.find("://*."); if(csss==4 || csss==5) drealm.replace(csss+3,1,"www"); const char *rtt[] = { STURI_OPENID20_RT, 0 }; yadiscover(rpv,drealm,rtt,false); if(rpv.seen) throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match any found while doing discovery on RP"); }catch(__RP_verifier_good_input&) { }catch(bad_return_to& brt) { throw; }catch(exception_network&) { } } } libopkele-2.0.4+git20140305.9651b55/libopkele.pc.in000066400000000000000000000005411273462535700207150ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libopkele Description: C++ implementation of OpenID protocol Version: @VERSION@ Requires: openssl @KONFORKA_KONFORKA@ @UUID_UUID@ Cflags: -I${includedir} @LIBCURL_CPPFLAGS@ @EXPAT_CFLAGS@ @TIDY_CFLAGS@ Libs: -L${libdir} -lopkele @LIBCURL@ @EXPAT_LIBS@ @TIDY_LIBS@ libopkele-2.0.4+git20140305.9651b55/libopkele.spec000066400000000000000000000036251273462535700206460ustar00rootroot00000000000000Summary: a c++ implementation of an OpenID decentralized identity system Name: libopkele Version: 2.0.4 Release: 1 License: MIT URL: http://kin.klever.net/libopkele/ Source0: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-root BuildRequires: expat-devel BuildRequires: gcc-c++ BuildRequires: libcurl-devel BuildRequires: libtidy-devel BuildRequires: openssl-devel %description libopkele is a c++ implementation of an OpenID decentralized identity system. It provides OpenID protocol handling, leaving authentication and user interaction to the implementor. %prep %setup -q %build %configure make %{?_smp_mflags} %install rm -rf %{buildroot} make install DESTDIR=%{buildroot} %clean rm -rf %{buildroot} %post -p /sbin/ldconfig %postun -p /sbin/ldconfig %files %defattr(-,root,root,-) %{_libdir}/libopkele.a %{_libdir}/libopkele.la %{_libdir}/libopkele.so %{_libdir}/libopkele.so.3 %{_libdir}/libopkele.so.3.0.0 %{_libdir}/pkgconfig/libopkele.pc %package devel Summary: Development headers for libopkele Requires: %{name}%{?_isa} = %{version}-%{release} %description devel libopkele is a c++ implementation of an OpenID decentralized identity system. It provides OpenID protocol handling, leaving authentication and user interaction to the implementor. %files devel %defattr(-,root,root,-) %dir %{_includedir}/opkele %{_includedir}/opkele/acconfig.h %{_includedir}/opkele/association.h %{_includedir}/opkele/ax.h %{_includedir}/opkele/basic_op.h %{_includedir}/opkele/basic_rp.h %{_includedir}/opkele/exception.h %{_includedir}/opkele/extension.h %{_includedir}/opkele/extension_chain.h %{_includedir}/opkele/iterator.h %{_includedir}/opkele/oauth_ext.h %{_includedir}/opkele/opkele-config.h %{_includedir}/opkele/prequeue_rp.h %{_includedir}/opkele/sreg.h %{_includedir}/opkele/tr1-mem.h %{_includedir}/opkele/types.h %{_includedir}/opkele/uris.h %{_includedir}/opkele/util.h %{_includedir}/opkele/verify_op.h libopkele-2.0.4+git20140305.9651b55/test/000077500000000000000000000000001273462535700167755ustar00rootroot00000000000000libopkele-2.0.4+git20140305.9651b55/test/.gitignore000066400000000000000000000001071273462535700207630ustar00rootroot00000000000000/.deps /.libs /test *.o /idiscover /RP.cgi /RP-db.cc /OP.cgi /OP-db.cc libopkele-2.0.4+git20140305.9651b55/test/Makefile.am000066400000000000000000000024261273462535700210350ustar00rootroot00000000000000noinst_PROGRAMS = test idiscover \ ${_dependent_programs_} AM_CPPFLAGS=${CPPFLAGS_DEBUG} DEFAULT_INCLUDES = -I${top_builddir} INCLUDES = -I${top_srcdir}/test/ -I${top_builddir}/include/ -I${top_srcdir}/include/ ${KONFORKA_CFLAGS} ${LIBCURL_CPPFLAGS} test_SOURCES = test.cc test_LDADD = ${top_builddir}/lib/libopkele.la EXTRA_DIST= \ sqlite.h kingate_openid_message.h \ RP-db.sql OP-db.sql idiscover_SOURCES = idiscover.cc idiscover_LDADD = ${top_builddir}/lib/libopkele.la if HAVE_SQLITE3 if HAVE_KINGATE if HAVE_UUID _dependent_programs_ = RP.cgi OP.cgi RP_cgi_SOURCES = RP.cc nodist_RP_cgi_SOURCES = RP-db.cc RP_cgi_LDADD = ${top_builddir}/lib/libopkele.la \ ${SQLITE3_LIBS} ${KINGATE_LIBS} ${UUID_LIBS} RP_cgi_CFLAGS = ${SQLITE3_CFLAGS} ${KINGATE_CFLAGS} ${UUID_CFLAGS} RP-db.cc: RP-db.sql ( \ echo 'const char * __RP_db_bootstrap = ' && \ sed -e 's/^/"/' -e 's/$$/"/' $< && \ echo ';' \ ) >$@ OP_cgi_SOURCES = OP.cc nodist_OP_cgi_SOURCES = OP-db.cc OP_cgi_LDADD = ${RP_cgi_LDADD} OP_cgi_CFLAGS = ${RP_cgi_CFLAGS} OP-db.cc: OP-db.sql ( \ echo 'const char * __OP_db_bootstrap = ' && \ sed -e 's/^/"/' -e 's/$$/"/' $< && \ echo ';' \ ) >$@ clean-local: rm -f RP-db.cc OP-db.cc endif #HAVE_UUID endif #HAVE_KINGATE endif #HAVE_SQLITE3 libopkele-2.0.4+git20140305.9651b55/test/OP-db.sql000066400000000000000000000007331273462535700204220ustar00rootroot00000000000000CREATE TABLE assoc ( a_op text, a_handle text NOT NULL, a_type text DEFAULT 'HMAC-SHA1', a_ctime text NOT NULL, a_etime text NOT NULL, a_secret text NOT NULL, a_stateless integer NOT NULL DEFAULT 0, a_itime integer, UNIQUE(a_op,a_handle) ); CREATE TABLE nonces ( n_once text NOT NULL PRIMARY KEY, n_itime integer ); CREATE TABLE setup ( s_password text ); CREATE TABLE ht_sessions ( hts_id text NOT NULL PRIMARY KEY, authorized integer NOT NULL DEFAULT 0 ); libopkele-2.0.4+git20140305.9651b55/test/OP.cc000066400000000000000000000276551273462535700176410ustar00rootroot00000000000000#include #include #include #include using namespace std; #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #ifdef HAVE_EXT_ALGORITHM_H # include #endif #include "sqlite.h" #include "kingate_openid_message.h" static const string get_self_url(const kingate::cgi_gateway& gw) { bool s = gw.has_meta("SSL_PROTOCOL_VERSION"); string rv = s?"https://":"http://"; rv += gw.http_request_header("Host"); const string& port = gw.get_meta("SERVER_PORT"); if( port!=(s?"443":"80") ) { rv += ':'; rv += port; } rv += gw.get_meta("REQUEST_URI"); string::size_type q = rv.find('?'); if(q!=string::npos) rv.erase(q); return rv; } class opdb_t : public sqlite3_t { public: opdb_t() : sqlite3_t("/tmp/OP.db") { assert(_D); char **resp; int nr,nc; char *errm; if(sqlite3_get_table( _D, "SELECT a_op FROM assoc LIMIT 0", &resp,&nr,&nc,&errm)!=SQLITE_OK) { extern const char *__OP_db_bootstrap; DOUT_("Bootstrapping DB"); if(sqlite3_exec(_D,__OP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK) throw opkele::exception(OPKELE_CP_ string("Failed to boostrap SQLite database: ")+errm); }else sqlite3_free_table(resp); } }; class example_op_t : public opkele::verify_OP { public: kingate::cgi_gateway& gw; opdb_t db; kingate::cookie htc; example_op_t(kingate::cgi_gateway& g) : gw(g) { try { htc = gw.cookies.get_cookie("htop_session"); sqlite3_mem_t S = sqlite3_mprintf( "SELECT 1 FROM ht_sessions WHERE hts_id=%Q", htc.get_value().c_str()); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); if(nr<1) throw kingate::exception_notfound(CODEPOINT,"forcing cookie generation"); }catch(kingate::exception_notfound& kenf) { uuid_t uuid; uuid_generate(uuid); htc = kingate::cookie("htop_session",opkele::util::encode_base64(uuid,sizeof(uuid))); sqlite3_mem_t S = sqlite3_mprintf( "INSERT INTO ht_sessions (hts_id) VALUES (%Q)", htc.get_value().c_str()); db.exec(S); } } void set_authorized(bool a) { sqlite3_mem_t S = sqlite3_mprintf( "UPDATE ht_sessions" " SET authorized=%d" " WHERE hts_id=%Q", (int)a,htc.get_value().c_str()); db.exec(S); } bool get_authorized() { sqlite3_mem_t S = sqlite3_mprintf( "SELECT authorized" " FROM ht_sessions" " WHERE hts_id=%Q", htc.get_value().c_str()); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); assert(nr==1); assert(nc=1); return opkele::util::string_to_long(T.get(1,0,nc)); } ostream& cookie_header(ostream& o) const { o << "Set-Cookie: " << htc.set_cookie_header() << "\n"; return o; } opkele::assoc_t alloc_assoc(const string& type,size_t klength,bool sl) { uuid_t uuid; uuid_generate(uuid); string a_handle = opkele::util::encode_base64(uuid,sizeof(uuid)); opkele::secret_t a_secret; generate_n( back_insert_iterator(a_secret),klength, rand ); string ssecret; a_secret.to_base64(ssecret); time_t now = time(0); int expires_in = sl?3600*2:3600*24*7*2; sqlite3_mem_t S = sqlite3_mprintf( "INSERT INTO assoc" " (a_handle,a_type,a_ctime,a_etime,a_secret,a_stateless)" " VALUES (" " %Q,%Q,datetime('now')," " datetime('now','+%d seconds')," " %Q,%d );", a_handle.c_str(), type.c_str(), expires_in, ssecret.c_str(), sl ); db.exec(S); return opkele::assoc_t(new opkele::association( "", a_handle, type, a_secret, now+expires_in, sl )); } opkele::assoc_t retrieve_assoc(const string& h) { sqlite3_mem_t S = sqlite3_mprintf( "SELECT" " a_handle,a_type,a_secret,a_stateless," " strftime('%%s',a_etime) AS a_etime," " a_itime" " FROM assoc" " WHERE a_handle=%Q AND a_itime IS NULL" " AND datetime('now') < a_etime" " LIMIT 1", h.c_str() ); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); if(nr<1) throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid unexpired assoc"); assert(nr==1); assert(nc==6); opkele::secret_t secret; opkele::util::decode_base64(T.get(1,2,nc),secret); return opkele::assoc_t(new opkele::association( "", h, T.get(1,1,nc), secret, strtol(T.get(1,4,nc),0,0), strtol(T.get(1,3,nc),0,0) )); } string& alloc_nonce(string& nonce) { uuid_t uuid; uuid_generate(uuid); nonce += opkele::util::encode_base64(uuid,sizeof(uuid)); sqlite3_mem_t S = sqlite3_mprintf( "INSERT INTO nonces" " (n_once) VALUES (%Q)", nonce.c_str() ); db.exec(S); return nonce; } bool check_nonce(const string& nonce) { sqlite3_mem_t S = sqlite3_mprintf( "SELECT 1" " FROM nonces" " WHERE n_once=%Q AND n_itime IS NULL", nonce.c_str()); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); return nr>=1; } void invalidate_nonce(const string& nonce) { sqlite3_mem_t S = sqlite3_mprintf( "UPDATE nonces" " SET n_itime=datetime('now')" " WHERE n_once=%Q", nonce.c_str()); db.exec(S); } const string get_op_endpoint() const { return get_self_url(gw); } }; int main(int,char **) { try { kingate::plaincgi_interface ci; kingate::cgi_gateway gw(ci); string op; try { op = gw.get_param("op"); }catch(kingate::exception_notfound&) { } string message; if(op=="set_password") { example_op_t OP(gw); string password = gw.get_param("password"); sqlite3_mem_t Sget = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1"); sqlite3_table_t T; int nr,nc; OP.db.get_table(Sget,T,&nr,&nc); if(nr>=1) throw opkele::exception(OPKELE_CP_ "Password already set"); sqlite3_mem_t Sset = sqlite3_mprintf( "INSERT INTO setup (s_password) VALUES (%Q)", password.c_str()); OP.db.exec(Sset); op.clear(); message = "password set"; }else if(op=="login") { example_op_t OP(gw); string password = gw.get_param("password"); sqlite3_mem_t Sget = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1"); sqlite3_table_t T; int nr,nc; OP.db.get_table(Sget,T,&nr,&nc); if(nr<1) throw opkele::exception(OPKELE_CP_ "no password set"); if(password!=T.get(1,0,nc)) throw opkele::exception(OPKELE_CP_ "wrong password"); OP.set_authorized(true); op.clear(); message = "logged in"; OP.cookie_header(cout); }else if(op=="logout") { example_op_t OP(gw); OP.set_authorized(false); op.clear(); message = "logged out"; } string omode; try { omode = gw.get_param("openid.mode"); }catch(kingate::exception_notfound&) { } if(op=="xrds") { cout << "Content-type: application/xrds+xml\n\n" "" "" "" "" "" STURI_OPENID20 "" "" << get_self_url(gw) << "" ""; if(gw.has_param("idsel")){ cout << "" "" STURI_OPENID20_OP "" "" << get_self_url(gw) << ""; } cout << "" ""; }else if(op=="id_res" || op=="cancel") { kingate_openid_message_t inm(gw); example_op_t OP(gw); if(gw.get_param("hts_id")!=OP.htc.get_value()) throw opkele::exception(OPKELE_CP_ "toying around, huh?"); opkele::sreg_t sreg; OP.checkid_(inm,sreg); OP.cookie_header(cout); opkele::openid_message_t om; if(op=="id_res") { if(!OP.get_authorized()) throw opkele::exception(OPKELE_CP_ "not logged in"); if(OP.is_id_select()) { OP.select_identity( get_self_url(gw), get_self_url(gw) ); } sreg.set_field(opkele::sreg_t::field_nickname,"anonymous"); sreg.set_field(opkele::sreg_t::field_fullname,"Ann O'Nymus"); sreg.set_field(opkele::sreg_t::field_gender,"F"); sreg.setup_response(); cout << "Status: 302 Going back to RP with id_res\n" "Location: " << OP.id_res(om,sreg).append_query(OP.get_return_to()) << "\n\n"; }else{ cout << "Status: 302 Going back to RP with cancel\n" "Location: " << OP.cancel(om).append_query(OP.get_return_to()) << "\n\n"; } om.to_keyvalues(clog); }else if(omode=="associate") { kingate_openid_message_t inm(gw); opkele::openid_message_t oum; example_op_t OP(gw); OP.associate(oum,inm); cout << "Content-type: text/plain\n\n"; oum.to_keyvalues(cout); }else if(omode=="checkid_setup") { kingate_openid_message_t inm(gw); example_op_t OP(gw); OP.checkid_(inm,0); OP.cookie_header(cout) << "Content-type: text/html\n" "\n" "" "" "test OP: confirm authentication" "" "" "realm: " << OP.get_realm() << "
" "return_to: " << OP.get_return_to() << "
" "claimed_id: " << OP.get_claimed_id() << "
" "identity: " << OP.get_identity() << "
"; if(OP.is_id_select()) { OP.select_identity( get_self_url(gw), get_self_url(gw) ); cout << "selected claimed_id: " << OP.get_claimed_id() << "
" "selected identity: " << OP.get_identity() << "
"; } cout << "
"; inm.to_htmlhiddens(cout); cout << "" "" "" "
" "" ""; }else if(omode=="check_authentication") { kingate_openid_message_t inm(gw); example_op_t OP(gw); opkele::openid_message_t oum; OP.check_authentication(oum,inm); cout << "Content-type: text/plain\n\n"; oum.to_keyvalues(cout); oum.to_keyvalues(clog); }else{ example_op_t OP(gw); string idsel; if(gw.has_param("idsel")) idsel = "&idsel=idsel"; OP.cookie_header(cout) << "Content-type: text/html\n" "X-XRDS-Location: " << get_self_url(gw) << "?op=xrds" << idsel << "\n" "\n" "" "" "test OP" "" "" "" "test openid 2.0 endpoint" "
" "XRDS document" "
" "

" << message << "

"; sqlite3_mem_t S = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1"); sqlite3_table_t T; int nr,nc; OP.db.get_table(S,T,&nr,&nc); if(nr<1) { cout << "
" "set password " "" "" "" "
"; }else if(OP.get_authorized()) { cout << "
" "logout"; }else{ cout << "
" "login " "" "" "" "
"; } cout << ""; } #ifdef OPKELE_HAVE_KONFORKA }catch(konforka::exception& e) { #else }catch(std::exception& e){ #endif DOUT_("Oops: " << e.what()); cout << "Content-Type: text/plain\n\n" "Exception:\n" " what: " << e.what() << endl; #ifdef OPKELE_HAVE_KONFORKA cout << " where: " << e.where() << endl; if(!e._seen.empty()) { cout << " seen:" << endl; for(list::const_iterator i=e._seen.begin();i!=e._seen.end();++i) { cout << " " << i->c_str() << endl; } } #endif } } libopkele-2.0.4+git20140305.9651b55/test/RP-db.sql000066400000000000000000000014301273462535700204200ustar00rootroot00000000000000CREATE TABLE assoc ( a_op text, a_handle text NOT NULL, a_type text DEFAULT 'HMAC-SHA1', a_ctime text NOT NULL, a_etime text NOT NULL, a_secret text NOT NULL, a_stateless integer NOT NULL DEFAULT 0, a_itime integer, UNIQUE(a_op,a_handle) ); CREATE TABLE nonces ( n_op text NOT NULL, n_once text NOT NULL, PRIMARY KEY (n_op,n_once) ); CREATE TABLE ht_sessions ( hts_id text NOT NULL PRIMARY KEY ); CREATE TABLE auth_sessions ( as_id integer PRIMARY KEY AUTOINCREMENT, hts_id text NOT NULL REFERENCES ht_sessions(hts_id), as_normalized_id text, UNIQUE (hts_id,as_id) ); CREATE TABLE endpoints_queue ( as_id integer NOT NULL REFERENCES auth_sessions (as_id), eq_ctime integer NOT NULL, eq_ordinal integer NOT NULL, eq_uri text, eq_claimed_id text, eq_local_id text ); libopkele-2.0.4+git20140305.9651b55/test/RP.cc000066400000000000000000000263611273462535700176350ustar00rootroot00000000000000#include #include #include #include #include #include #include #include using namespace std; #include #include #include #include #include #include #include #include #include #include using namespace opkele; #include #include #include "sqlite.h" #include "kingate_openid_message.h" #undef DUMB_RP #ifdef DUMB_RP # define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb") #else # define DUMBTHROW (void)0 #endif class rpdb_t : public sqlite3_t { public: rpdb_t() : sqlite3_t("/tmp/RP.db") { assert(_D); char **resp; int nrow,ncol; char *errm; if(sqlite3_get_table( _D,"SELECT a_op FROM assoc LIMIT 0", &resp,&nrow,&ncol,&errm)!=SQLITE_OK) { extern const char *__RP_db_bootstrap; DOUT_("Bootstrapping DB"); if(sqlite3_exec(_D,__RP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK) throw opkele::exception(OPKELE_CP_ string("Failed to bootstrap SQLite database: ")+errm); }else sqlite3_free_table(resp); } }; class example_rp_t : public opkele::prequeue_RP { public: mutable rpdb_t db; kingate::cookie htc; long as_id; int ordinal; kingate::cgi_gateway& gw; example_rp_t(kingate::cgi_gateway& g) : as_id(-1), ordinal(0), gw(g), have_eqtop(false) { try { htc = gw.cookies.get_cookie("ht_session"); as_id = opkele::util::string_to_long(gw.get_param("asid")); }catch(kingate::exception_notfound& kenf) { uuid_t uuid; uuid_generate(uuid); htc = kingate::cookie("ht_session",util::encode_base64(uuid,sizeof(uuid))); sqlite3_mem_t S = sqlite3_mprintf( "INSERT INTO ht_sessions (hts_id) VALUES (%Q)", htc.get_value().c_str()); db.exec(S); } } /* Global persistent store */ opkele::assoc_t store_assoc( const string& OP,const string& handle, const string& type,const secret_t& secret, int expires_in) { DUMBTHROW; DOUT_("Storing '" << handle << "' assoc with '" << OP << "'"); time_t exp = time(0)+expires_in; sqlite3_mem_t S = sqlite3_mprintf( "INSERT INTO assoc" " (a_op,a_handle,a_type,a_ctime,a_etime,a_secret)" " VALUES (" " %Q,%Q,%Q," " datetime('now'), datetime('now','+%d seconds')," " %Q" " );", OP.c_str(), handle.c_str(), type.c_str(), expires_in, util::encode_base64(&(secret.front()),secret.size()).c_str() ); db.exec(S); return opkele::assoc_t(new opkele::association( OP, handle, type, secret, exp, false )); } opkele::assoc_t find_assoc( const string& OP) { DUMBTHROW; DOUT_("Looking for an assoc with '" << OP << '\''); sqlite3_mem_t S = sqlite3_mprintf( "SELECT" " a_op,a_handle,a_type,a_secret," " strftime('%%s',a_etime) AS a_etime" " FROM assoc" " WHERE a_op=%Q AND a_itime IS NULL AND NOT a_stateless" " AND ( a_etime > datetime('now','-30 seconds') )" " LIMIT 1", OP.c_str()); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); if(nr<1) throw opkele::failed_lookup(OPKELE_CP_ "Couldn't find unexpired handle"); assert(nr==1); assert(nc==5); secret_t secret; util::decode_base64(T.get(1,3,nc),secret); DOUT_(" found '" << T.get(1,1,nc) << '\''); return opkele::assoc_t(new opkele::association( T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), secret, strtol(T.get(1,4,nc),0,0), false )); } opkele::assoc_t retrieve_assoc( const string& OP,const string& handle) { DUMBTHROW; DOUT_("Retrieving assoc '" << handle << "' with '" << OP << '\''); sqlite3_mem_t S = sqlite3_mprintf( "SELECT" " a_op,a_handle,a_type,a_secret," " strftime('%%s',a_etime) AS a_etime" " FROM assoc" " WHERE a_op=%Q AND a_handle=%Q" " AND a_itime IS NULL AND NOT a_stateless" " LIMIT 1", OP.c_str(),handle.c_str()); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); if(nr<1) throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid association"); assert(nr==1); assert(nc==5); secret_t secret; util::decode_base64(T.get(1,3,nc),secret); DOUT_(" found. type=" << T.get(1,2,nc) << '\''); return opkele::assoc_t(new opkele::association( T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), secret, strtol(T.get(1,4,nc),0,0), false )); } void invalidate_assoc( const string& OP,const string& handle) { DUMBTHROW; DOUT_("Invalidating assoc '" << handle << "' with '" << OP << '\''); sqlite3_mem_t S = sqlite3_mprintf( "UPDATE assoc SET a_itime=datetime('now')" " WHERE a_op=%Q AND a_handle=%Q", OP.c_str(), handle.c_str() ); db.exec(S); } void check_nonce(const string& OP,const string& nonce) { DOUT_("Checking nonce '" << nonce << "' from '" << OP << '\''); sqlite3_mem_t S = sqlite3_mprintf( "SELECT 1 FROM nonces WHERE n_op=%Q AND n_once=%Q", OP.c_str(), nonce.c_str()); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); if(nr) throw opkele::id_res_bad_nonce(OPKELE_CP_ "already seen that nonce"); sqlite3_mem_t SS = sqlite3_mprintf( "INSERT INTO nonces (n_op,n_once) VALUES (%Q,%Q)", OP.c_str(), nonce.c_str()); db.exec(SS); } /* Session perisistent store */ void begin_queueing() { assert(as_id>=0); DOUT_("Resetting queue for session '" << htc.get_value() << "'/" << as_id); sqlite3_mem_t S = sqlite3_mprintf( "DELETE FROM endpoints_queue" " WHERE as_id=%ld", as_id); db.exec(S); } void queue_endpoint(const opkele::openid_endpoint_t& ep) { assert(as_id>=0); DOUT_("Queueing endpoint " << ep.claimed_id << " : " << ep.local_id << " @ " << ep.uri); sqlite3_mem_t S = sqlite3_mprintf( "INSERT INTO endpoints_queue" " (as_id,eq_ctime,eq_ordinal,eq_uri,eq_claimed_id,eq_local_id)" " VALUES (%ld,strftime('%%s','now'),%d,%Q,%Q,%Q)", as_id,ordinal++, ep.uri.c_str(),ep.claimed_id.c_str(),ep.local_id.c_str()); db.exec(S); } mutable openid_endpoint_t eqtop; mutable bool have_eqtop; const openid_endpoint_t& get_endpoint() const { assert(as_id>=0); if(!have_eqtop) { sqlite3_mem_t S = sqlite3_mprintf( "SELECT" " eq_uri, eq_claimed_id, eq_local_id" " FROM endpoints_queue" " JOIN auth_sessions USING(as_id)" " WHERE hts_id=%Q AND as_id=%ld" " ORDER BY eq_ctime,eq_ordinal" " LIMIT 1",htc.get_value().c_str(),as_id); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); if(nr<1) throw opkele::exception(OPKELE_CP_ "No more endpoints queued"); assert(nr==1); assert(nc==3); eqtop.uri = T.get(1,0,nc); eqtop.claimed_id = T.get(1,1,nc); eqtop.local_id = T.get(1,2,nc); have_eqtop = true; } return eqtop; } void next_endpoint() { assert(as_id>=0); get_endpoint(); have_eqtop = false; sqlite3_mem_t S = sqlite3_mprintf( "DELETE FROM endpoints_queue" " WHERE as_id=%ld AND eq_uri=%Q AND eq_local_id=%Q", htc.get_value().c_str(),as_id, eqtop.uri.c_str()); db.exec(S); } mutable string _nid; void set_normalized_id(const string& nid) { assert(as_id>=0); sqlite3_mem_t S = sqlite3_mprintf( "UPDATE auth_sessions" " SET as_normalized_id=%Q" " WHERE hts_id=%Q and as_id=%ld", nid.c_str(), htc.get_value().c_str(),as_id); db.exec(S); _nid = nid; } const string get_normalized_id() const { assert(as_id>=0); if(_nid.empty()) { sqlite3_mem_t S = sqlite3_mprintf( "SELECT as_normalized_id" " FROM" " auth_sessions" " WHERE" " hts_id=%Q AND as_id=%ld", htc.get_value().c_str(),as_id); sqlite3_table_t T; int nr,nc; db.get_table(S,T,&nr,&nc); assert(nr==1); assert(nc==1); _nid = T.get(1,0,nc); } return _nid; } const string get_this_url() const { bool s = gw.has_meta("SSL_PROTOCOL_VERSION"); string rv = s?"https://":"http://"; rv += gw.http_request_header("Host"); const string& port = gw.get_meta("SERVER_PORT"); if( port!=(s?"443":"80") ) { rv += ':'; rv += port; } rv += gw.get_meta("REQUEST_URI"); return rv; } void initiate(const string& usi) { allocate_asid(); prequeue_RP::initiate(usi); } string get_self_url() const { string rv = get_this_url(); string::size_type q = rv.find('?'); if(q!=string::npos) rv.erase(q); return rv; } void allocate_asid() { sqlite3_mem_t S = sqlite3_mprintf( "INSERT INTO auth_sessions (hts_id)" " VALUES (%Q)", htc.get_value().c_str()); db.exec(S); as_id = sqlite3_last_insert_rowid(db); DOUT_("Allocated authentication session id "<=0); } #ifdef DUMB_RP virtual assoc_t associate(const string& OP) { DUMBTHROW; } #endif }; int main(int,char **) { try { kingate::plaincgi_interface ci; kingate::cgi_gateway gw(ci); string op; try { op = gw.get_param("op"); }catch(kingate::exception_notfound&) { } if(op=="initiate") { example_rp_t rp(gw); string usi = gw.get_param("openid_identity"); rp.initiate(usi); opkele::sreg_t sreg(opkele::sreg_t::fields_NONE,opkele::sreg_t::fields_ALL); opkele::openid_message_t cm; string loc; cout << "Set-Cookie: " << rp.htc.set_cookie_header() << "\n" "Status: 302 Going to OP\n" "Location: " << ( loc = rp.checkid_(cm,opkele::mode_checkid_setup, rp.get_self_url()+ "?op=confirm&asid="+opkele::util::long_to_string(rp.as_id), rp.get_self_url(),&sreg).append_query(rp.get_endpoint().uri) ) << "\n\n"; DOUT_("Going to " << loc); }else if(op=="confirm") { kingate_openid_message_t om(gw); example_rp_t rp(gw); opkele::sreg_t sreg(opkele::sreg_t::fields_NONE,opkele::sreg_t::fields_ALL); rp.id_res(om,&sreg); cout << "Content-Type: text/plain\n\n"; for(opkele::basic_openid_message::fields_iterator i=om.fields_begin(); i!=om.fields_end();++i) { cout << *i << '=' << om.get_field(*i) << endl; } cout << endl << "SREG fields: " << sreg.has_fields << endl; }else{ cout << "Content-type: text/html\n\n" "" "test RP" "" "
" "" "" "" "
" "

" "login with myopenid.com account" "
" "" ; } #ifdef OPKELE_HAVE_KONFORKA }catch(konforka::exception& e) { #else }catch(std::exception& e){ #endif DOUT_("Oops: " << e.what()); cout << "Content-Type: text/plain\n\n" "Exception:\n" " what: " << e.what() << endl; #ifdef OPKELE_HAVE_KONFORKA cout << " where: " << e.where() << endl; if(!e._seen.empty()) { cout << " seen:" << endl; for(list::const_iterator i=e._seen.begin();i!=e._seen.end();++i) { cout << " " << i->c_str() << endl; } } #endif } } libopkele-2.0.4+git20140305.9651b55/test/idiscover.cc000066400000000000000000000022671273462535700213020ustar00rootroot00000000000000#include #include #include #include #include using namespace std; #include #include #include #include namespace opkele { ostream& operator<<(ostream& o,const opkele::openid_endpoint_t& oep) { o << " URI: " << oep.uri << endl << " Claimed ID: " << oep.claimed_id << endl << " Local ID: " << oep.local_id << endl; return o; } } int main(int argc,char **argv) { try { if(argc<2) throw opkele::exception(OPKELE_CP_ "Please, give me something to resolve"); for(int a=1;a(cout," --\n") ,argv[a]); cout << "Normalized ID: " << normalized << endl; } }catch(exception& e) { cerr << "oops, caught " << opkele::util::abi_demangle(typeid(e).name()) << endl << " .what(): " << e.what() << endl; _exit(1); } _exit(0); } libopkele-2.0.4+git20140305.9651b55/test/kingate_openid_message.h000066400000000000000000000062611273462535700236370ustar00rootroot00000000000000template class join_iterator : public iterator< input_iterator_tag,typename IT::value_type, void,typename IT::pointer,typename IT::reference> { public: typedef pair range_t; typedef list ranges_t; ranges_t ranges; join_iterator() { } bool cleanup() { bool rv = false; while(!(ranges.empty() || ranges.front().first!=ranges.front().second)) { ranges.pop_front(); rv = true; } return rv; } join_iterator& add_range(const IT& b,const IT& e) { ranges.push_back(typename ranges_t::value_type(b,e)); cleanup(); return *this; } bool operator==(const join_iterator& x) const { return ranges==x.ranges; } bool operator!=(const join_iterator& x) const { return ranges!=x.ranges; } typename IT::reference operator*() const { assert(!ranges.empty()); assert(ranges.front().first!=ranges.front().second); return *ranges.front().first; } typename IT::pointer operator->() const { assert(!ranges.empty()); assert(ranges.front().first!=ranges.front().second); return ranges.front().first.operator->(); } join_iterator& operator++() { cleanup(); if(ranges.empty()) return *this; do { ++ranges.front().first; }while(cleanup() && !ranges.empty()); return *this; } join_iterator operator++(int) { join_iterator rv(*this); ++(*this); return rv; } }; template class cut_prefix_filterator : public opkele::util::basic_filterator { public: string pfx; mutable string tmp; cut_prefix_filterator() { } cut_prefix_filterator(const IT& _bi,const IT&_ei,const string& p) : opkele::util::basic_filterator(_bi,_ei), pfx(p) { this->prepare(); } bool is_interesting() const { return pfx.length()==0 || !strncmp(this->it->c_str(),pfx.c_str(),pfx.length()); } typename IT::reference operator*() const { assert(!this->empty); tmp = *this->it; tmp.erase(0,pfx.length()); return tmp; } typename IT::pointer operator->() const { assert(!this->empty); return &this->operator*(); } }; class kingate_openid_message_t : public opkele::basic_openid_message { typedef join_iterator jitterator; typedef opkele::util::map_keys_iterator< jitterator, fields_iterator::value_type, fields_iterator::reference, fields_iterator::pointer> keys_iterator; typedef cut_prefix_filterator pfilterator; public: const kingate::cgi_gateway& gw; kingate_openid_message_t(const kingate::cgi_gateway& g) : gw(g) { } bool has_field(const string& n) const { return gw.has_param("openid."+n); } const string& get_field(const string& n) const try { return gw.get_param("openid."+n); }catch(kingate::exception_notfound& nf) { throw opkele::failed_lookup(OPKELE_CP_ nf.what()); } fields_iterator fields_begin() const { return pfilterator( keys_iterator( jitterator() .add_range( gw.get.begin(), gw.get.end() ) .add_range( gw.post.begin(), gw.post.end() ), jitterator() ), keys_iterator(), "openid." ); } fields_iterator fields_end() const { return pfilterator(); } }; libopkele-2.0.4+git20140305.9651b55/test/sqlite.h000066400000000000000000000031011273462535700204420ustar00rootroot00000000000000#include class sqlite3_t { public: sqlite3 *_D; sqlite3_t(const char *f) : _D(0) { int r = sqlite3_open(f,&_D); if(r!=SQLITE_OK) { string msg = sqlite3_errmsg(_D); sqlite3_close(_D); throw opkele::exception(OPKELE_CP_ "Failed to open SQLite database: "+msg); } } ~sqlite3_t() { if(_D) sqlite3_close(_D); } operator const sqlite3*(void) const { return _D; } operator sqlite3*(void) { return _D; } void exec(const char *sql) { assert(_D); char *errm; if(sqlite3_exec(_D,sql,NULL,NULL,&errm)!=SQLITE_OK) throw opkele::exception(OPKELE_CP_ string("Failed to sqlite3_exec():")+errm); } void get_table(const char *sql,char ***resp,int *nr,int *nc) { assert(_D); char *errm; if(sqlite3_get_table(_D,sql,resp,nr,nc,&errm)!=SQLITE_OK) throw opkele::exception(OPKELE_CP_ string("Failed to sqlite3_get_table():")+errm); } }; template class sqlite3_mem_t { public: T _M; sqlite3_mem_t(T M) :_M(M) { } ~sqlite3_mem_t() { if(_M) sqlite3_free(_M); } operator const T&(void) const { return _M; } operator T&(void) { return _M; } sqlite3_mem_t operator=(T M) { if(_M) sqlite3_free(_M); _M = M; } }; class sqlite3_table_t { public: char **_T; sqlite3_table_t() : _T(0) { } sqlite3_table_t(char **T) : _T(T) { } ~sqlite3_table_t() { if(_T) sqlite3_free_table(_T); } operator char**&(void) { return _T; } operator char ***(void) { if(_T) sqlite3_free_table(_T); return &_T; } const char *get(int r,int c,int nc) { assert(_T); return _T[r*nc+c]; } }; libopkele-2.0.4+git20140305.9651b55/test/test.cc000066400000000000000000000077561273462535700203020ustar00rootroot00000000000000#include #include #include using namespace std; #include #include #include "config.h" class failed_test : public opkele::exception { public: failed_test(OPKELE_E_PARS) : exception(OPKELE_E_CONS) { } }; void test_rfc_3986_normalize_uri(const string &ouri,bool success,const string& nuri="") { try { string n = opkele::util::rfc_3986_normalize_uri(ouri); if(!success) throw failed_test(OPKELE_CP_ "Normalized URI when it shouldn't ('"+ouri+"' normalization resulted in '"+n+"')"); if(n!=nuri) throw failed_test(OPKELE_CP_ "rfc_3986_test_failed for '"+ouri+"' failed, expected '"+nuri+"', got '"+n+"'"); }catch(opkele::bad_input& obi) { if(success) throw failed_test(OPKELE_CP_ "Test '"+ouri+"' failed due to 'bad_input'["+obi.what()+"]"); }catch(opkele::not_implemented& oni) { if(success) throw failed_test(OPKELE_CP_ "Test '"+ouri+"' failed due to 'not_implemented'["+oni.what()+"]"); } } void test_rfc_3986_normalize_uri() { test_rfc_3986_normalize_uri( "invalid", false ); test_rfc_3986_normalize_uri( "http://", false ); test_rfc_3986_normalize_uri( "http:/hacker.klever.net/", false ); test_rfc_3986_normalize_uri( "hTTp://hacker.klever.net#uh?oh", true, "http://hacker.klever.net/#uh?oh" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net?uh#oh", true, "http://hacker.klever.net/?uh#oh" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net:80/", true, "http://hacker.klever.net/" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net:80?uh", true, "http://hacker.klever.net/?uh" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net:80#uh", true, "http://hacker.klever.net/#uh" ); test_rfc_3986_normalize_uri( "https://hacker.klever.net:443", true, "https://hacker.klever.net/" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net:?oh", true, "http://hacker.klever.net/?oh" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah%2E", true, "http://hacker.klever.net/ah." ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%2E/", true, "http://hacker.klever.net/ah/" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%2b/", true, "http://hacker.klever.net/ah/%2B/" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/./oh?eh", true, "http://hacker.klever.net/ah/oh?eh" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/../oh?", true, "http://hacker.klever.net/oh?" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah//oh?", true, "http://hacker.klever.net/ah/oh?" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/?", true, "http://hacker.klever.net/ah/?" ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%", false ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%a", false ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%zx", false ); test_rfc_3986_normalize_uri( "http://hacker.klever.net/ah/%5x", false ); test_rfc_3986_normalize_uri( "Http://Hacker.Klever.Net:", true, "http://hacker.klever.net/" ); test_rfc_3986_normalize_uri( "http://www.xxx.com/openid/1", true, "http://www.xxx.com/openid/1" ); } void test_w3c_to_time(const char *w3c,time_t expected) { time_t t = opkele::util::w3c_to_time(w3c); if(t!=expected) { char tmp[512]; snprintf(tmp,sizeof(tmp)-1, "test failed for %s, expected %lu, got %lu (expected-got == %lu)", w3c, (unsigned long)expected, (unsigned long)t, (unsigned long)(expected-t) ); throw failed_test(OPKELE_CP_ tmp); } } void test_w3c_to_time() { test_w3c_to_time("2008-06-29T12:33:44",1214742824); } int main() { try { test_w3c_to_time(); test_rfc_3986_normalize_uri(); }catch(failed_test& ft) { cerr << "Test failed: " << ft.what() << endl; }catch(exception& e) { cerr << "oops: " << e.what() << endl; _exit(1); } _exit(0); }