summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/opkele/basic_op.h2
-rw-r--r--include/opkele/expat.h16
-rw-r--r--include/opkele/iterator.h19
-rw-r--r--include/opkele/types.h1
-rw-r--r--lib/basic_op.cc29
-rw-r--r--lib/basic_rp.cc10
-rw-r--r--lib/discovery.cc2
-rw-r--r--lib/expat.cc1
-rw-r--r--lib/extension.cc2
-rw-r--r--lib/openid_message.cc32
-rw-r--r--lib/prequeue_rp.cc4
-rw-r--r--lib/sreg.cc6
-rw-r--r--lib/verify_op.cc4
-rw-r--r--test/OP.cc16
-rw-r--r--test/RP.cc6
-rw-r--r--test/kingate_openid_message.h4
16 files changed, 77 insertions, 77 deletions
diff --git a/include/opkele/basic_op.h b/include/opkele/basic_op.h
index 0326508..12306dd 100644
--- a/include/opkele/basic_op.h
+++ b/include/opkele/basic_op.h
@@ -1,240 +1,242 @@
1#ifndef __OPKELE_BASIC_OP_H 1#ifndef __OPKELE_BASIC_OP_H
2#define __OPKELE_BASIC_OP_H 2#define __OPKELE_BASIC_OP_H
3 3
4#include <string> 4#include <string>
5#include <opkele/types.h> 5#include <opkele/types.h>
6#include <opkele/extension.h> 6#include <opkele/extension.h>
7 7
8namespace opkele { 8namespace opkele {
9 using std::string; 9 using std::string;
10 10
11 /** 11 /**
12 * Implementation of basic OP functionality 12 * Implementation of basic OP functionality
13 */ 13 */
14 class basic_OP { 14 class basic_OP {
15 public: 15 public:
16 /** 16 /**
17 * The request mode for the request being processed 17 * The request mode for the request being processed
18 */ 18 */
19 mode_t mode; 19 mode_t mode;
20 /** 20 /**
21 * association used in transaction. reset in case of dumb operation 21 * association used in transaction. reset in case of dumb operation
22 */ 22 */
23 assoc_t assoc; 23 assoc_t assoc;
24 /** 24 /**
25 * true if the request is openid2 request 25 * true if the request is openid2 request
26 */ 26 */
27 bool openid2; 27 bool openid2;
28 /** 28 /**
29 * The return_to RP endpoint 29 * The return_to RP endpoint
30 */ 30 */
31 string return_to; 31 string return_to;
32 /** 32 /**
33 * The realm we authenticate for 33 * The realm we authenticate for
34 */ 34 */
35 string realm; 35 string realm;
36 /** 36 /**
37 * Claimed identifier 37 * Claimed identifier
38 */ 38 */
39 string claimed_id; 39 string claimed_id;
40 /** 40 /**
41 * The OP-Local identifier 41 * The OP-Local identifier
42 */ 42 */
43 string identity; 43 string identity;
44 /** 44 /**
45 * The invalidate handle for the reply request 45 * The invalidate handle for the reply request
46 */ 46 */
47 string invalidate_handle; 47 string invalidate_handle;
48 48
49 virtual ~basic_OP() { }
50
49 void reset_vars(); 51 void reset_vars();
50 52
51 /** 53 /**
52 * @name Request information access 54 * @name Request information access
53 * Setting and retrieval of the information pertaining to the request being processed 55 * Setting and retrieval of the information pertaining to the request being processed
54 * @{ 56 * @{
55 */ 57 */
56 /** 58 /**
57 * Check if the RP expects us to get back to them. 59 * Check if the RP expects us to get back to them.
58 * @return true if RP supplied return_to URL 60 * @return true if RP supplied return_to URL
59 */ 61 */
60 bool has_return_to() const; 62 bool has_return_to() const;
61 /** 63 /**
62 * Find out where the RP is waiting for us. 64 * Find out where the RP is waiting for us.
63 * @return the return_to URL supplied 65 * @return the return_to URL supplied
64 * @throw no_return_to if no return_to is supplied with the request 66 * @throw no_return_to if no return_to is supplied with the request
65 */ 67 */
66 const string& get_return_to() const; 68 const string& get_return_to() const;
67 69
68 /** 70 /**
69 * Find out what realm we are authenticating user for 71 * Find out what realm we are authenticating user for
70 * @return the realm 72 * @return the realm
71 */ 73 */
72 const string& get_realm() const; 74 const string& get_realm() const;
73 75
74 /** 76 /**
75 * Check if request is about identity 77 * Check if request is about identity
76 * @return true if so 78 * @return true if so
77 */ 79 */
78 bool has_identity() const; 80 bool has_identity() const;
79 /** 81 /**
80 * Get claimed identifier supplied with the request 82 * Get claimed identifier supplied with the request
81 * @return claimed identifier 83 * @return claimed identifier
82 * @throw non_identity if request is not about identity 84 * @throw non_identity if request is not about identity
83 */ 85 */
84 const string& get_claimed_id() const; 86 const string& get_claimed_id() const;
85 /** 87 /**
86 * Get the identity (OP-Local identifier) being confirmed 88 * Get the identity (OP-Local identifier) being confirmed
87 * @return identity 89 * @return identity
88 * @throw non_identity if request is not about identity 90 * @throw non_identity if request is not about identity
89 */ 91 */
90 const string& get_identity() const; 92 const string& get_identity() const;
91 93
92 /** 94 /**
93 * Is identifier supposed to be selected on our side? 95 * Is identifier supposed to be selected on our side?
94 * @return true if identity is a special identifier select URI 96 * @return true if identity is a special identifier select URI
95 */ 97 */
96 bool is_id_select() const; 98 bool is_id_select() const;
97 99
98 /** 100 /**
99 * Select the identity for identifier select request 101 * Select the identity for identifier select request
100 * @param cid claimed identifier 102 * @param cid claimed identifier
101 * @param lid local identifier 103 * @param lid local identifier
102 */ 104 */
103 void select_identity(const string& cid,const string& lid); 105 void select_identity(const string& cid,const string& lid);
104 /** 106 /**
105 * Set claimed identifier (for instance if it's supposed to have 107 * Set claimed identifier (for instance if it's supposed to have
106 * fragment part) 108 * fragment part)
107 * @param cid claimed identifier 109 * @param cid claimed identifier
108 */ 110 */
109 void set_claimed_id(const string& cid); 111 void set_claimed_id(const string& cid);
110 /** 112 /**
111 * @} 113 * @}
112 */ 114 */
113 115
114 /** @name OpenID operations 116 /** @name OpenID operations
115 * @{ 117 * @{
116 */ 118 */
117 /** 119 /**
118 * Establish association with RP 120 * Establish association with RP
119 * @param oum reply message 121 * @param oum reply message
120 * @param inm request message 122 * @param inm request message
121 */ 123 */
122 basic_openid_message& associate( 124 basic_openid_message& associate(
123 basic_openid_message& oum, 125 basic_openid_message& oum,
124 const basic_openid_message& inm); 126 const basic_openid_message& inm);
125 127
126 /** 128 /**
127 * Parse the checkid_* request. The function parses input message, 129 * Parse the checkid_* request. The function parses input message,
128 * retrieves the information needed for further processing, 130 * retrieves the information needed for further processing,
129 * verifies what can be verified at this stage. 131 * verifies what can be verified at this stage.
130 * @param inm incoming OpenID message 132 * @param inm incoming OpenID message
131 * @param ext extension/chain of extensions supported 133 * @param ext extension/chain of extensions supported
132 */ 134 */
133 void checkid_(const basic_openid_message& inm,extension_t *ext=0); 135 void checkid_(const basic_openid_message& inm,extension_t *ext=0);
134 /** 136 /**
135 * Build and sign a positive assertion message 137 * Build and sign a positive assertion message
136 * @param om outpu OpenID message 138 * @param om outpu OpenID message
137 * @param ext extension/chain of extensions supported 139 * @param ext extension/chain of extensions supported
138 * @return reference to om 140 * @return reference to om
139 */ 141 */
140 basic_openid_message& id_res(basic_openid_message& om, 142 basic_openid_message& id_res(basic_openid_message& om,
141 extension_t *ext=0); 143 extension_t *ext=0);
142 /** 144 /**
143 * Build a 'cancel' negative assertion 145 * Build a 'cancel' negative assertion
144 * @param om output OpenID message 146 * @param om output OpenID message
145 * @return reference to om 147 * @return reference to om
146 */ 148 */
147 basic_openid_message& cancel(basic_openid_message& om); 149 basic_openid_message& cancel(basic_openid_message& om);
148 /** 150 /**
149 * Build an 'error' reply 151 * Build an 'error' reply
150 * @param om output OpenID message 152 * @param om output OpenID message
151 * @param error a human-readable message indicating the cause 153 * @param error a human-readable message indicating the cause
152 * @param contact contact address for the server administrator (can be empty) 154 * @param contact contact address for the server administrator (can be empty)
153 * @param reference a reference token (can be empty) 155 * @param reference a reference token (can be empty)
154 * @return reference to om 156 * @return reference to om
155 */ 157 */
156 basic_openid_message& error(basic_openid_message& om, 158 basic_openid_message& error(basic_openid_message& om,
157 const string& error,const string& contact, 159 const string& error,const string& contact,
158 const string& reference ); 160 const string& reference );
159 /** 161 /**
160 * Build a setup_needed reply to checkid_immediate request 162 * Build a setup_needed reply to checkid_immediate request
161 * @param oum output OpenID message 163 * @param oum output OpenID message
162 * @param inm incoming OpenID request being processed 164 * @param inm incoming OpenID request being processed
163 * @return reference to oum 165 * @return reference to oum
164 */ 166 */
165 basic_openid_message& setup_needed( 167 basic_openid_message& setup_needed(
166 basic_openid_message& oum,const basic_openid_message& inm); 168 basic_openid_message& oum,const basic_openid_message& inm);
167 169
168 /** 170 /**
169 * Process check_authentication request 171 * Process check_authentication request
170 * @param oum output OpenID message 172 * @param oum output OpenID message
171 * @param inm incoming request 173 * @param inm incoming request
172 * @return reference to oum 174 * @return reference to oum
173 */ 175 */
174 basic_openid_message& check_authentication( 176 basic_openid_message& check_authentication(
175 basic_openid_message& oum,const basic_openid_message& inm); 177 basic_openid_message& oum,const basic_openid_message& inm);
176 /** 178 /**
177 * @} 179 * @}
178 */ 180 */
179 181
180 /** 182 /**
181 * Verify return_to url. The default implementation checks whether 183 * Verify return_to url. The default implementation checks whether
182 * return_to URI matches the realm 184 * return_to URI matches the realm
183 * @throw bad_realm in case of invalid realm 185 * @throw bad_realm in case of invalid realm
184 * @throw bad_return_to if return_to doesn't match the realm 186 * @throw bad_return_to if return_to doesn't match the realm
185 * @see verify_OP::verify_return_to() 187 * @see verify_OP::verify_return_to()
186 */ 188 */
187 virtual void verify_return_to(); 189 virtual void verify_return_to();
188 190
189 /** 191 /**
190 * @name Global persistent store API 192 * @name Global persistent store API
191 * These functions are related to the associations with RPs storage 193 * These functions are related to the associations with RPs storage
192 * and retrieval and nonce management. 194 * and retrieval and nonce management.
193 * @{ 195 * @{
194 */ 196 */
195 /** 197 /**
196 * Allocate association. 198 * Allocate association.
197 * @param type association type 199 * @param type association type
198 * @param kl association key length 200 * @param kl association key length
199 * @param sl true if the association is stateless 201 * @param sl true if the association is stateless
200 * @return association object 202 * @return association object
201 */ 203 */
202 virtual assoc_t alloc_assoc(const string& type,size_t kl,bool sl) = 0; 204 virtual assoc_t alloc_assoc(const string& type,size_t kl,bool sl) = 0;
203 /** 205 /**
204 * Retrieve valid unexpired association 206 * Retrieve valid unexpired association
205 * @param handle association handle 207 * @param handle association handle
206 * @return association object 208 * @return association object
207 */ 209 */
208 virtual assoc_t retrieve_assoc(const string& handle) = 0; 210 virtual assoc_t retrieve_assoc(const string& handle) = 0;
209 /** 211 /**
210 * Allocate nonce. 212 * Allocate nonce.
211 * @param nonce input-output parameter containing timestamp part of 213 * @param nonce input-output parameter containing timestamp part of
212 * the nonce on input 214 * the nonce on input
213 * @param sl true if the nonce is 215 * @param sl true if the nonce is
214 * @return reference to nonce 216 * @return reference to nonce
215 * @throw failed_lookup if no such valid unexpired association 217 * @throw failed_lookup if no such valid unexpired association
216 * could be retrieved 218 * could be retrieved
217 */ 219 */
218 virtual string& alloc_nonce(string& nonce) = 0; 220 virtual string& alloc_nonce(string& nonce) = 0;
219 /** 221 /**
220 * Check nonce validity 222 * Check nonce validity
221 * @param nonce nonce to check 223 * @param nonce nonce to check
222 * @return true if nonce found and isn't yet invalidated 224 * @return true if nonce found and isn't yet invalidated
223 */ 225 */
224 virtual bool check_nonce(const string& nonce) = 0; 226 virtual bool check_nonce(const string& nonce) = 0;
225 /** 227 /**
226 * Invalidate nonce 228 * Invalidate nonce
227 * @param nonce nonce to check 229 * @param nonce nonce to check
228 */ 230 */
229 virtual void invalidate_nonce(const string& nonce) = 0; 231 virtual void invalidate_nonce(const string& nonce) = 0;
230 /** 232 /**
231 * @} 233 * @}
232 */ 234 */
233 235
234 /** 236 /**
235 * @name Site particulars API 237 * @name Site particulars API
236 * @{ 238 * @{
237 */ 239 */
238 /** 240 /**
239 * Query the absolute URL of the op endpoint 241 * Query the absolute URL of the op endpoint
240 * @return fully qualified url of the OP endpoint 242 * @return fully qualified url of the OP endpoint
diff --git a/include/opkele/expat.h b/include/opkele/expat.h
index 60c41ac..3ab1630 100644
--- a/include/opkele/expat.h
+++ b/include/opkele/expat.h
@@ -1,91 +1,91 @@
1#ifndef __OPKELE_EXPAT_H 1#ifndef __OPKELE_EXPAT_H
2#define __OPKELE_EXPAT_H 2#define __OPKELE_EXPAT_H
3 3
4#include <cassert> 4#include <cassert>
5#include <expat.h> 5#include <expat.h>
6 6
7namespace opkele { 7namespace opkele {
8 8
9 namespace util { 9 namespace util {
10 10
11 class expat_t { 11 class expat_t {
12 public: 12 public:
13 XML_Parser _x; 13 XML_Parser _x;
14 14
15 expat_t() : _x(0) { } 15 expat_t() : _x(0) { }
16 expat_t(XML_Parser x) : _x(x) { } 16 expat_t(XML_Parser x) : _x(x) { }
17 virtual ~expat_t() throw(); 17 virtual ~expat_t() throw();
18 18
19 expat_t& operator=(XML_Parser x); 19 expat_t& operator=(XML_Parser x);
20 20
21 operator const XML_Parser(void) const { return _x; } 21 operator const XML_Parser(void) const { return _x; }
22 operator XML_Parser(void) { return _x; } 22 operator XML_Parser(void) { return _x; }
23 23
24 inline bool parse(const char *s,int len,bool final=false) { 24 inline bool parse(const char *s,int len,bool final=false) {
25 assert(_x); 25 assert(_x);
26 return XML_Parse(_x,s,len,final); 26 return XML_Parse(_x,s,len,final);
27 } 27 }
28 28
29 virtual void start_element(const XML_Char *n,const XML_Char **a) { } 29 virtual void start_element(const XML_Char * /* n */,const XML_Char ** /* a */) { }
30 virtual void end_element(const XML_Char *n) { } 30 virtual void end_element(const XML_Char * /* n */) { }
31 void set_element_handler(); 31 void set_element_handler();
32 32
33 virtual void character_data(const XML_Char *s,int l) { } 33 virtual void character_data(const XML_Char * /* s */,int /* l */) { }
34 void set_character_data_handler(); 34 void set_character_data_handler();
35 35
36 virtual void processing_instruction(const XML_Char *t,const XML_Char *d) { } 36 virtual void processing_instruction(const XML_Char * /* t */,const XML_Char * /* d */) { }
37 void set_processing_instruction_handler(); 37 void set_processing_instruction_handler();
38 38
39 virtual void comment(const XML_Char *d) { } 39 virtual void comment(const XML_Char * /* d */) { }
40 void set_comment_handler(); 40 void set_comment_handler();
41 41
42 virtual void start_cdata_section() { } 42 virtual void start_cdata_section() { }
43 virtual void end_cdata_section() { } 43 virtual void end_cdata_section() { }
44 void set_cdata_section_handler(); 44 void set_cdata_section_handler();
45 45
46 virtual void default_handler(const XML_Char *s,int l) { } 46 virtual void default_handler(const XML_Char * /* s */,int /* l */) { }
47 void set_default_handler(); 47 void set_default_handler();
48 void set_default_handler_expand(); 48 void set_default_handler_expand();
49 49
50 virtual void start_namespace_decl(const XML_Char *p,const XML_Char *u) { } 50 virtual void start_namespace_decl(const XML_Char * /* p */,const XML_Char * /* u */) { }
51 virtual void end_namespace_decl(const XML_Char *p) { } 51 virtual void end_namespace_decl(const XML_Char * /* p */) { }
52 void set_namespace_decl_handler(); 52 void set_namespace_decl_handler();
53 53
54 inline enum XML_Error get_error_code() { 54 inline enum XML_Error get_error_code() {
55 assert(_x); return XML_GetErrorCode(_x); } 55 assert(_x); return XML_GetErrorCode(_x); }
56 static inline const XML_LChar *error_string(XML_Error c) { 56 static inline const XML_LChar *error_string(XML_Error c) {
57 return XML_ErrorString(c); } 57 return XML_ErrorString(c); }
58 58
59 inline long get_current_byte_index() { 59 inline long get_current_byte_index() {
60 assert(_x); return XML_GetCurrentByteIndex(_x); } 60 assert(_x); return XML_GetCurrentByteIndex(_x); }
61 inline int get_current_line_number() { 61 inline int get_current_line_number() {
62 assert(_x); return XML_GetCurrentLineNumber(_x); } 62 assert(_x); return XML_GetCurrentLineNumber(_x); }
63 inline int get_current_column_number() { 63 inline int get_current_column_number() {
64 assert(_x); return XML_GetCurrentColumnNumber(_x); } 64 assert(_x); return XML_GetCurrentColumnNumber(_x); }
65 65
66 inline void set_user_data() { 66 inline void set_user_data() {
67 assert(_x); XML_SetUserData(_x,this); } 67 assert(_x); XML_SetUserData(_x,this); }
68 68
69 inline bool set_base(const XML_Char *b) { 69 inline bool set_base(const XML_Char *b) {
70 assert(_x); return XML_SetBase(_x,b); } 70 assert(_x); return XML_SetBase(_x,b); }
71 inline const XML_Char *get_base() { 71 inline const XML_Char *get_base() {
72 assert(_x); return XML_GetBase(_x); } 72 assert(_x); return XML_GetBase(_x); }
73 73
74 inline int get_specified_attribute_count() { 74 inline int get_specified_attribute_count() {
75 assert(_x); return XML_GetSpecifiedAttributeCount(_x); } 75 assert(_x); return XML_GetSpecifiedAttributeCount(_x); }
76 76
77 inline bool set_param_entity_parsing(enum XML_ParamEntityParsing c) { 77 inline bool set_param_entity_parsing(enum XML_ParamEntityParsing c) {
78 assert(_x); return XML_SetParamEntityParsing(_x,c); } 78 assert(_x); return XML_SetParamEntityParsing(_x,c); }
79 79
80 inline static XML_Parser parser_create(const XML_Char *e=0) { 80 inline static XML_Parser parser_create(const XML_Char *e=0) {
81 return XML_ParserCreate(e); } 81 return XML_ParserCreate(e); }
82 inline static XML_Parser parser_create_ns(const XML_Char *e=0,XML_Char s='\t') { 82 inline static XML_Parser parser_create_ns(const XML_Char *e=0,XML_Char s='\t') {
83 return XML_ParserCreateNS(e,s); } 83 return XML_ParserCreateNS(e,s); }
84 84
85 }; 85 };
86 86
87 } 87 }
88 88
89} 89}
90 90
91#endif /* __OPKELE_EXPAT_H */ 91#endif /* __OPKELE_EXPAT_H */
diff --git a/include/opkele/iterator.h b/include/opkele/iterator.h
index 812a786..28c1c83 100644
--- a/include/opkele/iterator.h
+++ b/include/opkele/iterator.h
@@ -1,217 +1,216 @@
1#ifndef __OPKELE_ITERATOR_H 1#ifndef __OPKELE_ITERATOR_H
2#define __OPKELE_ITERATOR_H 2#define __OPKELE_ITERATOR_H
3 3
4#include <cassert> 4#include <cassert>
5#include <iterator> 5#include <iterator>
6 6
7namespace opkele { 7namespace opkele {
8 namespace util { 8 namespace util {
9 using std::iterator; 9 using std::iterator;
10 using std::forward_iterator_tag; 10 using std::forward_iterator_tag;
11 using std::output_iterator_tag; 11 using std::output_iterator_tag;
12 12
13 template <typename T> 13 template <typename T>
14 class basic_output_iterator_proxy_impl : public iterator<output_iterator_tag,T,void,T*,T&> { 14 class basic_output_iterator_proxy_impl : public iterator<output_iterator_tag,T,void,T*,T&> {
15 public: 15 public:
16 virtual ~basic_output_iterator_proxy_impl() { } 16 virtual ~basic_output_iterator_proxy_impl() { }
17 17
18 virtual basic_output_iterator_proxy_impl<T>* dup() const = 0; 18 virtual basic_output_iterator_proxy_impl<T>* dup() const = 0;
19 basic_output_iterator_proxy_impl<T>& operator*() { return *this; }; 19 basic_output_iterator_proxy_impl<T>& operator*() { return *this; };
20 virtual basic_output_iterator_proxy_impl<T>& operator=(const T& x) = 0; 20 virtual basic_output_iterator_proxy_impl<T>& operator=(const T& x) = 0;
21 21
22 }; 22 };
23 23
24 template<typename IT,typename T=typename IT::value_type> 24 template<typename IT,typename T=typename IT::value_type>
25 class output_iterator_proxy_impl : public basic_output_iterator_proxy_impl<T> { 25 class output_iterator_proxy_impl : public basic_output_iterator_proxy_impl<T> {
26 public: 26 public:
27 IT i; 27 IT i;
28 28
29 output_iterator_proxy_impl(const IT& i) : i(i) { } 29 output_iterator_proxy_impl(const IT& _i) : i(_i) { }
30 basic_output_iterator_proxy_impl<T>* dup() const { 30 basic_output_iterator_proxy_impl<T>* dup() const {
31 return new output_iterator_proxy_impl<IT,T>(i); } 31 return new output_iterator_proxy_impl<IT,T>(i); }
32 basic_output_iterator_proxy_impl<T>& operator=(const T& x) { 32 basic_output_iterator_proxy_impl<T>& operator=(const T& x) {
33 (*i) = x; 33 (*i) = x; return *this; }
34 }
35 }; 34 };
36 35
37 template<typename T> 36 template<typename T>
38 class output_iterator_proxy : public iterator<output_iterator_tag,T,void,T*,T&> { 37 class output_iterator_proxy : public iterator<output_iterator_tag,T,void,T*,T&> {
39 public: 38 public:
40 basic_output_iterator_proxy_impl<T> *I; 39 basic_output_iterator_proxy_impl<T> *I;
41 40
42 template<typename IT> 41 template<typename IT>
43 output_iterator_proxy(const IT& i) 42 output_iterator_proxy(const IT& i)
44 : I(new output_iterator_proxy_impl<IT,T>(i)) { } 43 : I(new output_iterator_proxy_impl<IT,T>(i)) { }
45 output_iterator_proxy(const output_iterator_proxy<T>& x) 44 output_iterator_proxy(const output_iterator_proxy<T>& x)
46 : I(x.I->dup()) { } 45 : I(x.I->dup()) { }
47 ~output_iterator_proxy() { delete I; } 46 ~output_iterator_proxy() { delete I; }
48 47
49 output_iterator_proxy& operator=(const output_iterator_proxy<T>& x) { 48 output_iterator_proxy& operator=(const output_iterator_proxy<T>& x) {
50 delete I; I = x.I->dup(); } 49 delete I; I = x.I->dup(); }
51 50
52 output_iterator_proxy& operator*() { return *this; } 51 output_iterator_proxy& operator*() { return *this; }
53 output_iterator_proxy& operator=(const T& x) { 52 output_iterator_proxy& operator=(const T& x) {
54 (**I) = x; } 53 (**I) = x; return *this; }
55 54
56 output_iterator_proxy& operator++() { return *this; } 55 output_iterator_proxy& operator++() { return *this; }
57 output_iterator_proxy& operator++(int) { return *this; } 56 output_iterator_proxy& operator++(int) { return *this; }
58 }; 57 };
59 58
60 template <typename T,typename TR=T&,typename TP=T*> 59 template <typename T,typename TR=T&,typename TP=T*>
61 class basic_forward_iterator_proxy_impl : public iterator<forward_iterator_tag,T,void,TP,TR> { 60 class basic_forward_iterator_proxy_impl : public iterator<forward_iterator_tag,T,void,TP,TR> {
62 public: 61 public:
63 virtual ~basic_forward_iterator_proxy_impl() { } 62 virtual ~basic_forward_iterator_proxy_impl() { }
64 63
65 virtual basic_forward_iterator_proxy_impl<T,TR,TP>* dup() const = 0; 64 virtual basic_forward_iterator_proxy_impl<T,TR,TP>* dup() const = 0;
66 65
67 virtual bool operator==(const basic_forward_iterator_proxy_impl<T,TR,TP>& x) const = 0; 66 virtual bool operator==(const basic_forward_iterator_proxy_impl<T,TR,TP>& x) const = 0;
68 virtual bool operator!=(const basic_forward_iterator_proxy_impl<T,TR,TP>& x) const { 67 virtual bool operator!=(const basic_forward_iterator_proxy_impl<T,TR,TP>& x) const {
69 return !((*this)==x); } 68 return !((*this)==x); }
70 virtual TR operator*() const = 0; 69 virtual TR operator*() const = 0;
71 virtual TP operator->() const = 0; 70 virtual TP operator->() const = 0;
72 virtual void advance() = 0; 71 virtual void advance() = 0;
73 }; 72 };
74 73
75 template <typename IT> 74 template <typename IT>
76 class forward_iterator_proxy_impl : public basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer> { 75 class forward_iterator_proxy_impl : public basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer> {
77 public: 76 public:
78 IT i; 77 IT i;
79 78
80 forward_iterator_proxy_impl(const IT& i) : i(i) { } 79 forward_iterator_proxy_impl(const IT& _i) : i(_i) { }
81 80
82 virtual basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer>* dup() const { 81 virtual basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer>* dup() const {
83 return new forward_iterator_proxy_impl<IT>(i); } 82 return new forward_iterator_proxy_impl<IT>(i); }
84 83
85 virtual bool operator==(const basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer>& x) const { 84 virtual bool operator==(const basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer>& x) const {
86 return i==static_cast<const forward_iterator_proxy_impl<IT>*>(&x)->i; } 85 return i==static_cast<const forward_iterator_proxy_impl<IT>*>(&x)->i; }
87 virtual bool operator!=(const basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer>& x) const { 86 virtual bool operator!=(const basic_forward_iterator_proxy_impl<typename IT::value_type,typename IT::reference,typename IT::pointer>& x) const {
88 return i!=static_cast<const forward_iterator_proxy_impl<IT>*>(&x)->i; } 87 return i!=static_cast<const forward_iterator_proxy_impl<IT>*>(&x)->i; }
89 virtual typename IT::reference operator*() const { return *i; } 88 virtual typename IT::reference operator*() const { return *i; }
90 virtual typename IT::pointer operator->() const { return i.operator->(); } 89 virtual typename IT::pointer operator->() const { return i.operator->(); }
91 virtual void advance() { ++i; } 90 virtual void advance() { ++i; }
92 }; 91 };
93 92
94 template<typename T,typename TR=T&,typename TP=T*> 93 template<typename T,typename TR=T&,typename TP=T*>
95 class forward_iterator_proxy : public iterator<forward_iterator_tag,T,void,TP,TR> { 94 class forward_iterator_proxy : public iterator<forward_iterator_tag,T,void,TP,TR> {
96 public: 95 public:
97 basic_forward_iterator_proxy_impl<T,TR,TP> *I; 96 basic_forward_iterator_proxy_impl<T,TR,TP> *I;
98 97
99 template<typename IT> 98 template<typename IT>
100 forward_iterator_proxy(const IT& i) 99 forward_iterator_proxy(const IT& i)
101 : I(new forward_iterator_proxy_impl<IT>(i)) { } 100 : I(new forward_iterator_proxy_impl<IT>(i)) { }
102 forward_iterator_proxy(const forward_iterator_proxy<T,TR,TP>& x) 101 forward_iterator_proxy(const forward_iterator_proxy<T,TR,TP>& x)
103 : I(x.I->dup()) { } 102 : I(x.I->dup()) { }
104 ~forward_iterator_proxy() { delete I; } 103 ~forward_iterator_proxy() { delete I; }
105 104
106 forward_iterator_proxy& operator=(const forward_iterator_proxy<T,TR,TP>& x) { 105 forward_iterator_proxy& operator=(const forward_iterator_proxy<T,TR,TP>& x) {
107 delete I; I = x.I->dup(); } 106 delete I; I = x.I->dup(); }
108 107
109 bool operator==(const forward_iterator_proxy<T,TR,TP>& x) const { 108 bool operator==(const forward_iterator_proxy<T,TR,TP>& x) const {
110 return (*I)==(*(x.I)); } 109 return (*I)==(*(x.I)); }
111 bool operator!=(const forward_iterator_proxy<T,TR,TP>& x) const { 110 bool operator!=(const forward_iterator_proxy<T,TR,TP>& x) const {
112 return (*I)!=(*(x.I)); } 111 return (*I)!=(*(x.I)); }
113 112
114 TR operator*() const { 113 TR operator*() const {
115 return **I; } 114 return **I; }
116 TP operator->() const { 115 TP operator->() const {
117 return I->operator->(); } 116 return I->operator->(); }
118 117
119 forward_iterator_proxy<T,TR,TP>& operator++() { 118 forward_iterator_proxy<T,TR,TP>& operator++() {
120 I->advance(); return *this; } 119 I->advance(); return *this; }
121 forward_iterator_proxy<T,TR,TP>& operator++(int) { 120 forward_iterator_proxy<T,TR,TP>& operator++(int) {
122 forward_iterator_proxy<T,TR,TP> rv(*this); 121 forward_iterator_proxy<T,TR,TP> rv(*this);
123 I->advance(); return rv; } 122 I->advance(); return rv; }
124 }; 123 };
125 124
126 template<typename IT> 125 template<typename IT>
127 class basic_filterator : public iterator< 126 class basic_filterator : public iterator<
128 typename IT::iterator_category, 127 typename IT::iterator_category,
129 typename IT::value_type, 128 typename IT::value_type,
130 typename IT::difference_type, 129 typename IT::difference_type,
131 typename IT::pointer, 130 typename IT::pointer,
132 typename IT::reference> { 131 typename IT::reference> {
133 public: 132 public:
134 IT it; 133 IT it;
135 IT ei; 134 IT ei;
136 bool empty; 135 bool empty;
137 136
138 basic_filterator() : empty(true) { } 137 basic_filterator() : empty(true) { }
139 basic_filterator(const IT& bi,const IT& ei) 138 basic_filterator(const IT& _bi,const IT& _ei)
140 : it(bi), ei(ei) { empty = (bi==ei); } 139 : it(_bi), ei(_ei) { empty = (it==ei); }
141 basic_filterator(const basic_filterator<IT>& x) 140 basic_filterator(const basic_filterator<IT>& x)
142 : it(x.it), ei(x.ei), empty(x.empty) { } 141 : it(x.it), ei(x.ei), empty(x.empty) { }
143 virtual ~basic_filterator() { } 142 virtual ~basic_filterator() { }
144 143
145 bool operator==(const basic_filterator<IT>& x) const { 144 bool operator==(const basic_filterator<IT>& x) const {
146 return empty?x.empty:(it==x.it); } 145 return empty?x.empty:(it==x.it); }
147 bool operator!=(const basic_filterator<IT>& x) const { 146 bool operator!=(const basic_filterator<IT>& x) const {
148 return empty!=x.empty || it!=x.it; } 147 return empty!=x.empty || it!=x.it; }
149 148
150 typename IT::reference operator*() const { 149 typename IT::reference operator*() const {
151 assert(!empty); 150 assert(!empty);
152 return *it; } 151 return *it; }
153 typename IT::pointer operator->() const { 152 typename IT::pointer operator->() const {
154 assert(!empty); 153 assert(!empty);
155 return it.operator->(); } 154 return it.operator->(); }
156 155
157 basic_filterator<IT>& operator++() { 156 basic_filterator<IT>& operator++() {
158 bool found = false; 157 bool found = false;
159 for(++it;!(it==ei || (found=is_interesting()));++it); 158 for(++it;!(it==ei || (found=is_interesting()));++it);
160 if(!found) empty=true; 159 if(!found) empty=true;
161 return *this; 160 return *this;
162 } 161 }
163 basic_filterator<IT> operator++(int) { 162 basic_filterator<IT> operator++(int) {
164 basic_filterator<IT> rv(*this); 163 basic_filterator<IT> rv(*this);
165 ++(*this); 164 ++(*this);
166 return rv; 165 return rv;
167 } 166 }
168 167
169 void prepare() { 168 void prepare() {
170 bool found = false; 169 bool found = false;
171 for(;!(it==ei || (found=is_interesting()));++it); 170 for(;!(it==ei || (found=is_interesting()));++it);
172 if(!found) empty = true; 171 if(!found) empty = true;
173 } 172 }
174 virtual bool is_interesting() const = 0; 173 virtual bool is_interesting() const = 0;
175 }; 174 };
176 175
177 template<typename IT,typename T=typename IT::value_type::first_type,typename TR=T&,typename TP=T*> 176 template<typename IT,typename T=typename IT::value_type::first_type,typename TR=T&,typename TP=T*>
178 class map_keys_iterator : public iterator< 177 class map_keys_iterator : public iterator<
179 typename IT::iterator_category, 178 typename IT::iterator_category,
180 T,void,TP,TR> { 179 T,void,TP,TR> {
181 public: 180 public:
182 typedef map_keys_iterator<IT,T,TR,TP> self_type; 181 typedef map_keys_iterator<IT,T,TR,TP> self_type;
183 IT it; 182 IT it;
184 IT ei; 183 IT ei;
185 bool empty; 184 bool empty;
186 185
187 map_keys_iterator() : empty(true) { } 186 map_keys_iterator() : empty(true) { }
188 map_keys_iterator(const IT& bi, 187 map_keys_iterator(const IT& _bi,
189 const IT& ei) 188 const IT& _ei)
190 : it(bi), ei(ei) { empty = (bi==ei); } 189 : it(_bi), ei(_ei) { empty = (it==ei); }
191 map_keys_iterator(const self_type& x) 190 map_keys_iterator(const self_type& x)
192 : it(x.it), ei(x.ei), empty(x.empty) { } 191 : it(x.it), ei(x.ei), empty(x.empty) { }
193 192
194 bool operator==(const self_type& x) const { 193 bool operator==(const self_type& x) const {
195 return empty?x.empty:(it==x.it); } 194 return empty?x.empty:(it==x.it); }
196 bool operator!=(const self_type& x) const { 195 bool operator!=(const self_type& x) const {
197 return empty!=x.empty || it!=x.it; } 196 return empty!=x.empty || it!=x.it; }
198 197
199 TR operator*() const { 198 TR operator*() const {
200 assert(!empty); 199 assert(!empty);
201 return it->first; } 200 return it->first; }
202 TP operator->() const { 201 TP operator->() const {
203 assert(!empty); 202 assert(!empty);
204 return &(it->first); } 203 return &(it->first); }
205 204
206 self_type& operator++() { 205 self_type& operator++() {
207 assert(!empty); 206 assert(!empty);
208 empty=((++it)==ei); return *this; } 207 empty=((++it)==ei); return *this; }
209 self_type operator++(int) { 208 self_type operator++(int) {
210 self_type rv(*this); 209 self_type rv(*this);
211 ++(*this); return rv; } 210 ++(*this); return rv; }
212 }; 211 };
213 212
214 } 213 }
215} 214}
216 215
217#endif /* __OPKELE_ITERATOR_H */ 216#endif /* __OPKELE_ITERATOR_H */
diff --git a/include/opkele/types.h b/include/opkele/types.h
index 6ab51ef..a3b657d 100644
--- a/include/opkele/types.h
+++ b/include/opkele/types.h
@@ -1,229 +1,230 @@
1#ifndef __OPKELE_TYPES_H 1#ifndef __OPKELE_TYPES_H
2#define __OPKELE_TYPES_H 2#define __OPKELE_TYPES_H
3 3
4/** 4/**
5 * @file 5 * @file
6 * @brief various types declarations 6 * @brief various types declarations
7 */ 7 */
8 8
9#include <cstring> 9#include <cstring>
10#include <ostream> 10#include <ostream>
11#include <vector> 11#include <vector>
12#include <string> 12#include <string>
13#include <map> 13#include <map>
14#include <set> 14#include <set>
15#include <list> 15#include <list>
16#include <opkele/iterator.h> 16#include <opkele/iterator.h>
17#include <opkele/tr1-mem.h> 17#include <opkele/tr1-mem.h>
18 18
19namespace opkele { 19namespace opkele {
20 using std::vector; 20 using std::vector;
21 using std::string; 21 using std::string;
22 using std::map; 22 using std::map;
23 using std::ostream; 23 using std::ostream;
24 using std::multimap; 24 using std::multimap;
25 using std::set; 25 using std::set;
26 using std::list; 26 using std::list;
27 using std::iterator; 27 using std::iterator;
28 using std::forward_iterator_tag; 28 using std::forward_iterator_tag;
29 29
30 /** 30 /**
31 * the OpenID operation mode 31 * the OpenID operation mode
32 */ 32 */
33 typedef enum _mode_t { 33 typedef enum _mode_t {
34 mode_unknown = 0, 34 mode_unknown = 0,
35 mode_associate, 35 mode_associate,
36 mode_checkid_immediate, 36 mode_checkid_immediate,
37 mode_checkid_setup, 37 mode_checkid_setup,
38 mode_check_association 38 mode_check_association
39 } mode_t; 39 } mode_t;
40 40
41 /** 41 /**
42 * the association secret container 42 * the association secret container
43 */ 43 */
44 class secret_t : public vector<unsigned char> { 44 class secret_t : public vector<unsigned char> {
45 public: 45 public:
46 46
47 /** 47 /**
48 * xor the secret and hmac together and encode, using base64 48 * xor the secret and hmac together and encode, using base64
49 * @param key_d pointer to the message digest 49 * @param key_d pointer to the message digest
50 * @param rv reference to the return value 50 * @param rv reference to the return value
51 */ 51 */
52 void enxor_to_base64(const unsigned char *key_d,string& rv) const; 52 void enxor_to_base64(const unsigned char *key_d,string& rv) const;
53 /** 53 /**
54 * decode base64-encoded secret and xor it with the message digest 54 * decode base64-encoded secret and xor it with the message digest
55 * @param key_d pointer to the message digest 55 * @param key_d pointer to the message digest
56 * @param b64 base64-encoded secret value 56 * @param b64 base64-encoded secret value
57 */ 57 */
58 void enxor_from_base64(const unsigned char *key_d,const string& b64); 58 void enxor_from_base64(const unsigned char *key_d,const string& b64);
59 /** 59 /**
60 * plainly encode to base64 representation 60 * plainly encode to base64 representation
61 * @param rv reference to the return value 61 * @param rv reference to the return value
62 */ 62 */
63 void to_base64(string& rv) const; 63 void to_base64(string& rv) const;
64 /** 64 /**
65 * decode cleartext secret from base64 65 * decode cleartext secret from base64
66 * @param b64 base64-encoded representation of the secret value 66 * @param b64 base64-encoded representation of the secret value
67 */ 67 */
68 void from_base64(const string& b64); 68 void from_base64(const string& b64);
69 }; 69 };
70 70
71 /** 71 /**
72 * Interface to the association. 72 * Interface to the association.
73 */ 73 */
74 class association_t { 74 class association_t {
75 public: 75 public:
76 76
77 virtual ~association_t() { } 77 virtual ~association_t() { }
78 78
79 /** 79 /**
80 * retrieve the server with which association was established. 80 * retrieve the server with which association was established.
81 * @return server name 81 * @return server name
82 */ 82 */
83 virtual string server() const = 0; 83 virtual string server() const = 0;
84 /** 84 /**
85 * retrieve the association handle. 85 * retrieve the association handle.
86 * @return handle 86 * @return handle
87 */ 87 */
88 virtual string handle() const = 0; 88 virtual string handle() const = 0;
89 /** 89 /**
90 * retrieve the association type. 90 * retrieve the association type.
91 * @return association type 91 * @return association type
92 */ 92 */
93 virtual string assoc_type() const = 0; 93 virtual string assoc_type() const = 0;
94 /** 94 /**
95 * retrieve the association secret. 95 * retrieve the association secret.
96 * @return association secret 96 * @return association secret
97 */ 97 */
98 virtual secret_t secret() const = 0; 98 virtual secret_t secret() const = 0;
99 /** 99 /**
100 * retrieve the number of seconds the association expires in. 100 * retrieve the number of seconds the association expires in.
101 * @return seconds till expiration 101 * @return seconds till expiration
102 */ 102 */
103 virtual int expires_in() const = 0; 103 virtual int expires_in() const = 0;
104 /** 104 /**
105 * check whether the association is stateless. 105 * check whether the association is stateless.
106 * @return true if stateless 106 * @return true if stateless
107 */ 107 */
108 virtual bool stateless() const = 0; 108 virtual bool stateless() const = 0;
109 /** 109 /**
110 * check whether the association is expired. 110 * check whether the association is expired.
111 * @return true if expired 111 * @return true if expired
112 */ 112 */
113 virtual bool is_expired() const = 0; 113 virtual bool is_expired() const = 0;
114 }; 114 };
115 115
116 /** 116 /**
117 * the shared_ptr<> for association_t object type 117 * the shared_ptr<> for association_t object type
118 */ 118 */
119 typedef tr1mem::shared_ptr<association_t> assoc_t; 119 typedef tr1mem::shared_ptr<association_t> assoc_t;
120 120
121 class basic_openid_message { 121 class basic_openid_message {
122 public: 122 public:
123 typedef list<string> fields_t; 123 typedef list<string> fields_t;
124 typedef util::forward_iterator_proxy< 124 typedef util::forward_iterator_proxy<
125 string,const string&,const string* 125 string,const string&,const string*
126 > fields_iterator; 126 > fields_iterator;
127 127
128 basic_openid_message() { } 128 basic_openid_message() { }
129 virtual ~basic_openid_message() { }
129 basic_openid_message(const basic_openid_message& x); 130 basic_openid_message(const basic_openid_message& x);
130 void copy_to(basic_openid_message& x) const; 131 void copy_to(basic_openid_message& x) const;
131 132
132 virtual bool has_field(const string& n) const = 0; 133 virtual bool has_field(const string& n) const = 0;
133 virtual const string& get_field(const string& n) const = 0; 134 virtual const string& get_field(const string& n) const = 0;
134 135
135 virtual bool has_ns(const string& uri) const; 136 virtual bool has_ns(const string& uri) const;
136 virtual string get_ns(const string& uri) const; 137 virtual string get_ns(const string& uri) const;
137 138
138 virtual fields_iterator fields_begin() const = 0; 139 virtual fields_iterator fields_begin() const = 0;
139 virtual fields_iterator fields_end() const = 0; 140 virtual fields_iterator fields_end() const = 0;
140 141
141 virtual string append_query(const string& url) const; 142 virtual string append_query(const string& url) const;
142 virtual string query_string() const; 143 virtual string query_string() const;
143 144
144 145
145 virtual void reset_fields(); 146 virtual void reset_fields();
146 virtual void set_field(const string& n,const string& v); 147 virtual void set_field(const string& n,const string& v);
147 virtual void reset_field(const string& n); 148 virtual void reset_field(const string& n);
148 149
149 virtual void from_keyvalues(const string& kv); 150 virtual void from_keyvalues(const string& kv);
150 virtual void to_keyvalues(ostream& o) const; 151 virtual void to_keyvalues(ostream& o) const;
151 152
152 virtual void to_htmlhiddens(ostream& o) const; 153 virtual void to_htmlhiddens(ostream& o) const;
153 154
154 void add_to_signed(const string& fields); 155 void add_to_signed(const string& fields);
155 string find_ns(const string& uri,const char *pfx) const; 156 string find_ns(const string& uri,const char *pfx) const;
156 string allocate_ns(const string& uri,const char *pfx); 157 string allocate_ns(const string& uri,const char *pfx);
157 }; 158 };
158 159
159 class openid_message_t : public basic_openid_message, public map<string,string> { 160 class openid_message_t : public basic_openid_message, public map<string,string> {
160 public: 161 public:
161 openid_message_t() { } 162 openid_message_t() { }
162 openid_message_t(const basic_openid_message& x) 163 openid_message_t(const basic_openid_message& x)
163 : basic_openid_message(x) { } 164 : basic_openid_message(x) { }
164 165
165 void copy_to(basic_openid_message& x) const; 166 void copy_to(basic_openid_message& x) const;
166 167
167 bool has_field(const string& n) const; 168 bool has_field(const string& n) const;
168 const string& get_field(const string& n) const; 169 const string& get_field(const string& n) const;
169 virtual fields_iterator fields_begin() const; 170 virtual fields_iterator fields_begin() const;
170 virtual fields_iterator fields_end() const; 171 virtual fields_iterator fields_end() const;
171 172
172 void reset_fields(); 173 void reset_fields();
173 void set_field(const string& n,const string& v); 174 void set_field(const string& n,const string& v);
174 void reset_field(const string& n); 175 void reset_field(const string& n);
175 }; 176 };
176 177
177 /** 178 /**
178 * request/response parameters map 179 * request/response parameters map
179 */ 180 */
180 class params_t : public openid_message_t { 181 class params_t : public openid_message_t {
181 public: 182 public:
182 183
183 /** 184 /**
184 * check whether the parameter is present. 185 * check whether the parameter is present.
185 * @param n the parameter name 186 * @param n the parameter name
186 * @return true if yes 187 * @return true if yes
187 */ 188 */
188 bool has_param(const string& n) const { 189 bool has_param(const string& n) const {
189 return has_field(n); } 190 return has_field(n); }
190 /** 191 /**
191 * retrieve the parameter (const version) 192 * retrieve the parameter (const version)
192 * @param n the parameter name 193 * @param n the parameter name
193 * @return the parameter value 194 * @return the parameter value
194 * @throw failed_lookup if there is no such parameter 195 * @throw failed_lookup if there is no such parameter
195 */ 196 */
196 const string& get_param(const string& n) const { 197 const string& get_param(const string& n) const {
197 return get_field(n); } 198 return get_field(n); }
198 199
199 /** 200 /**
200 * parse the OpenID key/value data. 201 * parse the OpenID key/value data.
201 * @param kv the OpenID key/value data 202 * @param kv the OpenID key/value data
202 */ 203 */
203 void parse_keyvalues(const string& kv) { 204 void parse_keyvalues(const string& kv) {
204 from_keyvalues(kv); } 205 from_keyvalues(kv); }
205 206
206 string append_query(const string& url,const char *prefix="openid.") const; 207 string append_query(const string& url,const char *prefix="openid.") const;
207 208
208 }; 209 };
209 210
210 struct openid_endpoint_t { 211 struct openid_endpoint_t {
211 string uri; 212 string uri;
212 string claimed_id; 213 string claimed_id;
213 string local_id; 214 string local_id;
214 215
215 openid_endpoint_t() { } 216 openid_endpoint_t() { }
216 openid_endpoint_t(const string& u,const string& cid,const string& lid) 217 openid_endpoint_t(const string& u,const string& cid,const string& lid)
217 : uri(u), claimed_id(cid), local_id(lid) { } 218 : uri(u), claimed_id(cid), local_id(lid) { }
218 219
219 bool operator==(const openid_endpoint_t& x) const { 220 bool operator==(const openid_endpoint_t& x) const {
220 return uri==x.uri && local_id==x.local_id; } 221 return uri==x.uri && local_id==x.local_id; }
221 bool operator<(const openid_endpoint_t& x) const { 222 bool operator<(const openid_endpoint_t& x) const {
222 int c; 223 int c;
223 return (c=strcmp(uri.c_str(),x.uri.c_str())) 224 return (c=strcmp(uri.c_str(),x.uri.c_str()))
224 ? (c<0) : (strcmp(local_id.c_str(),x.local_id.c_str())<0); } 225 ? (c<0) : (strcmp(local_id.c_str(),x.local_id.c_str())<0); }
225 }; 226 };
226 227
227} 228}
228 229
229#endif /* __OPKELE_TYPES_H */ 230#endif /* __OPKELE_TYPES_H */
diff --git a/lib/basic_op.cc b/lib/basic_op.cc
index 18446dc..2d82147 100644
--- a/lib/basic_op.cc
+++ b/lib/basic_op.cc
@@ -1,330 +1,327 @@
1#include <time.h> 1#include <time.h>
2#include <cassert> 2#include <cassert>
3#include <openssl/sha.h> 3#include <openssl/sha.h>
4#include <openssl/hmac.h> 4#include <openssl/hmac.h>
5#include <opkele/data.h> 5#include <opkele/data.h>
6#include <opkele/basic_op.h> 6#include <opkele/basic_op.h>
7#include <opkele/exception.h> 7#include <opkele/exception.h>
8#include <opkele/util.h> 8#include <opkele/util.h>
9#include <opkele/uris.h> 9#include <opkele/uris.h>
10 10
11namespace opkele { 11namespace opkele {
12 12
13 void basic_OP::reset_vars() { 13 void basic_OP::reset_vars() {
14 assoc.reset(); 14 assoc.reset();
15 return_to.clear(); realm.clear(); 15 return_to.clear(); realm.clear();
16 claimed_id.clear(); identity.clear(); 16 claimed_id.clear(); identity.clear();
17 invalidate_handle.clear(); 17 invalidate_handle.clear();
18 } 18 }
19 19
20 bool basic_OP::has_return_to() const { 20 bool basic_OP::has_return_to() const {
21 return !return_to.empty(); 21 return !return_to.empty();
22 } 22 }
23 const string& basic_OP::get_return_to() const { 23 const string& basic_OP::get_return_to() const {
24 if(return_to.empty()) 24 if(return_to.empty())
25 throw no_return_to(OPKELE_CP_ "No return_to URL provided with request"); 25 throw no_return_to(OPKELE_CP_ "No return_to URL provided with request");
26 return return_to; 26 return return_to;
27 } 27 }
28 28
29 const string& basic_OP::get_realm() const { 29 const string& basic_OP::get_realm() const {
30 assert(!realm.empty()); 30 assert(!realm.empty());
31 return realm; 31 return realm;
32 } 32 }
33 33
34 bool basic_OP::has_identity() const { 34 bool basic_OP::has_identity() const {
35 return !identity.empty(); 35 return !identity.empty();
36 } 36 }
37 const string& basic_OP::get_claimed_id() const { 37 const string& basic_OP::get_claimed_id() const {
38 if(claimed_id.empty()) 38 if(claimed_id.empty())
39 throw non_identity(OPKELE_CP_ "attempting to retrieve claimed_id of non-identity related request"); 39 throw non_identity(OPKELE_CP_ "attempting to retrieve claimed_id of non-identity related request");
40 assert(!identity.empty()); 40 assert(!identity.empty());
41 return claimed_id; 41 return claimed_id;
42 } 42 }
43 const string& basic_OP::get_identity() const { 43 const string& basic_OP::get_identity() const {
44 if(identity.empty()) 44 if(identity.empty())
45 throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related request"); 45 throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related request");
46 assert(!claimed_id.empty()); 46 assert(!claimed_id.empty());
47 return identity; 47 return identity;
48 } 48 }
49 49
50 bool basic_OP::is_id_select() const { 50 bool basic_OP::is_id_select() const {
51 return identity==IDURI_SELECT20; 51 return identity==IDURI_SELECT20;
52 } 52 }
53 53
54 void basic_OP::select_identity(const string& c,const string& i) { 54 void basic_OP::select_identity(const string& c,const string& i) {
55 claimed_id = c; identity = i; 55 claimed_id = c; identity = i;
56 } 56 }
57 void basic_OP::set_claimed_id(const string& c) { 57 void basic_OP::set_claimed_id(const string& c) {
58 claimed_id = c; 58 claimed_id = c;
59 } 59 }
60 60
61 basic_openid_message& basic_OP::associate( 61 basic_openid_message& basic_OP::associate(
62 basic_openid_message& oum, 62 basic_openid_message& oum,
63 const basic_openid_message& inm) try { 63 const basic_openid_message& inm) try {
64 assert(inm.get_field("mode")=="associate"); 64 assert(inm.get_field("mode")=="associate");
65 util::dh_t dh; 65 util::dh_t dh;
66 util::bignum_t c_pub; 66 util::bignum_t c_pub;
67 unsigned char key_digest[SHA256_DIGEST_LENGTH]; 67 unsigned char key_digest[SHA256_DIGEST_LENGTH];
68 size_t d_len = 0; 68 size_t d_len = 0;
69 enum {
70 sess_cleartext, sess_dh_sha1, sess_dh_sha256
71 } st = sess_cleartext;
72 string sts = inm.get_field("session_type"); 69 string sts = inm.get_field("session_type");
73 string ats = inm.get_field("assoc_type"); 70 string ats = inm.get_field("assoc_type");
74 if(sts=="DH-SHA1" || sts=="DH-SHA256") { 71 if(sts=="DH-SHA1" || sts=="DH-SHA256") {
75 if(!(dh = DH_new())) 72 if(!(dh = DH_new()))
76 throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); 73 throw exception_openssl(OPKELE_CP_ "failed to DH_new()");
77 c_pub = util::base64_to_bignum(inm.get_field("dh_consumer_public")); 74 c_pub = util::base64_to_bignum(inm.get_field("dh_consumer_public"));
78 try { dh->p = util::base64_to_bignum(inm.get_field("dh_modulus")); 75 try { dh->p = util::base64_to_bignum(inm.get_field("dh_modulus"));
79 }catch(failed_lookup&) { 76 }catch(failed_lookup&) {
80 dh->p = util::dec_to_bignum(data::_default_p); } 77 dh->p = util::dec_to_bignum(data::_default_p); }
81 try { dh->g = util::base64_to_bignum(inm.get_field("dh_gen")); 78 try { dh->g = util::base64_to_bignum(inm.get_field("dh_gen"));
82 }catch(failed_lookup&) { 79 }catch(failed_lookup&) {
83 dh->g = util::dec_to_bignum(data::_default_g); } 80 dh->g = util::dec_to_bignum(data::_default_g); }
84 if(!DH_generate_key(dh)) 81 if(!DH_generate_key(dh))
85 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); 82 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()");
86 vector<unsigned char> ck(DH_size(dh)+1); 83 vector<unsigned char> ck(DH_size(dh)+1);
87 unsigned char *ckptr = &(ck.front())+1; 84 unsigned char *ckptr = &(ck.front())+1;
88 int cklen = DH_compute_key(ckptr,c_pub,dh); 85 int cklen = DH_compute_key(ckptr,c_pub,dh);
89 if(cklen<0) 86 if(cklen<0)
90 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); 87 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()");
91 if(cklen && (*ckptr)&0x80) { 88 if(cklen && (*ckptr)&0x80) {
92 (*(--ckptr)) = 0; ++cklen; } 89 (*(--ckptr)) = 0; ++cklen; }
93 if(sts=="DH-SHA1") { 90 if(sts=="DH-SHA1") {
94 SHA1(ckptr,cklen,key_digest); d_len = SHA_DIGEST_LENGTH; 91 SHA1(ckptr,cklen,key_digest); d_len = SHA_DIGEST_LENGTH;
95 }else if(sts=="DH-SHA256") { 92 }else if(sts=="DH-SHA256") {
96 SHA256(ckptr,cklen,key_digest); d_len = SHA256_DIGEST_LENGTH; 93 SHA256(ckptr,cklen,key_digest); d_len = SHA256_DIGEST_LENGTH;
97 }else 94 }else
98 throw internal_error(OPKELE_CP_ "I thought I knew the session type"); 95 throw internal_error(OPKELE_CP_ "I thought I knew the session type");
99 }else 96 }else
100 throw unsupported(OPKELE_CP_ "Unsupported session_type"); 97 throw unsupported(OPKELE_CP_ "Unsupported session_type");
101 assoc_t assoc; 98 assoc_t a;
102 if(ats=="HMAC-SHA1") 99 if(ats=="HMAC-SHA1")
103 assoc = alloc_assoc(ats,SHA_DIGEST_LENGTH,true); 100 a = alloc_assoc(ats,SHA_DIGEST_LENGTH,true);
104 else if(ats=="HMAC-SHA256") 101 else if(ats=="HMAC-SHA256")
105 assoc = alloc_assoc(ats,SHA256_DIGEST_LENGTH,true); 102 a = alloc_assoc(ats,SHA256_DIGEST_LENGTH,true);
106 else 103 else
107 throw unsupported(OPKELE_CP_ "Unsupported assoc_type"); 104 throw unsupported(OPKELE_CP_ "Unsupported assoc_type");
108 oum.reset_fields(); 105 oum.reset_fields();
109 oum.set_field("ns",OIURI_OPENID20); 106 oum.set_field("ns",OIURI_OPENID20);
110 oum.set_field("assoc_type",assoc->assoc_type()); 107 oum.set_field("assoc_type",a->assoc_type());
111 oum.set_field("assoc_handle",assoc->handle()); 108 oum.set_field("assoc_handle",a->handle());
112 oum.set_field("expires_in",util::long_to_string(assoc->expires_in())); 109 oum.set_field("expires_in",util::long_to_string(assoc->expires_in()));
113 secret_t secret = assoc->secret(); 110 secret_t secret = a->secret();
114 if(sts=="DH-SHA1" || sts=="DH-SHA256") { 111 if(sts=="DH-SHA1" || sts=="DH-SHA256") {
115 if(d_len != secret.size()) 112 if(d_len != secret.size())
116 throw bad_input(OPKELE_CP_ "Association secret and session MAC are not of the same size"); 113 throw bad_input(OPKELE_CP_ "Association secret and session MAC are not of the same size");
117 oum.set_field("session_type",sts); 114 oum.set_field("session_type",sts);
118 oum.set_field("dh_server_public",util::bignum_to_base64(dh->pub_key)); 115 oum.set_field("dh_server_public",util::bignum_to_base64(dh->pub_key));
119 string b64; secret.enxor_to_base64(key_digest,b64); 116 string b64; secret.enxor_to_base64(key_digest,b64);
120 oum.set_field("enc_mac_key",b64); 117 oum.set_field("enc_mac_key",b64);
121 }else /* TODO: support cleartext over encrypted connection */ 118 }else /* TODO: support cleartext over encrypted connection */
122 throw unsupported(OPKELE_CP_ "Unsupported session type"); 119 throw unsupported(OPKELE_CP_ "Unsupported session type");
123 return oum; 120 return oum;
124 } catch(unsupported& u) { 121 } catch(unsupported& u) {
125 oum.reset_fields(); 122 oum.reset_fields();
126 oum.set_field("ns",OIURI_OPENID20); 123 oum.set_field("ns",OIURI_OPENID20);
127 oum.set_field("error",u.what()); 124 oum.set_field("error",u.what());
128 oum.set_field("error_code","unsupported-type"); 125 oum.set_field("error_code","unsupported-type");
129 oum.set_field("session_type","DH-SHA256"); 126 oum.set_field("session_type","DH-SHA256");
130 oum.set_field("assoc_type","HMAC-SHA256"); 127 oum.set_field("assoc_type","HMAC-SHA256");
131 return oum; 128 return oum;
132 } 129 }
133 130
134 void basic_OP::checkid_(const basic_openid_message& inm, 131 void basic_OP::checkid_(const basic_openid_message& inm,
135 extension_t *ext) { 132 extension_t *ext) {
136 reset_vars(); 133 reset_vars();
137 string mode = inm.get_field("mode"); 134 string modestr = inm.get_field("mode");
138 if(mode=="checkid_setup") 135 if(modestr=="checkid_setup")
139 mode = mode_checkid_setup; 136 mode = mode_checkid_setup;
140 else if(mode=="checkid_immediate") 137 else if(modestr=="checkid_immediate")
141 mode = mode_checkid_immediate; 138 mode = mode_checkid_immediate;
142 else 139 else
143 throw bad_input(OPKELE_CP_ "Invalid checkid_* mode"); 140 throw bad_input(OPKELE_CP_ "Invalid checkid_* mode");
144 try { 141 try {
145 assoc = retrieve_assoc(invalidate_handle=inm.get_field("assoc_handle")); 142 assoc = retrieve_assoc(invalidate_handle=inm.get_field("assoc_handle"));
146 invalidate_handle.clear(); 143 invalidate_handle.clear();
147 }catch(failed_lookup&) { } 144 }catch(failed_lookup&) { }
148 try { 145 try {
149 openid2 = (inm.get_field("ns")==OIURI_OPENID20); 146 openid2 = (inm.get_field("ns")==OIURI_OPENID20);
150 }catch(failed_lookup&) { openid2 = false; } 147 }catch(failed_lookup&) { openid2 = false; }
151 try { 148 try {
152 return_to = inm.get_field("return_to"); 149 return_to = inm.get_field("return_to");
153 }catch(failed_lookup&) { } 150 }catch(failed_lookup&) { }
154 if(openid2) { 151 if(openid2) {
155 try { 152 try {
156 realm = inm.get_field("realm"); 153 realm = inm.get_field("realm");
157 }catch(failed_lookup&) { 154 }catch(failed_lookup&) {
158 try { 155 try {
159 realm = inm.get_field("trust_root"); 156 realm = inm.get_field("trust_root");
160 }catch(failed_lookup&) { 157 }catch(failed_lookup&) {
161 if(return_to.empty()) 158 if(return_to.empty())
162 throw bad_input(OPKELE_CP_ 159 throw bad_input(OPKELE_CP_
163 "Both realm and return_to are unset"); 160 "Both realm and return_to are unset");
164 realm = return_to; 161 realm = return_to;
165 } 162 }
166 } 163 }
167 }else{ 164 }else{
168 try { 165 try {
169 realm = inm.get_field("trust_root"); 166 realm = inm.get_field("trust_root");
170 }catch(failed_lookup&) { 167 }catch(failed_lookup&) {
171 if(return_to.empty()) 168 if(return_to.empty())
172 throw bad_input(OPKELE_CP_ 169 throw bad_input(OPKELE_CP_
173 "Both realm and return_to are unset"); 170 "Both realm and return_to are unset");
174 realm = return_to; 171 realm = return_to;
175 } 172 }
176 } 173 }
177 try { 174 try {
178 identity = inm.get_field("identity"); 175 identity = inm.get_field("identity");
179 try { 176 try {
180 claimed_id = inm.get_field("claimed_id"); 177 claimed_id = inm.get_field("claimed_id");
181 }catch(failed_lookup&) { 178 }catch(failed_lookup&) {
182 if(openid2) 179 if(openid2)
183 throw bad_input(OPKELE_CP_ 180 throw bad_input(OPKELE_CP_
184 "claimed_id and identity must be either both present or both absent"); 181 "claimed_id and identity must be either both present or both absent");
185 claimed_id = identity; 182 claimed_id = identity;
186 } 183 }
187 }catch(failed_lookup&) { 184 }catch(failed_lookup&) {
188 if(openid2 && inm.has_field("claimed_id")) 185 if(openid2 && inm.has_field("claimed_id"))
189 throw bad_input(OPKELE_CP_ 186 throw bad_input(OPKELE_CP_
190 "claimed_id and identity must be either both present or both absent"); 187 "claimed_id and identity must be either both present or both absent");
191 } 188 }
192 verify_return_to(); 189 verify_return_to();
193 if(ext) ext->op_checkid_hook(inm); 190 if(ext) ext->op_checkid_hook(inm);
194 } 191 }
195 192
196 basic_openid_message& basic_OP::id_res(basic_openid_message& om, 193 basic_openid_message& basic_OP::id_res(basic_openid_message& om,
197 extension_t *ext) { 194 extension_t *ext) {
198 assert(!return_to.empty()); 195 assert(!return_to.empty());
199 assert(!is_id_select()); 196 assert(!is_id_select());
200 if(!assoc) { 197 if(!assoc) {
201 assoc = alloc_assoc("HMAC-SHA256",SHA256_DIGEST_LENGTH,true); 198 assoc = alloc_assoc("HMAC-SHA256",SHA256_DIGEST_LENGTH,true);
202 } 199 }
203 time_t now = time(0); 200 time_t now = time(0);
204 struct tm gmt; gmtime_r(&now,&gmt); 201 struct tm gmt; gmtime_r(&now,&gmt);
205 char w3timestr[24]; 202 char w3timestr[24];
206 if(!strftime(w3timestr,sizeof(w3timestr),"%Y-%m-%dT%H:%M:%SZ",&gmt)) 203 if(!strftime(w3timestr,sizeof(w3timestr),"%Y-%m-%dT%H:%M:%SZ",&gmt))
207 throw failed_conversion(OPKELE_CP_ 204 throw failed_conversion(OPKELE_CP_
208 "Failed to build time string for nonce" ); 205 "Failed to build time string for nonce" );
209 om.set_field("ns",OIURI_OPENID20); 206 om.set_field("ns",OIURI_OPENID20);
210 om.set_field("mode","id_res"); 207 om.set_field("mode","id_res");
211 om.set_field("op_endpoint",get_op_endpoint()); 208 om.set_field("op_endpoint",get_op_endpoint());
212 string ats = "ns,mode,op_endpoint,return_to,response_nonce," 209 string ats = "ns,mode,op_endpoint,return_to,response_nonce,"
213 "assoc_handle,signed"; 210 "assoc_handle,signed";
214 if(!identity.empty()) { 211 if(!identity.empty()) {
215 om.set_field("identity",identity); 212 om.set_field("identity",identity);
216 om.set_field("claimed_id",claimed_id); 213 om.set_field("claimed_id",claimed_id);
217 ats += ",identity,claimed_id"; 214 ats += ",identity,claimed_id";
218 } 215 }
219 om.set_field("return_to",return_to); 216 om.set_field("return_to",return_to);
220 string nonce = w3timestr; 217 string nonce = w3timestr;
221 om.set_field("response_nonce",alloc_nonce(nonce)); 218 om.set_field("response_nonce",alloc_nonce(nonce));
222 if(!invalidate_handle.empty()) { 219 if(!invalidate_handle.empty()) {
223 om.set_field("invalidate_handle",invalidate_handle); 220 om.set_field("invalidate_handle",invalidate_handle);
224 ats += ",invalidate_handle"; 221 ats += ",invalidate_handle";
225 } 222 }
226 om.set_field("assoc_handle",assoc->handle()); 223 om.set_field("assoc_handle",assoc->handle());
227 om.add_to_signed(ats); 224 om.add_to_signed(ats);
228 if(ext) ext->op_id_res_hook(om); 225 if(ext) ext->op_id_res_hook(om);
229 om.set_field("sig",util::base64_signature(assoc,om)); 226 om.set_field("sig",util::base64_signature(assoc,om));
230 return om; 227 return om;
231 } 228 }
232 229
233 basic_openid_message& basic_OP::cancel(basic_openid_message& om) { 230 basic_openid_message& basic_OP::cancel(basic_openid_message& om) {
234 assert(!return_to.empty()); 231 assert(!return_to.empty());
235 om.set_field("ns",OIURI_OPENID20); 232 om.set_field("ns",OIURI_OPENID20);
236 om.set_field("mode","cancel"); 233 om.set_field("mode","cancel");
237 return om; 234 return om;
238 } 235 }
239 236
240 basic_openid_message& basic_OP::error(basic_openid_message& om, 237 basic_openid_message& basic_OP::error(basic_openid_message& om,
241 const string& error,const string& contact, 238 const string& err,const string& contact,
242 const string& reference ) { 239 const string& reference ) {
243 assert(!return_to.empty()); 240 assert(!return_to.empty());
244 om.set_field("ns",OIURI_OPENID20); 241 om.set_field("ns",OIURI_OPENID20);
245 om.set_field("mode","error"); 242 om.set_field("mode","error");
246 om.set_field("error",error); 243 om.set_field("error",err);
247 om.set_field("contact",contact); 244 if(!contact.empty()) om.set_field("contact",contact);
248 om.set_field("reference",reference); 245 if(!reference.empty()) om.set_field("reference",reference);
249 return om; 246 return om;
250 } 247 }
251 248
252 basic_openid_message& basic_OP::setup_needed( 249 basic_openid_message& basic_OP::setup_needed(
253 basic_openid_message& oum,const basic_openid_message& inm) { 250 basic_openid_message& oum,const basic_openid_message& inm) {
254 assert(mode==mode_checkid_immediate); 251 assert(mode==mode_checkid_immediate);
255 assert(!return_to.empty()); 252 assert(!return_to.empty());
256 if(openid2) { 253 if(openid2) {
257 oum.set_field("ns",OIURI_OPENID20); 254 oum.set_field("ns",OIURI_OPENID20);
258 oum.set_field("mode","setup_needed"); 255 oum.set_field("mode","setup_needed");
259 }else{ 256 }else{
260 oum.set_field("mode","id_res"); 257 oum.set_field("mode","id_res");
261 static const string setupmode = "checkid_setup"; 258 static const string setupmode = "checkid_setup";
262 oum.set_field("user_setup_url", 259 oum.set_field("user_setup_url",
263 util::change_mode_message_proxy(inm,setupmode) 260 util::change_mode_message_proxy(inm,setupmode)
264 .append_query(get_op_endpoint())); 261 .append_query(get_op_endpoint()));
265 } 262 }
266 return oum; 263 return oum;
267 } 264 }
268 265
269 basic_openid_message& basic_OP::check_authentication( 266 basic_openid_message& basic_OP::check_authentication(
270 basic_openid_message& oum, 267 basic_openid_message& oum,
271 const basic_openid_message& inm) try { 268 const basic_openid_message& inm) try {
272 assert(inm.get_field("mode")=="check_authentication"); 269 assert(inm.get_field("mode")=="check_authentication");
273 oum.reset_fields(); 270 oum.reset_fields();
274 oum.set_field("ns",OIURI_OPENID20); 271 oum.set_field("ns",OIURI_OPENID20);
275 bool o2; 272 bool o2;
276 try { 273 try {
277 o2 = (inm.get_field("ns")==OIURI_OPENID20); 274 o2 = (inm.get_field("ns")==OIURI_OPENID20);
278 }catch(failed_lookup&) { o2 = false; } 275 }catch(failed_lookup&) { o2 = false; }
279 string nonce; 276 string nonce;
280 if(o2) { 277 if(o2) {
281 try { 278 try {
282 if(!check_nonce(nonce = inm.get_field("response_nonce"))) 279 if(!check_nonce(nonce = inm.get_field("response_nonce")))
283 throw failed_check_authentication(OPKELE_CP_ "Invalid nonce"); 280 throw failed_check_authentication(OPKELE_CP_ "Invalid nonce");
284 }catch(failed_lookup&) { 281 }catch(failed_lookup&) {
285 throw failed_check_authentication(OPKELE_CP_ "No nonce provided with check_authentication request"); 282 throw failed_check_authentication(OPKELE_CP_ "No nonce provided with check_authentication request");
286 } 283 }
287 } 284 }
288 try { 285 try {
289 assoc = retrieve_assoc(inm.get_field("assoc_handle")); 286 assoc = retrieve_assoc(inm.get_field("assoc_handle"));
290 if(!assoc->stateless()) 287 if(!assoc->stateless())
291 throw failed_check_authentication(OPKELE_CP_ "Will not do check_authentication on a stateful handle"); 288 throw failed_check_authentication(OPKELE_CP_ "Will not do check_authentication on a stateful handle");
292 }catch(failed_lookup&) { 289 }catch(failed_lookup&) {
293 throw failed_check_authentication(OPKELE_CP_ "No assoc_handle or invalid assoc_handle specified with check_authentication request"); 290 throw failed_check_authentication(OPKELE_CP_ "No assoc_handle or invalid assoc_handle specified with check_authentication request");
294 } 291 }
295 static const string idresmode = "id_res"; 292 static const string idresmode = "id_res";
296 try { 293 try {
297 if(util::base64_signature(assoc,util::change_mode_message_proxy(inm,idresmode))!=inm.get_field("sig")) 294 if(util::base64_signature(assoc,util::change_mode_message_proxy(inm,idresmode))!=inm.get_field("sig"))
298 throw failed_check_authentication(OPKELE_CP_ "Signature mismatch"); 295 throw failed_check_authentication(OPKELE_CP_ "Signature mismatch");
299 }catch(failed_lookup&) { 296 }catch(failed_lookup&) {
300 throw failed_check_authentication(OPKELE_CP_ "failed to calculate signature"); 297 throw failed_check_authentication(OPKELE_CP_ "failed to calculate signature");
301 } 298 }
302 oum.set_field("is_valid","true"); 299 oum.set_field("is_valid","true");
303 try { 300 try {
304 string h = inm.get_field("invalidate_handle"); 301 string h = inm.get_field("invalidate_handle");
305 try { 302 try {
306 assoc_t ih = retrieve_assoc(h); 303 assoc_t ih = retrieve_assoc(h);
307 }catch(invalid_handle& ih) { 304 }catch(invalid_handle& ih) {
308 oum.set_field("invalidate_handle",h); 305 oum.set_field("invalidate_handle",h);
309 }catch(failed_lookup& ih) { 306 }catch(failed_lookup& ih) {
310 oum.set_field("invalidate_handle",h); 307 oum.set_field("invalidate_handle",h);
311 } 308 }
312 }catch(failed_lookup&) { } 309 }catch(failed_lookup&) { }
313 if(o2) { 310 if(o2) {
314 assert(!nonce.empty()); 311 assert(!nonce.empty());
315 invalidate_nonce(nonce); 312 invalidate_nonce(nonce);
316 } 313 }
317 return oum; 314 return oum;
318 }catch(failed_check_authentication& ) { 315 }catch(failed_check_authentication& ) {
319 oum.set_field("is_valid","false"); 316 oum.set_field("is_valid","false");
320 return oum; 317 return oum;
321 } 318 }
322 319
323 void basic_OP::verify_return_to() { 320 void basic_OP::verify_return_to() {
324 if(realm.find('#')!=string::npos) 321 if(realm.find('#')!=string::npos)
325 throw opkele::bad_realm(OPKELE_CP_ "authentication realm contains URI fragment"); 322 throw opkele::bad_realm(OPKELE_CP_ "authentication realm contains URI fragment");
326 if(!util::uri_matches_realm(return_to,realm)) 323 if(!util::uri_matches_realm(return_to,realm))
327 throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match realm"); 324 throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match realm");
328 } 325 }
329 326
330} 327}
diff --git a/lib/basic_rp.cc b/lib/basic_rp.cc
index bd45d99..a0ad130 100644
--- a/lib/basic_rp.cc
+++ b/lib/basic_rp.cc
@@ -1,297 +1,299 @@
1#include <cassert>
1#include <openssl/sha.h> 2#include <openssl/sha.h>
2#include <openssl/hmac.h> 3#include <openssl/hmac.h>
3#include <opkele/basic_rp.h> 4#include <opkele/basic_rp.h>
4#include <opkele/exception.h> 5#include <opkele/exception.h>
5#include <opkele/uris.h> 6#include <opkele/uris.h>
6#include <opkele/data.h> 7#include <opkele/data.h>
7#include <opkele/util.h> 8#include <opkele/util.h>
8#include <opkele/curl.h> 9#include <opkele/curl.h>
9 10
10namespace opkele { 11namespace opkele {
11 12
12 static void dh_get_secret( 13 static void dh_get_secret(
13 secret_t& secret, const basic_openid_message& om, 14 secret_t& secret, const basic_openid_message& om,
14 const char *exp_assoc, const char *exp_sess, 15 const char *exp_assoc, const char *exp_sess,
15 util::dh_t& dh, 16 util::dh_t& dh,
16 size_t d_len, unsigned char *(*d_fun)(const unsigned char*,size_t,unsigned char*), 17 size_t d_len, unsigned char *(*d_fun)(const unsigned char*,size_t,unsigned char*),
17 size_t exp_s_len) try { 18 size_t exp_s_len) try {
18 if(om.get_field("assoc_type")!=exp_assoc || om.get_field("session_type")!=exp_sess) 19 if(om.get_field("assoc_type")!=exp_assoc || om.get_field("session_type")!=exp_sess)
19 throw bad_input(OPKELE_CP_ "Unexpected associate response"); 20 throw bad_input(OPKELE_CP_ "Unexpected associate response");
20 util::bignum_t s_pub = util::base64_to_bignum(om.get_field("dh_server_public")); 21 util::bignum_t s_pub = util::base64_to_bignum(om.get_field("dh_server_public"));
21 vector<unsigned char> ck(DH_size(dh)+1); 22 vector<unsigned char> ck(DH_size(dh)+1);
22 unsigned char *ckptr = &(ck.front())+1; 23 unsigned char *ckptr = &(ck.front())+1;
23 int cklen = DH_compute_key(ckptr,s_pub,dh); 24 int cklen = DH_compute_key(ckptr,s_pub,dh);
24 if(cklen<0) 25 if(cklen<0)
25 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); 26 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()");
26 if(cklen && (*ckptr)&0x80) { 27 if(cklen && (*ckptr)&0x80) {
27 (*(--ckptr))=0; ++cklen; } 28 (*(--ckptr))=0; ++cklen; }
28 unsigned char key_digest[d_len]; 29 assert(d_len<=SHA256_DIGEST_LENGTH);
30 unsigned char key_digest[SHA256_DIGEST_LENGTH];
29 secret.enxor_from_base64((*d_fun)(ckptr,cklen,key_digest),om.get_field("enc_mac_key")); 31 secret.enxor_from_base64((*d_fun)(ckptr,cklen,key_digest),om.get_field("enc_mac_key"));
30 if(secret.size()!=exp_s_len) 32 if(secret.size()!=exp_s_len)
31 throw bad_input(OPKELE_CP_ "Secret length isn't consistent with association type"); 33 throw bad_input(OPKELE_CP_ "Secret length isn't consistent with association type");
32 }catch(opkele::failed_lookup& ofl) { 34 }catch(opkele::failed_lookup& ofl) {
33 throw bad_input(OPKELE_CP_ "Incoherent response from OP"); 35 throw bad_input(OPKELE_CP_ "Incoherent response from OP");
34 } OPKELE_RETHROW 36 } OPKELE_RETHROW
35 37
36 static void direct_request(basic_openid_message& oum,const basic_openid_message& inm,const string& OP) { 38 static void direct_request(basic_openid_message& oum,const basic_openid_message& inm,const string& OP) {
37 util::curl_pick_t curl = util::curl_pick_t::easy_init(); 39 util::curl_pick_t curl = util::curl_pick_t::easy_init();
38 if(!curl) 40 if(!curl)
39 throw exception_curl(OPKELE_CP_ "failed to initialize curl"); 41 throw exception_curl(OPKELE_CP_ "failed to initialize curl");
40 string request = inm.query_string(); 42 string request = inm.query_string();
41 CURLcode r; 43 CURLcode r;
42 (r=curl.misc_sets()) 44 (r=curl.misc_sets())
43 || (r=curl.easy_setopt(CURLOPT_URL,OP.c_str())) 45 || (r=curl.easy_setopt(CURLOPT_URL,OP.c_str()))
44 || (r=curl.easy_setopt(CURLOPT_POST,1)) 46 || (r=curl.easy_setopt(CURLOPT_POST,1))
45 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data())) 47 || (r=curl.easy_setopt(CURLOPT_POSTFIELDS,request.data()))
46 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length())) 48 || (r=curl.easy_setopt(CURLOPT_POSTFIELDSIZE,request.length()))
47 || (r=curl.set_write()); 49 || (r=curl.set_write());
48 if(r) 50 if(r)
49 throw exception_curl(OPKELE_CP_ "failed to set curly options",r); 51 throw exception_curl(OPKELE_CP_ "failed to set curly options",r);
50 if( (r=curl.easy_perform()) ) 52 if( (r=curl.easy_perform()) )
51 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); 53 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r);
52 oum.from_keyvalues(curl.response); 54 oum.from_keyvalues(curl.response);
53 } 55 }
54 56
55 57
56 assoc_t basic_RP::associate(const string& OP) { 58 assoc_t basic_RP::associate(const string& OP) {
57 util::dh_t dh = DH_new(); 59 util::dh_t dh = DH_new();
58 if(!dh) 60 if(!dh)
59 throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); 61 throw exception_openssl(OPKELE_CP_ "failed to DH_new()");
60 dh->p = util::dec_to_bignum(data::_default_p); 62 dh->p = util::dec_to_bignum(data::_default_p);
61 dh->g = util::dec_to_bignum(data::_default_g); 63 dh->g = util::dec_to_bignum(data::_default_g);
62 if(!DH_generate_key(dh)) 64 if(!DH_generate_key(dh))
63 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); 65 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()");
64 openid_message_t req; 66 openid_message_t req;
65 req.set_field("ns",OIURI_OPENID20); 67 req.set_field("ns",OIURI_OPENID20);
66 req.set_field("mode","associate"); 68 req.set_field("mode","associate");
67 req.set_field("dh_modulus",util::bignum_to_base64(dh->p)); 69 req.set_field("dh_modulus",util::bignum_to_base64(dh->p));
68 req.set_field("dh_gen",util::bignum_to_base64(dh->g)); 70 req.set_field("dh_gen",util::bignum_to_base64(dh->g));
69 req.set_field("dh_consumer_public",util::bignum_to_base64(dh->pub_key)); 71 req.set_field("dh_consumer_public",util::bignum_to_base64(dh->pub_key));
70 openid_message_t res; 72 openid_message_t res;
71 req.set_field("assoc_type","HMAC-SHA256"); 73 req.set_field("assoc_type","HMAC-SHA256");
72 req.set_field("session_type","DH-SHA256"); 74 req.set_field("session_type","DH-SHA256");
73 secret_t secret; 75 secret_t secret;
74 int expires_in; 76 int expires_in;
75 try { 77 try {
76 direct_request(res,req,OP); 78 direct_request(res,req,OP);
77 dh_get_secret( secret, res, 79 dh_get_secret( secret, res,
78 "HMAC-SHA256", "DH-SHA256", 80 "HMAC-SHA256", "DH-SHA256",
79 dh, SHA256_DIGEST_LENGTH, SHA256, SHA256_DIGEST_LENGTH ); 81 dh, SHA256_DIGEST_LENGTH, SHA256, SHA256_DIGEST_LENGTH );
80 expires_in = util::string_to_long(res.get_field("expires_in")); 82 expires_in = util::string_to_long(res.get_field("expires_in"));
81 }catch(exception& e) { 83 }catch(exception&) {
82 try { 84 try {
83 req.set_field("assoc_type","HMAC-SHA1"); 85 req.set_field("assoc_type","HMAC-SHA1");
84 req.set_field("session_type","DH-SHA1"); 86 req.set_field("session_type","DH-SHA1");
85 direct_request(res,req,OP); 87 direct_request(res,req,OP);
86 dh_get_secret( secret, res, 88 dh_get_secret( secret, res,
87 "HMAC-SHA1", "DH-SHA1", 89 "HMAC-SHA1", "DH-SHA1",
88 dh, SHA_DIGEST_LENGTH, SHA1, SHA_DIGEST_LENGTH ); 90 dh, SHA_DIGEST_LENGTH, SHA1, SHA_DIGEST_LENGTH );
89 expires_in = util::string_to_long(res.get_field("expires_in")); 91 expires_in = util::string_to_long(res.get_field("expires_in"));
90 }catch(bad_input& e) { 92 }catch(bad_input&) {
91 throw dumb_RP(OPKELE_CP_ "OP failed to supply an association"); 93 throw dumb_RP(OPKELE_CP_ "OP failed to supply an association");
92 } 94 }
93 } 95 }
94 return store_assoc( 96 return store_assoc(
95 OP, res.get_field("assoc_handle"), 97 OP, res.get_field("assoc_handle"),
96 res.get_field("assoc_type"), secret, 98 res.get_field("assoc_type"), secret,
97 expires_in ); 99 expires_in );
98 } 100 }
99 101
100 basic_openid_message& basic_RP::checkid_( 102 basic_openid_message& basic_RP::checkid_(
101 basic_openid_message& rv, 103 basic_openid_message& rv,
102 mode_t mode, 104 mode_t mode,
103 const string& return_to,const string& realm, 105 const string& return_to,const string& realm,
104 extension_t *ext) { 106 extension_t *ext) {
105 rv.reset_fields(); 107 rv.reset_fields();
106 rv.set_field("ns",OIURI_OPENID20); 108 rv.set_field("ns",OIURI_OPENID20);
107 if(mode==mode_checkid_immediate) 109 if(mode==mode_checkid_immediate)
108 rv.set_field("mode","checkid_immediate"); 110 rv.set_field("mode","checkid_immediate");
109 else if(mode==mode_checkid_setup) 111 else if(mode==mode_checkid_setup)
110 rv.set_field("mode","checkid_setup"); 112 rv.set_field("mode","checkid_setup");
111 else 113 else
112 throw bad_input(OPKELE_CP_ "unknown checkid_* mode"); 114 throw bad_input(OPKELE_CP_ "unknown checkid_* mode");
113 if(realm.empty() && return_to.empty()) 115 if(realm.empty() && return_to.empty())
114 throw bad_input(OPKELE_CP_ "At least one of realm and return_to must be non-empty"); 116 throw bad_input(OPKELE_CP_ "At least one of realm and return_to must be non-empty");
115 if(!realm.empty()) { 117 if(!realm.empty()) {
116 rv.set_field("realm",realm); 118 rv.set_field("realm",realm);
117 rv.set_field("trust_root",realm); 119 rv.set_field("trust_root",realm);
118 } 120 }
119 if(!return_to.empty()) 121 if(!return_to.empty())
120 rv.set_field("return_to",return_to); 122 rv.set_field("return_to",return_to);
121 const openid_endpoint_t& ep = get_endpoint(); 123 const openid_endpoint_t& ep = get_endpoint();
122 rv.set_field("claimed_id",ep.claimed_id); 124 rv.set_field("claimed_id",ep.claimed_id);
123 rv.set_field("identity",ep.local_id); 125 rv.set_field("identity",ep.local_id);
124 try { 126 try {
125 rv.set_field("assoc_handle",find_assoc(ep.uri)->handle()); 127 rv.set_field("assoc_handle",find_assoc(ep.uri)->handle());
126 }catch(dumb_RP& drp) { 128 }catch(dumb_RP& drp) {
127 }catch(failed_lookup& fl) { 129 }catch(failed_lookup& fl) {
128 try { 130 try {
129 rv.set_field("assoc_handle",associate(ep.uri)->handle()); 131 rv.set_field("assoc_handle",associate(ep.uri)->handle());
130 }catch(dumb_RP& drp) { } 132 }catch(dumb_RP& drp) { }
131 } OPKELE_RETHROW 133 } OPKELE_RETHROW
132 if(ext) ext->rp_checkid_hook(rv); 134 if(ext) ext->rp_checkid_hook(rv);
133 return rv; 135 return rv;
134 } 136 }
135 137
136 class signed_part_message_proxy : public basic_openid_message { 138 class signed_part_message_proxy : public basic_openid_message {
137 public: 139 public:
138 const basic_openid_message& x; 140 const basic_openid_message& x;
139 set<string> signeds; 141 set<string> signeds;
140 142
141 signed_part_message_proxy(const basic_openid_message& xx) : x(xx) { 143 signed_part_message_proxy(const basic_openid_message& xx) : x(xx) {
142 const string& slist = x.get_field("signed"); 144 const string& slist = x.get_field("signed");
143 string::size_type p = 0; 145 string::size_type p = 0;
144 while(true) { 146 while(true) {
145 string::size_type co = slist.find(',',p); 147 string::size_type co = slist.find(',',p);
146 string f = (co==string::npos) 148 string f = (co==string::npos)
147 ?slist.substr(p):slist.substr(p,co-p); 149 ?slist.substr(p):slist.substr(p,co-p);
148 signeds.insert(f); 150 signeds.insert(f);
149 if(co==string::npos) break; 151 if(co==string::npos) break;
150 p = co+1; 152 p = co+1;
151 } 153 }
152 } 154 }
153 155
154 bool has_field(const string& n) const { 156 bool has_field(const string& n) const {
155 return signeds.find(n)!=signeds.end() && x.has_field(n); } 157 return signeds.find(n)!=signeds.end() && x.has_field(n); }
156 const string& get_field(const string& n) const { 158 const string& get_field(const string& n) const {
157 if(signeds.find(n)==signeds.end()) 159 if(signeds.find(n)==signeds.end())
158 throw failed_lookup(OPKELE_CP_ "The field isn't known to be signed"); 160 throw failed_lookup(OPKELE_CP_ "The field isn't known to be signed");
159 return x.get_field(n); } 161 return x.get_field(n); }
160 162
161 fields_iterator fields_begin() const { 163 fields_iterator fields_begin() const {
162 return signeds.begin(); } 164 return signeds.begin(); }
163 fields_iterator fields_end() const { 165 fields_iterator fields_end() const {
164 return signeds.end(); } 166 return signeds.end(); }
165 }; 167 };
166 168
167 static void parse_query(const string& u,string::size_type q, 169 static void parse_query(const string& u,string::size_type q,
168 map<string,string>& p) { 170 map<string,string>& p) {
169 if(q==string::npos) 171 if(q==string::npos)
170 return; 172 return;
171 assert(u[q]=='?'); 173 assert(u[q]=='?');
172 ++q; 174 ++q;
173 string::size_type l = u.size(); 175 string::size_type l = u.size();
174 while(q<l) { 176 while(q<l) {
175 string::size_type eq = u.find('=',q); 177 string::size_type eq = u.find('=',q);
176 string::size_type am = u.find('&',q); 178 string::size_type am = u.find('&',q);
177 if(am==string::npos) { 179 if(am==string::npos) {
178 if(eq==string::npos) { 180 if(eq==string::npos) {
179 p[""] = u.substr(q); 181 p[""] = u.substr(q);
180 }else{ 182 }else{
181 p[u.substr(q,eq-q)] = u.substr(eq+1); 183 p[u.substr(q,eq-q)] = u.substr(eq+1);
182 } 184 }
183 break; 185 break;
184 }else{ 186 }else{
185 if(eq==string::npos || eq>am) { 187 if(eq==string::npos || eq>am) {
186 p[""] = u.substr(q,eq-q); 188 p[""] = u.substr(q,eq-q);
187 }else{ 189 }else{
188 p[u.substr(q,eq-q)] = u.substr(eq+1,am-eq-1); 190 p[u.substr(q,eq-q)] = u.substr(eq+1,am-eq-1);
189 } 191 }
190 q = ++am; 192 q = ++am;
191 } 193 }
192 } 194 }
193 } 195 }
194 196
195 void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) { 197 void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) {
196 bool o2 = om.has_field("ns") 198 bool o2 = om.has_field("ns")
197 && om.get_field("ns")==OIURI_OPENID20; 199 && om.get_field("ns")==OIURI_OPENID20;
198 if( (!o2) && om.has_field("user_setup_url")) 200 if( (!o2) && om.has_field("user_setup_url"))
199 throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided", 201 throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided",
200 om.get_field("user_setup_url")); 202 om.get_field("user_setup_url"));
201 string m = om.get_field("mode"); 203 string m = om.get_field("mode");
202 if(o2 && m=="setup_needed") 204 if(o2 && m=="setup_needed")
203 throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided"); 205 throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided");
204 if(m=="cancel") 206 if(m=="cancel")
205 throw id_res_cancel(OPKELE_CP_ "authentication cancelled"); 207 throw id_res_cancel(OPKELE_CP_ "authentication cancelled");
206 bool go_dumb=false; 208 bool go_dumb=false;
207 try { 209 try {
208 string OP = o2 210 string OP = o2
209 ?om.get_field("op_endpoint") 211 ?om.get_field("op_endpoint")
210 :get_endpoint().uri; 212 :get_endpoint().uri;
211 assoc_t assoc = retrieve_assoc( 213 assoc_t assoc = retrieve_assoc(
212 OP,om.get_field("assoc_handle")); 214 OP,om.get_field("assoc_handle"));
213 if(om.get_field("sig")!=util::base64_signature(assoc,om)) 215 if(om.get_field("sig")!=util::base64_signature(assoc,om))
214 throw id_res_mismatch(OPKELE_CP_ "signature mismatch"); 216 throw id_res_mismatch(OPKELE_CP_ "signature mismatch");
215 }catch(dumb_RP& drp) { 217 }catch(dumb_RP& drp) {
216 go_dumb=true; 218 go_dumb=true;
217 }catch(failed_lookup& e) { 219 }catch(failed_lookup& e) {
218 go_dumb=true; 220 go_dumb=true;
219 } OPKELE_RETHROW 221 } OPKELE_RETHROW
220 if(go_dumb) { 222 if(go_dumb) {
221 try { 223 try {
222 string OP = o2 224 string OP = o2
223 ?om.get_field("op_endpoint") 225 ?om.get_field("op_endpoint")
224 :get_endpoint().uri; 226 :get_endpoint().uri;
225 check_authentication(OP,om); 227 check_authentication(OP,om);
226 }catch(failed_check_authentication& fca) { 228 }catch(failed_check_authentication& fca) {
227 throw id_res_failed(OPKELE_CP_ "failed to check_authentication()"); 229 throw id_res_failed(OPKELE_CP_ "failed to check_authentication()");
228 } OPKELE_RETHROW 230 } OPKELE_RETHROW
229 } 231 }
230 signed_part_message_proxy signeds(om); 232 signed_part_message_proxy signeds(om);
231 if(o2) { 233 if(o2) {
232 check_nonce(om.get_field("op_endpoint"), 234 check_nonce(om.get_field("op_endpoint"),
233 om.get_field("response_nonce")); 235 om.get_field("response_nonce"));
234 static const char *mustsign[] = { 236 static const char *mustsign[] = {
235 "op_endpoint", "return_to", "response_nonce", "assoc_handle", 237 "op_endpoint", "return_to", "response_nonce", "assoc_handle",
236 "claimed_id", "identity" }; 238 "claimed_id", "identity" };
237 for(int ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) { 239 for(size_t ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) {
238 if(om.has_field(mustsign[ms]) && !signeds.has_field(mustsign[ms])) 240 if(om.has_field(mustsign[ms]) && !signeds.has_field(mustsign[ms]))
239 throw bad_input(OPKELE_CP_ string("Field '")+mustsign[ms]+"' is not signed against the specs"); 241 throw bad_input(OPKELE_CP_ string("Field '")+mustsign[ms]+"' is not signed against the specs");
240 } 242 }
241 if( ( 243 if( (
242 (om.has_field("claimed_id")?1:0) 244 (om.has_field("claimed_id")?1:0)
243 ^ 245 ^
244 (om.has_field("identity")?1:0) 246 (om.has_field("identity")?1:0)
245 )&1 ) 247 )&1 )
246 throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent"); 248 throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent");
247 249
248 string turl = util::rfc_3986_normalize_uri(get_this_url()); 250 string turl = util::rfc_3986_normalize_uri(get_this_url());
249 util::strip_uri_fragment_part(turl); 251 util::strip_uri_fragment_part(turl);
250 string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to")); 252 string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to"));
251 util::strip_uri_fragment_part(rurl); 253 util::strip_uri_fragment_part(rurl);
252 string::size_type 254 string::size_type
253 tq = turl.find('?'), rq = rurl.find('?'); 255 tq = turl.find('?'), rq = rurl.find('?');
254 if( 256 if(
255 ((tq==string::npos)?turl:turl.substr(0,tq)) 257 ((tq==string::npos)?turl:turl.substr(0,tq))
256 != 258 !=
257 ((rq==string::npos)?rurl:rurl.substr(0,rq)) 259 ((rq==string::npos)?rurl:rurl.substr(0,rq))
258 ) 260 )
259 throw id_res_bad_return_to(OPKELE_CP_ "return_to url doesn't match request url"); 261 throw id_res_bad_return_to(OPKELE_CP_ "return_to url doesn't match request url");
260 map<string,string> tp; parse_query(turl,tq,tp); 262 map<string,string> tp; parse_query(turl,tq,tp);
261 map<string,string> rp; parse_query(rurl,rq,rp); 263 map<string,string> rp; parse_query(rurl,rq,rp);
262 for(map<string,string>::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) { 264 for(map<string,string>::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) {
263 map<string,string>::const_iterator tpi = tp.find(rpi->first); 265 map<string,string>::const_iterator tpi = tp.find(rpi->first);
264 if(tpi==tp.end()) 266 if(tpi==tp.end())
265 throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to is missing from the request"); 267 throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to is missing from the request");
266 if(tpi->second!=rpi->second) 268 if(tpi->second!=rpi->second)
267 throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to doesn't matche the request"); 269 throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to doesn't matche the request");
268 } 270 }
269 271
270 if(om.has_field("claimed_id")) { 272 if(om.has_field("claimed_id")) {
271 verify_OP( 273 verify_OP(
272 om.get_field("op_endpoint"), 274 om.get_field("op_endpoint"),
273 om.get_field("claimed_id"), 275 om.get_field("claimed_id"),
274 om.get_field("identity") ); 276 om.get_field("identity") );
275 } 277 }
276 278
277 } 279 }
278 if(ext) ext->rp_id_res_hook(om,signeds); 280 if(ext) ext->rp_id_res_hook(om,signeds);
279 } 281 }
280 282
281 void basic_RP::check_authentication(const string& OP, 283 void basic_RP::check_authentication(const string& OP,
282 const basic_openid_message& om){ 284 const basic_openid_message& om){
283 openid_message_t res; 285 openid_message_t res;
284 static const string checkauthmode = "check_authentication"; 286 static const string checkauthmode = "check_authentication";
285 direct_request(res,util::change_mode_message_proxy(om,checkauthmode),OP); 287 direct_request(res,util::change_mode_message_proxy(om,checkauthmode),OP);
286 if(res.has_field("is_valid")) { 288 if(res.has_field("is_valid")) {
287 if(res.get_field("is_valid")=="true") { 289 if(res.get_field("is_valid")=="true") {
288 if(res.has_field("invalidate_handle")) 290 if(res.has_field("invalidate_handle"))
289 invalidate_assoc(OP,res.get_field("invalidate_handle")); 291 invalidate_assoc(OP,res.get_field("invalidate_handle"));
290 return; 292 return;
291 } 293 }
292 } 294 }
293 throw failed_check_authentication( 295 throw failed_check_authentication(
294 OPKELE_CP_ "failed to verify response"); 296 OPKELE_CP_ "failed to verify response");
295 } 297 }
296 298
297} 299}
diff --git a/lib/discovery.cc b/lib/discovery.cc
index 6f58339..6f9926c 100644
--- a/lib/discovery.cc
+++ b/lib/discovery.cc
@@ -141,385 +141,385 @@ namespace opkele {
141 idis.clear(); 141 idis.clear();
142 if(strchr(i_leaders,id[0])) { 142 if(strchr(i_leaders,id[0])) {
143 /* TODO: further normalize xri identity? Like folding case 143 /* TODO: further normalize xri identity? Like folding case
144 * or whatever... */ 144 * or whatever... */
145 rv = id; 145 rv = id;
146 set<string> cids; 146 set<string> cids;
147 for(const struct service_type_t *st=op_service_types; 147 for(const struct service_type_t *st=op_service_types;
148 st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) { 148 st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) {
149 idis.clear(); 149 idis.clear();
150 discover_at( idis, 150 discover_at( idis,
151 xri_proxy + util::url_encode(id)+ 151 xri_proxy + util::url_encode(id)+
152 "?_xrd_t="+util::url_encode(st->uri)+ 152 "?_xrd_t="+util::url_encode(st->uri)+
153 "&_xrd_r=application/xrd%2Bxml" 153 "&_xrd_r=application/xrd%2Bxml"
154 ";sep=true;refs=true", 154 ";sep=true;refs=true",
155 xmode_xrd ); 155 xmode_xrd );
156 if(status_code==241) continue; 156 if(status_code==241) continue;
157 if(status_code!=100) 157 if(status_code!=100)
158 throw failed_xri_resolution(OPKELE_CP_ 158 throw failed_xri_resolution(OPKELE_CP_
159 "XRI resolution failed with '"+status_string+"' message" 159 "XRI resolution failed with '"+status_string+"' message"
160 ", while looking for SEP with type '"+st->uri+"'", status_code); 160 ", while looking for SEP with type '"+st->uri+"'", status_code);
161 if(idis.xrd.canonical_ids.empty()) 161 if(idis.xrd.canonical_ids.empty())
162 throw opkele::failed_discovery(OPKELE_CP_ "No CanonicalID found for XRI identity found"); 162 throw opkele::failed_discovery(OPKELE_CP_ "No CanonicalID found for XRI identity found");
163 string cid = idis.xrd.canonical_ids.begin()->second; 163 string cid = idis.xrd.canonical_ids.begin()->second;
164 if(cids.find(cid)==cids.end()) { 164 if(cids.find(cid)==cids.end()) {
165 cids.insert(cid); 165 cids.insert(cid);
166 idis.clear(); 166 idis.clear();
167 discover_at( idis, 167 discover_at( idis,
168 xri_proxy + util::url_encode(id)+ 168 xri_proxy + util::url_encode(id)+
169 "?_xrd_t="+util::url_encode(st->uri)+ 169 "?_xrd_t="+util::url_encode(st->uri)+
170 "&_xrd_r=application/xrd%2Bxml" 170 "&_xrd_r=application/xrd%2Bxml"
171 ";sep=true;refs=true", 171 ";sep=true;refs=true",
172 xmode_xrd ); 172 xmode_xrd );
173 if(status_code==241) continue; 173 if(status_code==241) continue;
174 if(status_code!=100) 174 if(status_code!=100)
175 throw failed_xri_resolution(OPKELE_CP_ 175 throw failed_xri_resolution(OPKELE_CP_
176 "XRI resolution failed with '"+status_string+"' message" 176 "XRI resolution failed with '"+status_string+"' message"
177 ", while looking for SEP with type '"+st->uri+"'" 177 ", while looking for SEP with type '"+st->uri+"'"
178 " on canonical id", status_code); 178 " on canonical id", status_code);
179 } 179 }
180 idis.canonicalized_id = cid; 180 idis.canonicalized_id = cid;
181 idis.normalized_id = rv; idis.xri_identity = true; 181 idis.normalized_id = rv; idis.xri_identity = true;
182 queue_endpoints(oi,idis,st); 182 queue_endpoints(oi,idis,st);
183 } 183 }
184 }else{ 184 }else{
185 idis.xri_identity = false; 185 idis.xri_identity = false;
186 if(id.find("://")==string::npos) 186 if(id.find("://")==string::npos)
187 id.insert(0,"http://"); 187 id.insert(0,"http://");
188 string::size_type fp = id.find('#'); 188 string::size_type fp = id.find('#');
189 if(fp!=string::npos) { 189 if(fp!=string::npos) {
190 string::size_type qp = id.find('?'); 190 string::size_type qp = id.find('?');
191 if(qp==string::npos || qp<fp) 191 if(qp==string::npos || qp<fp)
192 id.erase(fp); 192 id.erase(fp);
193 else if(qp>fp) 193 else if(qp>fp)
194 id.erase(fp,qp-fp); 194 id.erase(fp,qp-fp);
195 } 195 }
196 rv = idis.normalized_id = util::rfc_3986_normalize_uri(id); 196 rv = idis.normalized_id = util::rfc_3986_normalize_uri(id);
197 discover_at(idis,id,xmode_html|xmode_xrd); 197 discover_at(idis,id,xmode_html|xmode_xrd);
198 const char * eu = 0; 198 const char * eu = 0;
199 CURLcode r = easy_getinfo(CURLINFO_EFFECTIVE_URL,&eu); 199 CURLcode r = easy_getinfo(CURLINFO_EFFECTIVE_URL,&eu);
200 if(r) 200 if(r)
201 throw exception_curl(OPKELE_CP_ "failed to get CURLINFO_EFFECTIVE_URL",r); 201 throw exception_curl(OPKELE_CP_ "failed to get CURLINFO_EFFECTIVE_URL",r);
202 string cid = util::strip_uri_fragment_part( idis.canonicalized_id = util::rfc_3986_normalize_uri(eu) ); 202 string cid = util::strip_uri_fragment_part( idis.canonicalized_id = util::rfc_3986_normalize_uri(eu) );
203 if(xrds_location.empty()) { 203 if(xrds_location.empty()) {
204 html2xrd(oi,idis); 204 html2xrd(oi,idis);
205 }else{ 205 }else{
206 idis.clear(); 206 idis.clear();
207 idis.canonicalized_id = cid; 207 idis.canonicalized_id = cid;
208 discover_at(idis,xrds_location,xmode_xrd); 208 discover_at(idis,xrds_location,xmode_xrd);
209 if(idis.xrd.empty()) 209 if(idis.xrd.empty())
210 html2xrd(oi,idis); 210 html2xrd(oi,idis);
211 else{ 211 else{
212 for(const service_type_t *st=op_service_types; 212 for(const service_type_t *st=op_service_types;
213 st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st) 213 st<&op_service_types[sizeof(op_service_types)/sizeof(*op_service_types)];++st)
214 queue_endpoints(oi,idis,st); 214 queue_endpoints(oi,idis,st);
215 } 215 }
216 } 216 }
217 } 217 }
218 return rv; 218 return rv;
219 } 219 }
220 220
221 void discover_at(idiscovery_t& idis,const string& url,int xm) { 221 void discover_at(idiscovery_t& idis,const string& url,int xm) {
222 CURLcode r = easy_setopt(CURLOPT_MAXREDIRS, (xm&xmode_noredirs)?0:5); 222 CURLcode r = easy_setopt(CURLOPT_MAXREDIRS, (xm&xmode_noredirs)?0:5);
223 if(r) 223 if(r)
224 throw exception_curl(OPKELE_CP_ "failed to set curly maxredirs option"); 224 throw exception_curl(OPKELE_CP_ "failed to set curly maxredirs option");
225 if( (r=easy_setopt(CURLOPT_URL,url.c_str())) ) 225 if( (r=easy_setopt(CURLOPT_URL,url.c_str())) )
226 throw exception_curl(OPKELE_CP_ "failed to set curly urlie",r); 226 throw exception_curl(OPKELE_CP_ "failed to set curly urlie",r);
227 227
228 http_content_type.clear(); 228 http_content_type.clear();
229 xmode = xm; 229 xmode = xm;
230 prepare_to_parse(); 230 prepare_to_parse();
231 if(xmode&xmode_html) { 231 if(xmode&xmode_html) {
232 xrds_location.clear(); 232 xrds_location.clear();
233 save_html.clear(); 233 save_html.clear();
234 save_html.reserve(max_html); 234 save_html.reserve(max_html);
235 } 235 }
236 xrd = &idis.xrd; 236 xrd = &idis.xrd;
237 237
238 r = easy_perform(); 238 r = easy_perform();
239 if(r && r!=CURLE_WRITE_ERROR) 239 if(r && r!=CURLE_WRITE_ERROR)
240 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r); 240 throw exception_curl(OPKELE_CP_ "failed to perform curly request",r);
241 241
242 if(!parser_choked) { 242 if(!parser_choked) {
243 parse(0,0,true); 243 parse(0,0,true);
244 }else{ 244 }else{
245 /* TODO: do not bother if we've seen xml */ 245 /* TODO: do not bother if we've seen xml */
246 try { 246 try {
247 util::tidy_doc_t td = util::tidy_doc_t::create(); 247 util::tidy_doc_t td = util::tidy_doc_t::create();
248 if(!td) 248 if(!td)
249 throw exception_tidy(OPKELE_CP_ "failed to create htmltidy document"); 249 throw exception_tidy(OPKELE_CP_ "failed to create htmltidy document");
250#ifndef NDEBUG 250#ifndef NDEBUG
251 td.opt_set(TidyQuiet,false); 251 td.opt_set(TidyQuiet,false);
252 td.opt_set(TidyShowWarnings,false); 252 td.opt_set(TidyShowWarnings,false);
253#endif /* NDEBUG */ 253#endif /* NDEBUG */
254 td.opt_set(TidyForceOutput,true); 254 td.opt_set(TidyForceOutput,true);
255 td.opt_set(TidyXhtmlOut,true); 255 td.opt_set(TidyXhtmlOut,true);
256 td.opt_set(TidyDoctypeMode,TidyDoctypeOmit); 256 td.opt_set(TidyDoctypeMode,TidyDoctypeOmit);
257 td.opt_set(TidyMark,false); 257 td.opt_set(TidyMark,false);
258 if(td.parse_string(save_html)<=0) 258 if(td.parse_string(save_html)<=0)
259 throw exception_tidy(OPKELE_CP_ "tidy failed to parse document"); 259 throw exception_tidy(OPKELE_CP_ "tidy failed to parse document");
260 if(td.clean_and_repair()<=0) 260 if(td.clean_and_repair()<=0)
261 throw exception_tidy(OPKELE_CP_ "tidy failed to clean and repair"); 261 throw exception_tidy(OPKELE_CP_ "tidy failed to clean and repair");
262 util::tidy_buf_t tide; 262 util::tidy_buf_t tide;
263 if(td.save_buffer(tide)<=0) 263 if(td.save_buffer(tide)<=0)
264 throw exception_tidy(OPKELE_CP_ "tidy failed to save buffer"); 264 throw exception_tidy(OPKELE_CP_ "tidy failed to save buffer");
265 prepare_to_parse(); 265 prepare_to_parse();
266 parse(tide.c_str(),tide.size(),true); 266 parse(tide.c_str(),tide.size(),true);
267 }catch(exception_tidy& et) { } 267 }catch(exception_tidy& et) { }
268 } 268 }
269 save_html.clear(); 269 save_html.clear();
270 } 270 }
271 271
272 void prepare_to_parse() { 272 void prepare_to_parse() {
273 (*(expat_t*)this) = parser_create_ns(); 273 (*(expat_t*)this) = parser_create_ns();
274 set_user_data(); set_element_handler(); 274 set_user_data(); set_element_handler();
275 set_character_data_handler(); 275 set_character_data_handler();
276 276
277 if(xmode&xmode_html) { 277 if(xmode&xmode_html) {
278 html_openid1.clear(); html_openid2.clear(); 278 html_openid1.clear(); html_openid2.clear();
279 parser_choked = false; 279 parser_choked = false;
280 } 280 }
281 281
282 cdata = 0; xrd_service = 0; skipping = 0; 282 cdata = 0; xrd_service = 0; skipping = 0;
283 pt_stack.clear(); 283 pt_stack.clear();
284 status_code = 100; status_string.clear(); 284 status_code = 100; status_string.clear();
285 } 285 }
286 286
287 void html2xrd(endpoint_discovery_iterator& oi,idiscovery_t& id) { 287 void html2xrd(endpoint_discovery_iterator& oi,idiscovery_t& id) {
288 XRD_t& x = id.xrd; 288 XRD_t& x = id.xrd;
289 if(!html_openid2.uris.empty()) { 289 if(!html_openid2.uris.empty()) {
290 html_openid2.types.insert(STURI_OPENID20); 290 html_openid2.types.insert(STURI_OPENID20);
291 x.services.add(-1,html_openid2); 291 x.services.add(-1,html_openid2);
292 queue_endpoints(oi,id,&op_service_types[st_index_2]); 292 queue_endpoints(oi,id,&op_service_types[st_index_2]);
293 } 293 }
294 if(!html_openid1.uris.empty()) { 294 if(!html_openid1.uris.empty()) {
295 html_openid1.types.insert(STURI_OPENID11); 295 html_openid1.types.insert(STURI_OPENID11);
296 x.services.add(-1,html_openid1); 296 x.services.add(-1,html_openid1);
297 queue_endpoints(oi,id,&op_service_types[st_index_1]); 297 queue_endpoints(oi,id,&op_service_types[st_index_1]);
298 } 298 }
299 } 299 }
300 300
301 size_t write(void *p,size_t s,size_t nm) { 301 size_t write(void *p,size_t s,size_t nm) {
302 /* TODO: limit total size */ 302 /* TODO: limit total size */
303 size_t bytes = s*nm; 303 size_t bytes = s*nm;
304 const char *inbuf = (const char*)p; 304 const char *inbuf = (const char*)p;
305 if(xmode&xmode_html) { 305 if(xmode&xmode_html) {
306 size_t mbts = save_html.capacity()-save_html.size(); 306 size_t mbts = save_html.capacity()-save_html.size();
307 size_t bts = 0; 307 size_t bts = 0;
308 if(mbts>0) { 308 if(mbts>0) {
309 bts = (bytes>mbts)?mbts:bytes; 309 bts = (bytes>mbts)?mbts:bytes;
310 save_html.append(inbuf,bts); 310 save_html.append(inbuf,bts);
311 } 311 }
312 if(skipping<0) return bts; 312 if(skipping<0) return bts;
313 } 313 }
314 if(skipping<0) return 0; 314 if(skipping<0) return 0;
315 bool rp = parse(inbuf,bytes,false); 315 bool rp = parse(inbuf,bytes,false);
316 if(!rp) { 316 if(!rp) {
317 parser_choked = true; 317 parser_choked = true;
318 skipping = -1; 318 skipping = -1;
319 if(!(xmode&xmode_html)) 319 if(!(xmode&xmode_html))
320 bytes = 0; 320 bytes = 0;
321 } 321 }
322 return bytes; 322 return bytes;
323 } 323 }
324 size_t header(void *p,size_t s,size_t nm) { 324 size_t header(void *p,size_t s,size_t nm) {
325 size_t bytes = s*nm; 325 size_t bytes = s*nm;
326 const char *h = (const char*)p; 326 const char *h = (const char*)p;
327 const char *colon = (const char*)memchr(p,':',bytes); 327 const char *colon = (const char*)memchr(p,':',bytes);
328 const char *space = (const char*)memchr(p,' ',bytes); 328 const char *space = (const char*)memchr(p,' ',bytes);
329 if(space && ( (!colon) || space<colon ) ) { 329 if(space && ( (!colon) || space<colon ) ) {
330 xrds_location.clear(); http_content_type.clear(); 330 xrds_location.clear(); http_content_type.clear();
331 }else if(colon) { 331 }else if(colon) {
332 const char *hv = ++colon; 332 const char *hv = ++colon;
333 int hnl = colon-h; 333 size_t hnl = colon-h;
334 int rb; 334 int rb;
335 for(rb = bytes-hnl-1;rb>0 && isspace(*hv);++hv,--rb); 335 for(rb = bytes-hnl-1;rb>0 && isspace(*hv);++hv,--rb);
336 while(rb>0 && isspace(hv[rb-1])) --rb; 336 while(rb>0 && isspace(hv[rb-1])) --rb;
337 if(rb) { 337 if(rb) {
338 if( (hnl>=sizeof(XRDS_HEADER)) 338 if( (hnl>=sizeof(XRDS_HEADER))
339 && !strncasecmp(h,XRDS_HEADER":", 339 && !strncasecmp(h,XRDS_HEADER":",
340 sizeof(XRDS_HEADER)) ) { 340 sizeof(XRDS_HEADER)) ) {
341 xrds_location.assign(hv,rb); 341 xrds_location.assign(hv,rb);
342 }else if( (hnl>=sizeof(CT_HEADER)) 342 }else if( (hnl>=sizeof(CT_HEADER))
343 && !strncasecmp(h,CT_HEADER":", 343 && !strncasecmp(h,CT_HEADER":",
344 sizeof(CT_HEADER)) ) { 344 sizeof(CT_HEADER)) ) {
345 const char *sc = (const char*)memchr( 345 const char *sc = (const char*)memchr(
346 hv,';',rb); 346 hv,';',rb);
347 http_content_type.assign(hv,sc?(sc-hv):rb); 347 http_content_type.assign(hv,sc?(sc-hv):rb);
348 } 348 }
349 } 349 }
350 } 350 }
351 return curl_t::header(p,s,nm); 351 return curl_t::header(p,s,nm);
352 } 352 }
353 353
354 void start_element(const XML_Char *n,const XML_Char **a) { 354 void start_element(const XML_Char *n,const XML_Char **a) {
355 if(skipping<0) return; 355 if(skipping<0) return;
356 if(skipping) { 356 if(skipping) {
357 if(xmode&xmode_html) 357 if(xmode&xmode_html)
358 html_start_element(n,a); 358 html_start_element(n,a);
359 ++skipping; return; 359 ++skipping; return;
360 } 360 }
361 if(pt_stack.empty()) { 361 if(pt_stack.empty()) {
362 if(is_qelement(n,NSURI_XRDS "\tXRDS")) 362 if(is_qelement(n,NSURI_XRDS "\tXRDS"))
363 return; 363 return;
364 if(is_qelement(n,NSURI_XRD "\tXRD")) { 364 if(is_qelement(n,NSURI_XRD "\tXRD")) {
365 assert(xrd); 365 assert(xrd);
366 xrd->clear(); 366 xrd->clear();
367 pt_stack.push_back(n); 367 pt_stack.push_back(n);
368 }else if(xmode&xmode_html) { 368 }else if(xmode&xmode_html) {
369 html_start_element(n,a); 369 html_start_element(n,a);
370 }else{ 370 }else{
371 skipping = -1; 371 skipping = -1;
372 } 372 }
373 }else{ 373 }else{
374 int pt_s = pt_stack.size(); 374 int pt_s = pt_stack.size();
375 if(pt_s==1) { 375 if(pt_s==1) {
376 if(is_qelement(n,NSURI_XRD "\tCanonicalID")) { 376 if(is_qelement(n,NSURI_XRD "\tCanonicalID")) {
377 assert(xrd); 377 assert(xrd);
378 cdata = &(xrd->canonical_ids.add(element_priority(a),string())); 378 cdata = &(xrd->canonical_ids.add(element_priority(a),string()));
379 }else if(is_qelement(n,NSURI_XRD "\tLocalID")) { 379 }else if(is_qelement(n,NSURI_XRD "\tLocalID")) {
380 assert(xrd); 380 assert(xrd);
381 cdata = &(xrd->local_ids.add(element_priority(a),string())); 381 cdata = &(xrd->local_ids.add(element_priority(a),string()));
382 }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { 382 }else if(is_qelement(n,NSURI_XRD "\tProviderID")) {
383 assert(xrd); 383 assert(xrd);
384 cdata = &(xrd->provider_id); 384 cdata = &(xrd->provider_id);
385 }else if(is_qelement(n,NSURI_XRD "\tService")) { 385 }else if(is_qelement(n,NSURI_XRD "\tService")) {
386 assert(xrd); 386 assert(xrd);
387 xrd_service = &(xrd->services.add(element_priority(a), 387 xrd_service = &(xrd->services.add(element_priority(a),
388 service_t())); 388 service_t()));
389 pt_stack.push_back(n); 389 pt_stack.push_back(n);
390 }else if(is_qelement(n,NSURI_XRD "\tStatus")) { 390 }else if(is_qelement(n,NSURI_XRD "\tStatus")) {
391 for(;*a;) { 391 for(;*a;) {
392 if(!strcasecmp(*(a++),"code")) { 392 if(!strcasecmp(*(a++),"code")) {
393 if(sscanf(*(a++),"%ld",&status_code)==1 && status_code!=100) { 393 if(sscanf(*(a++),"%ld",&status_code)==1 && status_code!=100) {
394 cdata = &status_string; 394 cdata = &status_string;
395 pt_stack.push_back(n); 395 pt_stack.push_back(n);
396 break; 396 break;
397 } 397 }
398 }else 398 }else
399 ++a; 399 ++a;
400 } 400 }
401 }else if(is_qelement(n,NSURI_XRD "\tExpires")) { 401 }else if(is_qelement(n,NSURI_XRD "\tExpires")) {
402 assert(xrd); 402 assert(xrd);
403 cdata_buf.clear(); 403 cdata_buf.clear();
404 cdata = &cdata_buf; 404 cdata = &cdata_buf;
405 }else if(xmode&xmode_html) { 405 }else if(xmode&xmode_html) {
406 html_start_element(n,a); 406 html_start_element(n,a);
407 }else{ 407 }else{
408 skipping = 1; 408 skipping = 1;
409 } 409 }
410 }else if(pt_s==2) { 410 }else if(pt_s==2) {
411 if(is_qelement(pt_stack.back().c_str(), NSURI_XRD "\tService")) { 411 if(is_qelement(pt_stack.back().c_str(), NSURI_XRD "\tService")) {
412 if(is_qelement(n,NSURI_XRD "\tType")) { 412 if(is_qelement(n,NSURI_XRD "\tType")) {
413 assert(xrd); assert(xrd_service); 413 assert(xrd); assert(xrd_service);
414 cdata_buf.clear(); 414 cdata_buf.clear();
415 cdata = &cdata_buf; 415 cdata = &cdata_buf;
416 }else if(is_qelement(n,NSURI_XRD "\tURI")) { 416 }else if(is_qelement(n,NSURI_XRD "\tURI")) {
417 assert(xrd); assert(xrd_service); 417 assert(xrd); assert(xrd_service);
418 const char *append = element_attr(a,"append"); 418 const char *append = element_attr(a,"append");
419 xrd::uri_t& uri = xrd_service->uris.add(element_priority(a),xrd::uri_t("",append?append:"")); 419 xrd::uri_t& uri = xrd_service->uris.add(element_priority(a),xrd::uri_t("",append?append:""));
420 cdata = &uri.uri; 420 cdata = &uri.uri;
421 }else if(is_qelement(n,NSURI_XRD "\tLocalID") 421 }else if(is_qelement(n,NSURI_XRD "\tLocalID")
422 || is_qelement(n,NSURI_OPENID10 "\tDelegate") ) { 422 || is_qelement(n,NSURI_OPENID10 "\tDelegate") ) {
423 assert(xrd); assert(xrd_service); 423 assert(xrd); assert(xrd_service);
424 cdata = &(xrd_service->local_ids.add(element_priority(a),string())); 424 cdata = &(xrd_service->local_ids.add(element_priority(a),string()));
425 }else if(is_qelement(n,NSURI_XRD "\tProviderID")) { 425 }else if(is_qelement(n,NSURI_XRD "\tProviderID")) {
426 assert(xrd); assert(xrd_service); 426 assert(xrd); assert(xrd_service);
427 cdata = &(xrd_service->provider_id); 427 cdata = &(xrd_service->provider_id);
428 }else{ 428 }else{
429 skipping = 1; 429 skipping = 1;
430 } 430 }
431 }else 431 }else
432 skipping = 1; 432 skipping = 1;
433 }else if(xmode&xmode_html) { 433 }else if(xmode&xmode_html) {
434 html_start_element(n,a); 434 html_start_element(n,a);
435 }else{ 435 }else{
436 skipping = 1; 436 skipping = 1;
437 } 437 }
438 } 438 }
439 } 439 }
440 void end_element(const XML_Char *n) { 440 void end_element(const XML_Char *n) {
441 if(skipping<0) return; 441 if(skipping<0) return;
442 if(skipping) { 442 if(skipping) {
443 --skipping; return; 443 --skipping; return;
444 } 444 }
445 if(is_qelement(n,NSURI_XRD "\tType")) { 445 if(is_qelement(n,NSURI_XRD "\tType")) {
446 assert(xrd); assert(xrd_service); assert(cdata==&cdata_buf); 446 assert(xrd); assert(xrd_service); assert(cdata==&cdata_buf);
447 xrd_service->types.insert(cdata_buf); 447 xrd_service->types.insert(cdata_buf);
448 }else if(is_qelement(n,NSURI_XRD "\tService")) { 448 }else if(is_qelement(n,NSURI_XRD "\tService")) {
449 assert(xrd); assert(xrd_service); 449 assert(xrd); assert(xrd_service);
450 assert(!pt_stack.empty()); 450 assert(!pt_stack.empty());
451 assert(pt_stack.back()==(NSURI_XRD "\tService")); 451 assert(pt_stack.back()==(NSURI_XRD "\tService"));
452 pt_stack.pop_back(); 452 pt_stack.pop_back();
453 xrd_service = 0; 453 xrd_service = 0;
454 }else if(is_qelement(n,NSURI_XRD "\tStatus")) { 454 }else if(is_qelement(n,NSURI_XRD "\tStatus")) {
455 assert(xrd); 455 assert(xrd);
456 if(is_qelement(pt_stack.back().c_str(),n)) { 456 if(is_qelement(pt_stack.back().c_str(),n)) {
457 assert(cdata==&status_string); 457 assert(cdata==&status_string);
458 pt_stack.pop_back(); 458 pt_stack.pop_back();
459 if(status_code!=100) 459 if(status_code!=100)
460 skipping = -1; 460 skipping = -1;
461 } 461 }
462 }else if(is_qelement(n,NSURI_XRD "\tExpires")) { 462 }else if(is_qelement(n,NSURI_XRD "\tExpires")) {
463 assert(xrd); 463 assert(xrd);
464 xrd->expires = util::w3c_to_time(cdata_buf); 464 xrd->expires = util::w3c_to_time(cdata_buf);
465 }else if((xmode&xmode_html) && is_element(n,"head")) { 465 }else if((xmode&xmode_html) && is_element(n,"head")) {
466 skipping = -1; 466 skipping = -1;
467 } 467 }
468 cdata = 0; 468 cdata = 0;
469 } 469 }
470 void character_data(const XML_Char *s,int l) { 470 void character_data(const XML_Char *s,int l) {
471 if(skipping) return; 471 if(skipping) return;
472 if(cdata) cdata->append(s,l); 472 if(cdata) cdata->append(s,l);
473 } 473 }
474 474
475 void html_start_element(const XML_Char *n,const XML_Char **a) { 475 void html_start_element(const XML_Char *n,const XML_Char **a) {
476 if(is_element(n,"meta")) { 476 if(is_element(n,"meta")) {
477 bool heq = false; 477 bool heq = false;
478 string l; 478 string l;
479 for(;*a;a+=2) { 479 for(;*a;a+=2) {
480 if(!( strcasecmp(a[0],"http-equiv") 480 if(!( strcasecmp(a[0],"http-equiv")
481 || strcasecmp(a[1],XRDS_HEADER) )) 481 || strcasecmp(a[1],XRDS_HEADER) ))
482 heq = true; 482 heq = true;
483 else if(!strcasecmp(a[0],"content")) 483 else if(!strcasecmp(a[0],"content"))
484 l.assign(a[1]); 484 l.assign(a[1]);
485 } 485 }
486 if(heq) 486 if(heq)
487 xrds_location = l; 487 xrds_location = l;
488 }else if(is_element(n,"link")) { 488 }else if(is_element(n,"link")) {
489 string rels; 489 string rels;
490 string href; 490 string href;
491 for(;*a;a+=2) { 491 for(;*a;a+=2) {
492 if( !strcasecmp(a[0],"rel") ) { 492 if( !strcasecmp(a[0],"rel") ) {
493 rels.assign(a[1]); 493 rels.assign(a[1]);
494 }else if( !strcasecmp(a[0],"href") ) { 494 }else if( !strcasecmp(a[0],"href") ) {
495 const char *ns = a[1]; 495 const char *ns = a[1];
496 for(;*ns && isspace(*ns);++ns); 496 for(;*ns && isspace(*ns);++ns);
497 href.assign(ns); 497 href.assign(ns);
498 string::size_type lns=href.find_last_not_of(whitespace); 498 string::size_type lns=href.find_last_not_of(whitespace);
499 href.erase(lns+1); 499 href.erase(lns+1);
500 } 500 }
501 } 501 }
502 for(string::size_type ns=rels.find_first_not_of(whitespace); 502 for(string::size_type ns=rels.find_first_not_of(whitespace);
503 ns!=string::npos; ns=rels.find_first_not_of(whitespace,ns)) { 503 ns!=string::npos; ns=rels.find_first_not_of(whitespace,ns)) {
504 string::size_type s = rels.find_first_of(whitespace,ns); 504 string::size_type s = rels.find_first_of(whitespace,ns);
505 string rel; 505 string rel;
506 if(s==string::npos) { 506 if(s==string::npos) {
507 rel.assign(rels,ns,string::npos); 507 rel.assign(rels,ns,string::npos);
508 ns = string::npos; 508 ns = string::npos;
509 }else{ 509 }else{
510 rel.assign(rels,ns,s-ns); 510 rel.assign(rels,ns,s-ns);
511 ns = s; 511 ns = s;
512 } 512 }
513 if(rel=="openid.server") 513 if(rel=="openid.server")
514 html_openid1.uris.add(-1,xrd::uri_t(href)); 514 html_openid1.uris.add(-1,xrd::uri_t(href));
515 else if(rel=="openid.delegate") 515 else if(rel=="openid.delegate")
516 html_openid1.local_ids.add(-1,href); 516 html_openid1.local_ids.add(-1,href);
517 else if(rel=="openid2.provider") 517 else if(rel=="openid2.provider")
518 html_openid2.uris.add(-1,xrd::uri_t(href)); 518 html_openid2.uris.add(-1,xrd::uri_t(href));
519 else if(rel=="openid2.local_id") 519 else if(rel=="openid2.local_id")
520 html_openid2.local_ids.add(-1,href); 520 html_openid2.local_ids.add(-1,href);
521 } 521 }
522 }else if(is_element(n,"body")) { 522 }else if(is_element(n,"body")) {
523 skipping = -1; 523 skipping = -1;
524 } 524 }
525 } 525 }
diff --git a/lib/expat.cc b/lib/expat.cc
index fa6fdde..c4dab7e 100644
--- a/lib/expat.cc
+++ b/lib/expat.cc
@@ -1,96 +1,97 @@
1#include <opkele/expat.h> 1#include <opkele/expat.h>
2 2
3namespace opkele { 3namespace opkele {
4 4
5 namespace util { 5 namespace util {
6 6
7 expat_t::~expat_t() throw() { 7 expat_t::~expat_t() throw() {
8 if(_x) 8 if(_x)
9 XML_ParserFree(_x); 9 XML_ParserFree(_x);
10 } 10 }
11 11
12 expat_t& expat_t::operator=(XML_Parser x) { 12 expat_t& expat_t::operator=(XML_Parser x) {
13 if(_x) 13 if(_x)
14 XML_ParserFree(_x); 14 XML_ParserFree(_x);
15 _x = x; 15 _x = x;
16 return *this;
16 } 17 }
17 18
18 static void _start_element(void* ud,const XML_Char *n,const XML_Char **a) { 19 static void _start_element(void* ud,const XML_Char *n,const XML_Char **a) {
19 ((expat_t*)ud)->start_element(n,a); 20 ((expat_t*)ud)->start_element(n,a);
20 } 21 }
21 static void _end_element(void *ud,const XML_Char *n) { 22 static void _end_element(void *ud,const XML_Char *n) {
22 ((expat_t*)ud)->end_element(n); 23 ((expat_t*)ud)->end_element(n);
23 } 24 }
24 25
25 void expat_t::set_element_handler() { 26 void expat_t::set_element_handler() {
26 assert(_x); 27 assert(_x);
27 XML_SetElementHandler(_x,_start_element,_end_element); 28 XML_SetElementHandler(_x,_start_element,_end_element);
28 } 29 }
29 30
30 static void _character_data(void *ud,const XML_Char *s,int l) { 31 static void _character_data(void *ud,const XML_Char *s,int l) {
31 ((expat_t*)ud)->character_data(s,l); 32 ((expat_t*)ud)->character_data(s,l);
32 } 33 }
33 34
34 void expat_t::set_character_data_handler() { 35 void expat_t::set_character_data_handler() {
35 assert(_x); 36 assert(_x);
36 XML_SetCharacterDataHandler(_x,_character_data); 37 XML_SetCharacterDataHandler(_x,_character_data);
37 } 38 }
38 39
39 static void _processing_instruction(void *ud,const XML_Char *t,const XML_Char *d) { 40 static void _processing_instruction(void *ud,const XML_Char *t,const XML_Char *d) {
40 ((expat_t*)ud)->processing_instruction(t,d); 41 ((expat_t*)ud)->processing_instruction(t,d);
41 } 42 }
42 43
43 void expat_t::set_processing_instruction_handler() { 44 void expat_t::set_processing_instruction_handler() {
44 assert(_x); 45 assert(_x);
45 XML_SetProcessingInstructionHandler(_x,_processing_instruction); 46 XML_SetProcessingInstructionHandler(_x,_processing_instruction);
46 } 47 }
47 48
48 static void _comment(void *ud,const XML_Char *d) { 49 static void _comment(void *ud,const XML_Char *d) {
49 ((expat_t*)ud)->comment(d); 50 ((expat_t*)ud)->comment(d);
50 } 51 }
51 52
52 void expat_t::set_comment_handler() { 53 void expat_t::set_comment_handler() {
53 assert(_x); 54 assert(_x);
54 XML_SetCommentHandler(_x,_comment); 55 XML_SetCommentHandler(_x,_comment);
55 } 56 }
56 57
57 static void _start_cdata_section(void *ud) { 58 static void _start_cdata_section(void *ud) {
58 ((expat_t*)ud)->start_cdata_section(); 59 ((expat_t*)ud)->start_cdata_section();
59 } 60 }
60 static void _end_cdata_section(void *ud) { 61 static void _end_cdata_section(void *ud) {
61 ((expat_t*)ud)->end_cdata_section(); 62 ((expat_t*)ud)->end_cdata_section();
62 } 63 }
63 64
64 void expat_t::set_cdata_section_handler() { 65 void expat_t::set_cdata_section_handler() {
65 assert(_x); 66 assert(_x);
66 XML_SetCdataSectionHandler(_x,_start_cdata_section,_end_cdata_section); 67 XML_SetCdataSectionHandler(_x,_start_cdata_section,_end_cdata_section);
67 } 68 }
68 69
69 static void _default_handler(void *ud,const XML_Char *s,int l) { 70 static void _default_handler(void *ud,const XML_Char *s,int l) {
70 ((expat_t*)ud)->default_handler(s,l); 71 ((expat_t*)ud)->default_handler(s,l);
71 } 72 }
72 73
73 void expat_t::set_default_handler() { 74 void expat_t::set_default_handler() {
74 assert(_x); 75 assert(_x);
75 XML_SetDefaultHandler(_x,_default_handler); 76 XML_SetDefaultHandler(_x,_default_handler);
76 } 77 }
77 void expat_t::set_default_handler_expand() { 78 void expat_t::set_default_handler_expand() {
78 assert(_x); 79 assert(_x);
79 XML_SetDefaultHandlerExpand(_x,_default_handler); 80 XML_SetDefaultHandlerExpand(_x,_default_handler);
80 } 81 }
81 82
82 static void _start_namespace_decl(void *ud,const XML_Char *p,const XML_Char *u) { 83 static void _start_namespace_decl(void *ud,const XML_Char *p,const XML_Char *u) {
83 ((expat_t*)ud)->start_namespace_decl(p,u); 84 ((expat_t*)ud)->start_namespace_decl(p,u);
84 } 85 }
85 static void _end_namespace_decl(void *ud,const XML_Char *p) { 86 static void _end_namespace_decl(void *ud,const XML_Char *p) {
86 ((expat_t*)ud)->end_namespace_decl(p); 87 ((expat_t*)ud)->end_namespace_decl(p);
87 } 88 }
88 89
89 void expat_t::set_namespace_decl_handler() { 90 void expat_t::set_namespace_decl_handler() {
90 assert(_x); 91 assert(_x);
91 XML_SetNamespaceDeclHandler(_x,_start_namespace_decl,_end_namespace_decl); 92 XML_SetNamespaceDeclHandler(_x,_start_namespace_decl,_end_namespace_decl);
92 } 93 }
93 94
94 } 95 }
95 96
96} 97}
diff --git a/lib/extension.cc b/lib/extension.cc
index f7aaea5..0f121ca 100644
--- a/lib/extension.cc
+++ b/lib/extension.cc
@@ -1,26 +1,26 @@
1#include <opkele/exception.h> 1#include <opkele/exception.h>
2#include <opkele/extension.h> 2#include <opkele/extension.h>
3 3
4namespace opkele { 4namespace opkele {
5 5
6 void extension_t::rp_checkid_hook(basic_openid_message&) { 6 void extension_t::rp_checkid_hook(basic_openid_message&) {
7 throw not_implemented(OPKELE_CP_ "RP checkid_* hook not implemented"); } 7 throw not_implemented(OPKELE_CP_ "RP checkid_* hook not implemented"); }
8 void extension_t::rp_id_res_hook(const basic_openid_message&, 8 void extension_t::rp_id_res_hook(const basic_openid_message&,
9 const basic_openid_message&) { 9 const basic_openid_message&) {
10 throw not_implemented(OPKELE_CP_ "RP id_res hook not implemented"); } 10 throw not_implemented(OPKELE_CP_ "RP id_res hook not implemented"); }
11 11
12 void extension_t::op_checkid_hook(const basic_openid_message&) { 12 void extension_t::op_checkid_hook(const basic_openid_message&) {
13 throw not_implemented(OPKELE_CP_ "OP checkid_* hook not implemented"); } 13 throw not_implemented(OPKELE_CP_ "OP checkid_* hook not implemented"); }
14 void extension_t::op_id_res_hook(basic_openid_message& om) { 14 void extension_t::op_id_res_hook(basic_openid_message&) {
15 throw not_implemented(OPKELE_CP_ "OP id_res hook not implemented"); } 15 throw not_implemented(OPKELE_CP_ "OP id_res hook not implemented"); }
16 16
17 17
18 void extension_t::checkid_hook(basic_openid_message&) { 18 void extension_t::checkid_hook(basic_openid_message&) {
19 throw not_implemented(OPKELE_CP_ "deprecated consumer checkid_* hook not implemented"); } 19 throw not_implemented(OPKELE_CP_ "deprecated consumer checkid_* hook not implemented"); }
20 void extension_t::id_res_hook(const basic_openid_message&, 20 void extension_t::id_res_hook(const basic_openid_message&,
21 const basic_openid_message&) { 21 const basic_openid_message&) {
22 throw not_implemented(OPKELE_CP_ "deprecated consumer id_res hook not implemented"); } 22 throw not_implemented(OPKELE_CP_ "deprecated consumer id_res hook not implemented"); }
23 23
24 void extension_t::checkid_hook(const basic_openid_message&,basic_openid_message&) { 24 void extension_t::checkid_hook(const basic_openid_message&,basic_openid_message&) {
25 throw not_implemented(OPKELE_CP_ "deprecated server checkid hook not implemented"); } 25 throw not_implemented(OPKELE_CP_ "deprecated server checkid hook not implemented"); }
26} 26}
diff --git a/lib/openid_message.cc b/lib/openid_message.cc
index fdb4b04..521ea85 100644
--- a/lib/openid_message.cc
+++ b/lib/openid_message.cc
@@ -1,265 +1,265 @@
1#include <cassert> 1#include <cassert>
2#include <opkele/types.h> 2#include <opkele/types.h>
3#include <opkele/exception.h> 3#include <opkele/exception.h>
4#include <opkele/util.h> 4#include <opkele/util.h>
5#include <opkele/debug.h> 5#include <opkele/debug.h>
6 6
7#include "config.h" 7#include "config.h"
8 8
9namespace opkele { 9namespace opkele {
10 using std::input_iterator_tag; 10 using std::input_iterator_tag;
11 using std::unary_function; 11 using std::unary_function;
12 12
13 struct __om_copier : public unary_function<const string&,void> { 13 struct __om_copier : public unary_function<const string&,void> {
14 public: 14 public:
15 const basic_openid_message& from; 15 const basic_openid_message& from;
16 basic_openid_message& to; 16 basic_openid_message& to;
17 17
18 __om_copier(basic_openid_message& to,const basic_openid_message& from) 18 __om_copier(basic_openid_message& t,const basic_openid_message& f)
19 : from(from), to(to) { 19 : from(f), to(t) {
20 to.reset_fields(); 20 to.reset_fields();
21 } 21 }
22 22
23 result_type operator()(argument_type f) { 23 result_type operator()(argument_type f) {
24 to.set_field(f,from.get_field(f)); } 24 to.set_field(f,from.get_field(f)); }
25 }; 25 };
26 26
27 basic_openid_message::basic_openid_message(const basic_openid_message& x) { 27 basic_openid_message::basic_openid_message(const basic_openid_message& x) {
28 x.copy_to(*this); 28 x.copy_to(*this);
29 } 29 }
30 void basic_openid_message::copy_to(basic_openid_message& x) const { 30 void basic_openid_message::copy_to(basic_openid_message& x) const {
31 for_each(fields_begin(),fields_end(), 31 for_each(fields_begin(),fields_end(),
32 __om_copier(x,*this) ); 32 __om_copier(x,*this) );
33 } 33 }
34 34
35 struct __om_ns_finder : public unary_function<const string&,bool> { 35 struct __om_ns_finder : public unary_function<const string&,bool> {
36 public: 36 public:
37 const basic_openid_message& om; 37 const basic_openid_message& om;
38 const string& uri; 38 const string& uri;
39 39
40 __om_ns_finder(const basic_openid_message& om, 40 __om_ns_finder(const basic_openid_message& m,
41 const string& uri) : om(om), uri(uri) { } 41 const string& u) : om(m), uri(u) { }
42 42
43 result_type operator()(argument_type f) { 43 result_type operator()(argument_type f) {
44 return 44 return
45 (!strncmp(f.c_str(),"ns.",sizeof("ns.")-1)) 45 (!strncmp(f.c_str(),"ns.",sizeof("ns.")-1))
46 && om.get_field(f)==uri ; 46 && om.get_field(f)==uri ;
47 } 47 }
48 }; 48 };
49 49
50 bool basic_openid_message::has_ns(const string& uri) const { 50 bool basic_openid_message::has_ns(const string& uri) const {
51 fields_iterator ei = fields_end(); 51 fields_iterator ei = fields_end();
52 fields_iterator i = find_if(fields_begin(),fields_end(), 52 fields_iterator i = find_if(fields_begin(),fields_end(),
53 __om_ns_finder(*this,uri)); 53 __om_ns_finder(*this,uri));
54 return !(i==ei); 54 return !(i==ei);
55 } 55 }
56 string basic_openid_message::get_ns(const string& uri) const { 56 string basic_openid_message::get_ns(const string& uri) const {
57 fields_iterator ei = fields_end(); 57 fields_iterator ei = fields_end();
58 fields_iterator i = find_if(fields_begin(),fields_end(), 58 fields_iterator i = find_if(fields_begin(),fields_end(),
59 __om_ns_finder(*this,uri)); 59 __om_ns_finder(*this,uri));
60 if(i==ei) 60 if(i==ei)
61 throw failed_lookup(OPKELE_CP_ string("failed to find namespace ")+uri); 61 throw failed_lookup(OPKELE_CP_ string("failed to find namespace ")+uri);
62 return i->substr(3); 62 return i->substr(3);
63 } 63 }
64 64
65 struct __om_query_builder : public unary_function<const string&,void> { 65 struct __om_query_builder : public unary_function<const string&,void> {
66 public: 66 public:
67 const basic_openid_message& om; 67 const basic_openid_message& om;
68 string& rv;
69 bool first; 68 bool first;
69 string& rv;
70 70
71 __om_query_builder(string& rv,const basic_openid_message& om) 71 __om_query_builder(string& r,const basic_openid_message& m)
72 : om(om), first(true), rv(rv) { 72 : om(m), first(true), rv(r) {
73 for_each(om.fields_begin(),om.fields_end(),*this); 73 for_each(om.fields_begin(),om.fields_end(),*this);
74 } 74 }
75 __om_query_builder(string& rv,const basic_openid_message& om,const string& url) 75 __om_query_builder(string& r,const basic_openid_message& m,const string& u)
76 : om(om), first(true), rv(rv) { 76 : om(m), first(true), rv(r) {
77 rv = url; 77 rv = u;
78 if(rv.find('?')==string::npos) 78 if(rv.find('?')==string::npos)
79 rv += '?'; 79 rv += '?';
80 else 80 else
81 first = false; 81 first = false;
82 for_each(om.fields_begin(),om.fields_end(),*this); 82 for_each(om.fields_begin(),om.fields_end(),*this);
83 } 83 }
84 84
85 result_type operator()(argument_type f) { 85 result_type operator()(argument_type f) {
86 if(first) 86 if(first)
87 first = false; 87 first = false;
88 else 88 else
89 rv += '&'; 89 rv += '&';
90 rv += "openid."; rv+= f; 90 rv += "openid."; rv+= f;
91 rv += '='; 91 rv += '=';
92 rv += util::url_encode(om.get_field(f)); 92 rv += util::url_encode(om.get_field(f));
93 } 93 }
94 }; 94 };
95 95
96 string basic_openid_message::append_query(const string& url) const { 96 string basic_openid_message::append_query(const string& url) const {
97 string rv; 97 string rv;
98 return __om_query_builder(rv,*this,url).rv; 98 return __om_query_builder(rv,*this,url).rv;
99 } 99 }
100 string basic_openid_message::query_string() const { 100 string basic_openid_message::query_string() const {
101 string rv; 101 string rv;
102 return __om_query_builder(rv,*this).rv; 102 return __om_query_builder(rv,*this).rv;
103 } 103 }
104 104
105 void basic_openid_message::reset_fields() { 105 void basic_openid_message::reset_fields() {
106 throw not_implemented(OPKELE_CP_ "reset_fields() not implemented"); 106 throw not_implemented(OPKELE_CP_ "reset_fields() not implemented");
107 } 107 }
108 void basic_openid_message::set_field(const string& n,const string& v) { 108 void basic_openid_message::set_field(const string&,const string&) {
109 throw not_implemented(OPKELE_CP_ "set_field() not implemented"); 109 throw not_implemented(OPKELE_CP_ "set_field() not implemented");
110 } 110 }
111 void basic_openid_message::reset_field(const string& n) { 111 void basic_openid_message::reset_field(const string&) {
112 throw not_implemented(OPKELE_CP_ "reset_field() not implemented"); 112 throw not_implemented(OPKELE_CP_ "reset_field() not implemented");
113 } 113 }
114 114
115 void basic_openid_message::from_keyvalues(const string& kv) { 115 void basic_openid_message::from_keyvalues(const string& kv) {
116 reset_fields(); 116 reset_fields();
117 string::size_type p = 0; 117 string::size_type p = 0;
118 while(true) { 118 while(true) {
119 string::size_type co = kv.find(':',p); 119 string::size_type co = kv.find(':',p);
120 if(co==string::npos) 120 if(co==string::npos)
121 break; 121 break;
122#ifndef POSTELS_LAW 122#ifndef POSTELS_LAW
123 string::size_type nl = kv.find('\n',co+1); 123 string::size_type nl = kv.find('\n',co+1);
124 if(nl==string::npos) 124 if(nl==string::npos)
125 throw bad_input(OPKELE_CP_ "malformed input"); 125 throw bad_input(OPKELE_CP_ "malformed input");
126 if(nl>co) 126 if(nl>co)
127 insert(value_type(kv.substr(p,co-p),kv.substr(co+1,nl-co-1))); 127 insert(value_type(kv.substr(p,co-p),kv.substr(co+1,nl-co-1)));
128 p = nl+1; 128 p = nl+1;
129#else /* POSTELS_LAW */ 129#else /* POSTELS_LAW */
130 string::size_type lb = kv.find_first_of("\r\n",co+1); 130 string::size_type lb = kv.find_first_of("\r\n",co+1);
131 if(lb==string::npos) { 131 if(lb==string::npos) {
132 set_field(kv.substr(p,co-p),kv.substr(co+1)); 132 set_field(kv.substr(p,co-p),kv.substr(co+1));
133 break; 133 break;
134 } 134 }
135 if(lb>co) 135 if(lb>co)
136 set_field(kv.substr(p,co-p),kv.substr(co+1,lb-co-1)); 136 set_field(kv.substr(p,co-p),kv.substr(co+1,lb-co-1));
137 string::size_type nolb = kv.find_first_not_of("\r\n",lb); 137 string::size_type nolb = kv.find_first_not_of("\r\n",lb);
138 if(nolb==string::npos) 138 if(nolb==string::npos)
139 break; 139 break;
140 p = nolb; 140 p = nolb;
141#endif /* POSTELS_LAW */ 141#endif /* POSTELS_LAW */
142 } 142 }
143 } 143 }
144 144
145 struct __om_kv_outputter : public unary_function<const string&,void> { 145 struct __om_kv_outputter : public unary_function<const string&,void> {
146 public: 146 public:
147 const basic_openid_message& om; 147 const basic_openid_message& om;
148 ostream& os; 148 ostream& os;
149 149
150 __om_kv_outputter(const basic_openid_message& om,ostream& os) 150 __om_kv_outputter(const basic_openid_message& m,ostream& s)
151 : om(om), os(os) { } 151 : om(m), os(s) { }
152 152
153 result_type operator()(argument_type f) { 153 result_type operator()(argument_type f) {
154 os << f << ':' << om.get_field(f) << '\n'; 154 os << f << ':' << om.get_field(f) << '\n';
155 } 155 }
156 }; 156 };
157 157
158 void basic_openid_message::to_keyvalues(ostream& o) const { 158 void basic_openid_message::to_keyvalues(ostream& o) const {
159 for_each(fields_begin(),fields_end(),__om_kv_outputter(*this,o)); 159 for_each(fields_begin(),fields_end(),__om_kv_outputter(*this,o));
160 } 160 }
161 161
162 struct __om_html_outputter : public unary_function<const string&,void> { 162 struct __om_html_outputter : public unary_function<const string&,void> {
163 public: 163 public:
164 const basic_openid_message& om; 164 const basic_openid_message& om;
165 ostream& os; 165 ostream& os;
166 166
167 __om_html_outputter(const basic_openid_message& om,ostream& os) 167 __om_html_outputter(const basic_openid_message& m,ostream& s)
168 : om(om), os(os) { } 168 : om(m), os(s) { }
169 169
170 result_type operator()(argument_type f) { 170 result_type operator()(argument_type f) {
171 os << 171 os <<
172 "<input type=\"hidden\"" 172 "<input type=\"hidden\""
173 " name=\"" << util::attr_escape(f) << "\"" 173 " name=\"" << util::attr_escape(f) << "\""
174 " value=\"" << util::attr_escape(om.get_field(f)) << "\" />"; 174 " value=\"" << util::attr_escape(om.get_field(f)) << "\" />";
175 } 175 }
176 }; 176 };
177 177
178 void basic_openid_message::to_htmlhiddens(ostream& o) const { 178 void basic_openid_message::to_htmlhiddens(ostream& o) const {
179 for_each(fields_begin(),fields_end(),__om_html_outputter(*this,o)); 179 for_each(fields_begin(),fields_end(),__om_html_outputter(*this,o));
180 } 180 }
181 181
182 void basic_openid_message::add_to_signed(const string& fields) { 182 void basic_openid_message::add_to_signed(const string& fields) {
183 string::size_type fnc = fields.find_first_not_of(","); 183 string::size_type fnc = fields.find_first_not_of(",");
184 if(fnc==string::npos) 184 if(fnc==string::npos)
185 throw bad_input(OPKELE_CP_ "Trying to add nothing in particular to the list of signed fields"); 185 throw bad_input(OPKELE_CP_ "Trying to add nothing in particular to the list of signed fields");
186 string signeds; 186 string signeds;
187 try { 187 try {
188 signeds = get_field("signed"); 188 signeds = get_field("signed");
189 string::size_type lnc = signeds.find_last_not_of(","); 189 string::size_type lnc = signeds.find_last_not_of(",");
190 if(lnc==string::npos) 190 if(lnc==string::npos)
191 signeds.assign(fields,fnc,fields.size()-fnc); 191 signeds.assign(fields,fnc,fields.size()-fnc);
192 else{ 192 else{
193 string::size_type ss = signeds.size(); 193 string::size_type ss = signeds.size();
194 if(lnc==(ss-1)) { 194 if(lnc==(ss-1)) {
195 signeds+= ','; 195 signeds+= ',';
196 signeds.append(fields,fnc,fields.size()-fnc); 196 signeds.append(fields,fnc,fields.size()-fnc);
197 }else{ 197 }else{
198 if(lnc<(ss-2)) 198 if(lnc<(ss-2))
199 signeds.replace(lnc+2,ss-lnc-2, 199 signeds.replace(lnc+2,ss-lnc-2,
200 fields,fnc,fields.size()-fnc); 200 fields,fnc,fields.size()-fnc);
201 else 201 else
202 signeds.append(fields,fnc,fields.size()-fnc); 202 signeds.append(fields,fnc,fields.size()-fnc);
203 } 203 }
204 } 204 }
205 }catch(failed_lookup&) { 205 }catch(failed_lookup&) {
206 signeds.assign(fields,fnc,fields.size()-fnc); 206 signeds.assign(fields,fnc,fields.size()-fnc);
207 } 207 }
208 set_field("signed",signeds); 208 set_field("signed",signeds);
209 } 209 }
210 210
211 string basic_openid_message::find_ns(const string& uri,const char *pfx) const { 211 string basic_openid_message::find_ns(const string& uri,const char *pfx) const {
212 if(has_field("ns")) 212 if(has_field("ns"))
213 return get_ns(uri); 213 return get_ns(uri);
214 return pfx; 214 return pfx;
215 } 215 }
216 string basic_openid_message::allocate_ns(const string& uri,const char *pfx) { 216 string basic_openid_message::allocate_ns(const string& uri,const char *pfx) {
217 if(!has_field("ns")) 217 if(!has_field("ns"))
218 return pfx; 218 return pfx;
219 if(has_ns(uri)) 219 if(has_ns(uri))
220 throw bad_input(OPKELE_CP_ "OpenID message already contains namespace"); 220 throw bad_input(OPKELE_CP_ "OpenID message already contains namespace");
221 string rv = pfx; 221 string rv = pfx;
222 if(has_field("ns."+rv)) { 222 if(has_field("ns."+rv)) {
223 string::reference c=rv[rv.length()]; 223 string::reference c=rv[rv.length()];
224 for(c='a';c<='z' && has_field("ns."+rv);++c); 224 for(c='a';c<='z' && has_field("ns."+rv);++c);
225 if(c=='z') 225 if(c=='z')
226 throw exception(OPKELE_CP_ "Failed to allocate namespace"); 226 throw exception(OPKELE_CP_ "Failed to allocate namespace");
227 } 227 }
228 set_field("ns."+rv,uri); 228 set_field("ns."+rv,uri);
229 return rv; 229 return rv;
230 } 230 }
231 231
232 void openid_message_t::copy_to(basic_openid_message& x) const { 232 void openid_message_t::copy_to(basic_openid_message& x) const {
233 x.reset_fields(); 233 x.reset_fields();
234 for(const_iterator i=begin();i!=end();++i) 234 for(const_iterator i=begin();i!=end();++i)
235 x.set_field(i->first,i->second); 235 x.set_field(i->first,i->second);
236 } 236 }
237 237
238 bool openid_message_t::has_field(const string& n) const { 238 bool openid_message_t::has_field(const string& n) const {
239 return find(n)!=end(); 239 return find(n)!=end();
240 } 240 }
241 const string& openid_message_t::get_field(const string& n) const { 241 const string& openid_message_t::get_field(const string& n) const {
242 const_iterator i=find(n); 242 const_iterator i=find(n);
243 if(i==end()) 243 if(i==end())
244 throw failed_lookup(OPKELE_CP_ n+": no such field"); 244 throw failed_lookup(OPKELE_CP_ n+": no such field");
245 return i->second; 245 return i->second;
246 } 246 }
247 247
248 openid_message_t::fields_iterator openid_message_t::fields_begin() const { 248 openid_message_t::fields_iterator openid_message_t::fields_begin() const {
249 return util::map_keys_iterator<const_iterator,string,const string&,const string*>(begin(),end()); 249 return util::map_keys_iterator<const_iterator,string,const string&,const string*>(begin(),end());
250 } 250 }
251 openid_message_t::fields_iterator openid_message_t::fields_end() const { 251 openid_message_t::fields_iterator openid_message_t::fields_end() const {
252 return util::map_keys_iterator<const_iterator,string,const string&,const string*>(end(),end()); 252 return util::map_keys_iterator<const_iterator,string,const string&,const string*>(end(),end());
253 } 253 }
254 254
255 void openid_message_t::reset_fields() { 255 void openid_message_t::reset_fields() {
256 clear(); 256 clear();
257 } 257 }
258 void openid_message_t::set_field(const string& n,const string& v) { 258 void openid_message_t::set_field(const string& n,const string& v) {
259 (*this)[n]=v; 259 (*this)[n]=v;
260 } 260 }
261 void openid_message_t::reset_field(const string& n) { 261 void openid_message_t::reset_field(const string& n) {
262 erase(n); 262 erase(n);
263 } 263 }
264 264
265} 265}
diff --git a/lib/prequeue_rp.cc b/lib/prequeue_rp.cc
index e242f87..3aa960f 100644
--- a/lib/prequeue_rp.cc
+++ b/lib/prequeue_rp.cc
@@ -1,81 +1,81 @@
1#include <iostream> 1#include <iostream>
2#include <openssl/sha.h> 2#include <openssl/sha.h>
3#include <openssl/hmac.h> 3#include <openssl/hmac.h>
4#include <opkele/exception.h> 4#include <opkele/exception.h>
5#include <opkele/prequeue_rp.h> 5#include <opkele/prequeue_rp.h>
6#include <opkele/discovery.h> 6#include <opkele/discovery.h>
7#include <opkele/uris.h> 7#include <opkele/uris.h>
8#include <opkele/data.h> 8#include <opkele/data.h>
9#include <opkele/util.h> 9#include <opkele/util.h>
10#include <opkele/curl.h> 10#include <opkele/curl.h>
11#include <opkele/debug.h> 11#include <opkele/debug.h>
12 12
13namespace opkele { 13namespace opkele {
14 14
15 class __OP_verifier_good_input : public exception { 15 class __OP_verifier_good_input : public exception {
16 public: 16 public:
17 __OP_verifier_good_input(OPKELE_E_PARS) 17 __OP_verifier_good_input(OPKELE_E_PARS)
18 : exception(OPKELE_E_CONS) { } 18 : exception(OPKELE_E_CONS) { }
19 }; 19 };
20 20
21 class OP_verifier : public iterator<output_iterator_tag,openid_endpoint_t,void> { 21 class OP_verifier : public iterator<output_iterator_tag,openid_endpoint_t,void> {
22 public: 22 public:
23 const string& OP; 23 const string& OP;
24 const string& id; 24 const string& id;
25 25
26 OP_verifier(const string& o,const string& i) 26 OP_verifier(const string& o,const string& i)
27 : OP(o), id(i) { } 27 : OP(o), id(i) { }
28 28
29 OP_verifier& operator*() { return *this; } 29 OP_verifier& operator*() { return *this; }
30 OP_verifier& operator=(const openid_endpoint_t& oep) { 30 OP_verifier& operator=(const openid_endpoint_t& oep) {
31 if(oep.uri==OP) { 31 if(oep.uri==OP) {
32 if(oep.claimed_id==IDURI_SELECT20 32 if(oep.claimed_id==IDURI_SELECT20
33 || oep.local_id==IDURI_SELECT20 ) 33 || oep.local_id==IDURI_SELECT20 )
34 throw bad_input(OPKELE_CP_ "claimed_id is an OP-Id"); 34 throw bad_input(OPKELE_CP_ "claimed_id is an OP-Id");
35 if(oep.local_id==id) 35 if(oep.local_id==id)
36 throw __OP_verifier_good_input(OPKELE_CP_ "Found corresponding endpoint"); 36 throw __OP_verifier_good_input(OPKELE_CP_ "Found corresponding endpoint");
37 } 37 }
38 return *this; 38 return *this;
39 } 39 }
40 40
41 OP_verifier& operator++() { return *this; } 41 OP_verifier& operator++() { return *this; }
42 OP_verifier& operator++(int) { return *this; } 42 OP_verifier& operator++(int) { return *this; }
43 }; 43 };
44 44
45 void prequeue_RP::verify_OP(const string& OP,const string& claimed_id,const string& identity) const { 45 void prequeue_RP::verify_OP(const string& OP,const string& claimed_id,const string& identity) const {
46 try { 46 try {
47 idiscover(OP_verifier(OP,identity),claimed_id); 47 idiscover(OP_verifier(OP,identity),claimed_id);
48 throw id_res_unauthorized(OPKELE_CP_ 48 throw id_res_unauthorized(OPKELE_CP_
49 "OP is not authorized to make an assertion regarding the identity"); 49 "OP is not authorized to make an assertion regarding the identity");
50 }catch(__OP_verifier_good_input& ovgi) { 50 }catch(__OP_verifier_good_input& ovgi) {
51 } 51 }
52 } 52 }
53 53
54 class endpoint_queuer : public iterator<output_iterator_tag,openid_endpoint_t,void> { 54 class endpoint_queuer : public iterator<output_iterator_tag,openid_endpoint_t,void> {
55 public: 55 public:
56 prequeue_RP& rp; 56 prequeue_RP& rp;
57 57
58 endpoint_queuer(prequeue_RP& rp) : rp(rp) { } 58 endpoint_queuer(prequeue_RP& r) : rp(r) { }
59 59
60 endpoint_queuer& operator*() { return *this; } 60 endpoint_queuer& operator*() { return *this; }
61 endpoint_queuer& operator=(const openid_endpoint_t& oep) { 61 endpoint_queuer& operator=(const openid_endpoint_t& oep) {
62 rp.queue_endpoint(oep); return *this; } 62 rp.queue_endpoint(oep); return *this; }
63 63
64 endpoint_queuer& operator++() { return *this; } 64 endpoint_queuer& operator++() { return *this; }
65 endpoint_queuer& operator++(int) { return *this; } 65 endpoint_queuer& operator++(int) { return *this; }
66 }; 66 };
67 67
68 void prequeue_RP::initiate(const string& usi) { 68 void prequeue_RP::initiate(const string& usi) {
69 begin_queueing(); 69 begin_queueing();
70 set_normalized_id( idiscover(endpoint_queuer(*this),usi) ); 70 set_normalized_id( idiscover(endpoint_queuer(*this),usi) );
71 end_queueing(); 71 end_queueing();
72 } 72 }
73 73
74 void prequeue_RP::set_normalized_id(const string& nid) { 74 void prequeue_RP::set_normalized_id(const string&) {
75 } 75 }
76 76
77 const string prequeue_RP::get_normalized_id() const { 77 const string prequeue_RP::get_normalized_id() const {
78 throw not_implemented(OPKELE_CP_ "get_normalized_id() is not implemented"); 78 throw not_implemented(OPKELE_CP_ "get_normalized_id() is not implemented");
79 } 79 }
80 80
81} 81}
diff --git a/lib/sreg.cc b/lib/sreg.cc
index b40cd45..0bd4d2e 100644
--- a/lib/sreg.cc
+++ b/lib/sreg.cc
@@ -1,160 +1,158 @@
1#include <opkele/exception.h> 1#include <opkele/exception.h>
2#include <opkele/sreg.h> 2#include <opkele/sreg.h>
3#include <opkele/uris.h> 3#include <opkele/uris.h>
4#include <algorithm> 4#include <algorithm>
5 5
6namespace opkele { 6namespace opkele {
7 using std::find; 7 using std::find;
8 8
9 static const struct _sreg_field { 9 static const struct _sreg_field {
10 const char *fieldname; 10 const char *fieldname;
11 sreg_t::fieldbit_t fieldbit; 11 sreg_t::fieldbit_t fieldbit;
12 }fields[] = { 12 }fields[] = {
13 { "nickname", sreg_t::field_nickname }, 13 { "nickname", sreg_t::field_nickname },
14 { "email", sreg_t::field_email }, 14 { "email", sreg_t::field_email },
15 { "fullname", sreg_t::field_fullname }, 15 { "fullname", sreg_t::field_fullname },
16 { "dob", sreg_t::field_dob }, 16 { "dob", sreg_t::field_dob },
17 { "gender", sreg_t::field_gender }, 17 { "gender", sreg_t::field_gender },
18 { "postcode", sreg_t::field_postcode }, 18 { "postcode", sreg_t::field_postcode },
19 { "country", sreg_t::field_country }, 19 { "country", sreg_t::field_country },
20 { "language", sreg_t::field_language }, 20 { "language", sreg_t::field_language },
21 { "timezone", sreg_t::field_timezone } 21 { "timezone", sreg_t::field_timezone }
22 }; 22 };
23 # define fields_BEGINfields 23 # define fields_BEGINfields
24# define fields_END &fields[sizeof(fields)/sizeof(*fields)] 24# define fields_END &fields[sizeof(fields)/sizeof(*fields)]
25 typedef const struct _sreg_field *fields_iterator; 25 typedef const struct _sreg_field *fields_iterator;
26 26
27 bool operator==(const struct _sreg_field& fd,const string& fn) { 27 bool operator==(const struct _sreg_field& fd,const string& fn) {
28 return fd.fieldname==fn; 28 return fd.fieldname==fn;
29 } 29 }
30 30
31 void sreg_t::rp_checkid_hook(basic_openid_message& om) { 31 void sreg_t::rp_checkid_hook(basic_openid_message& om) {
32 string fr, fo; 32 string fr, fo;
33 for(fields_iterator f=fields_BEGIN;f<fields_END;++f) { 33 for(fields_iterator f=fields_BEGIN;f<fields_END;++f) {
34 if(f->fieldbit&fields_required) { 34 if(f->fieldbit&fields_required) {
35 if(!fr.empty()) fr+=","; 35 if(!fr.empty()) fr+=",";
36 fr += f->fieldname; 36 fr += f->fieldname;
37 } 37 }
38 if(f->fieldbit&fields_optional) { 38 if(f->fieldbit&fields_optional) {
39 if(!fo.empty()) fo+=","; 39 if(!fo.empty()) fo+=",";
40 fo += f->fieldname; 40 fo += f->fieldname;
41 } 41 }
42 } 42 }
43 string pfx = om.allocate_ns(OIURI_SREG11,"sreg"); 43 string pfx = om.allocate_ns(OIURI_SREG11,"sreg");
44 if(!fr.empty()) om.set_field(pfx+".required",fr); 44 if(!fr.empty()) om.set_field(pfx+".required",fr);
45 if(!fo.empty()) om.set_field(pfx+".optional",fo); 45 if(!fo.empty()) om.set_field(pfx+".optional",fo);
46 if(!policy_url.empty()) om.set_field(pfx+".policy_url",policy_url); 46 if(!policy_url.empty()) om.set_field(pfx+".policy_url",policy_url);
47 } 47 }
48 48
49 void sreg_t::checkid_hook(basic_openid_message& om) { 49 void sreg_t::checkid_hook(basic_openid_message& om) {
50 rp_checkid_hook(om); } 50 rp_checkid_hook(om); }
51 51
52 void sreg_t::rp_id_res_hook(const basic_openid_message& om, 52 void sreg_t::rp_id_res_hook(const basic_openid_message& om,
53 const basic_openid_message& sp) { 53 const basic_openid_message& sp) {
54 clear(); 54 clear();
55 string pfx; 55 string pfx;
56 try { 56 try {
57 pfx = om.find_ns(OIURI_SREG11,"sreg"); 57 pfx = om.find_ns(OIURI_SREG11,"sreg");
58 }catch(failed_lookup& fl) { 58 }catch(failed_lookup&) {
59 try { 59 try {
60 pfx = om.find_ns(OIURI_SREG10,"sreg"); 60 pfx = om.find_ns(OIURI_SREG10,"sreg");
61 }catch(failed_lookup& fl) { 61 }catch(failed_lookup&) { return; }
62 return;
63 }
64 } 62 }
65 pfx += '.'; 63 pfx += '.';
66 for(fields_iterator f=fields_BEGIN;f<fields_END;++f) { 64 for(fields_iterator f=fields_BEGIN;f<fields_END;++f) {
67 string fn = pfx; fn+=f->fieldname; 65 string fn = pfx; fn+=f->fieldname;
68 if(!sp.has_field(fn)) continue; 66 if(!sp.has_field(fn)) continue;
69 has_fields |= f->fieldbit; 67 has_fields |= f->fieldbit;
70 response[f->fieldbit]=sp.get_field(fn); 68 response[f->fieldbit]=sp.get_field(fn);
71 } 69 }
72 } 70 }
73 71
74 void sreg_t::id_res_hook(const basic_openid_message& om, 72 void sreg_t::id_res_hook(const basic_openid_message& om,
75 const basic_openid_message& sp) { 73 const basic_openid_message& sp) {
76 rp_id_res_hook(om,sp); } 74 rp_id_res_hook(om,sp); }
77 75
78 const string& sreg_t::get_field(fieldbit_t fb) const { 76 const string& sreg_t::get_field(fieldbit_t fb) const {
79 response_t::const_iterator i = response.find(fb); 77 response_t::const_iterator i = response.find(fb);
80 if(i==response.end()) 78 if(i==response.end())
81 throw failed_lookup(OPKELE_CP_ "no field data available"); 79 throw failed_lookup(OPKELE_CP_ "no field data available");
82 return i->second; 80 return i->second;
83 } 81 }
84 82
85 void sreg_t::set_field(fieldbit_t fb,const string& fv) { 83 void sreg_t::set_field(fieldbit_t fb,const string& fv) {
86 response[fb] = fv; 84 response[fb] = fv;
87 has_fields |= fb; 85 has_fields |= fb;
88 } 86 }
89 87
90 void sreg_t::reset_field(fieldbit_t fb) { 88 void sreg_t::reset_field(fieldbit_t fb) {
91 has_fields &= ~fb; 89 has_fields &= ~fb;
92 response.erase(fb); 90 response.erase(fb);
93 } 91 }
94 92
95 void sreg_t::clear() { 93 void sreg_t::clear() {
96 has_fields = 0; response.clear(); 94 has_fields = 0; response.clear();
97 } 95 }
98 96
99 static long fields_list_to_bitmask(string& fl) { 97 static long fields_list_to_bitmask(string& fl) {
100 long rv = 0; 98 long rv = 0;
101 while(!fl.empty()) { 99 while(!fl.empty()) {
102 string::size_type co = fl.find(','); 100 string::size_type co = fl.find(',');
103 string fn; 101 string fn;
104 if(co==string::npos) { 102 if(co==string::npos) {
105 fn = fl; fl.erase(); 103 fn = fl; fl.erase();
106 }else{ 104 }else{
107 fn = fl.substr(0,co); fl.erase(0,co+1); 105 fn = fl.substr(0,co); fl.erase(0,co+1);
108 } 106 }
109 fields_iterator f = find(fields_BEGIN,fields_END,fn); 107 fields_iterator f = find(fields_BEGIN,fields_END,fn);
110 if(f!=fields_END) 108 if(f!=fields_END)
111 rv |= f->fieldbit; 109 rv |= f->fieldbit;
112 } 110 }
113 return rv; 111 return rv;
114 } 112 }
115 113
116 void sreg_t::op_checkid_hook(const basic_openid_message& inm) { 114 void sreg_t::op_checkid_hook(const basic_openid_message& inm) {
117 string ins = inm.find_ns(OIURI_SREG11,"sreg"); 115 string ins = inm.find_ns(OIURI_SREG11,"sreg");
118 fields_optional = 0; fields_required = 0; policy_url.erase(); 116 fields_optional = 0; fields_required = 0; policy_url.erase();
119 fields_response = 0; 117 fields_response = 0;
120 try { 118 try {
121 string fl = inm.get_field(ins+".required"); 119 string fl = inm.get_field(ins+".required");
122 fields_required = fields_list_to_bitmask(fl); 120 fields_required = fields_list_to_bitmask(fl);
123 }catch(failed_lookup&) { } 121 }catch(failed_lookup&) { }
124 try { 122 try {
125 string fl = inm.get_field(ins+".optional"); 123 string fl = inm.get_field(ins+".optional");
126 fields_optional = fields_list_to_bitmask(fl); 124 fields_optional = fields_list_to_bitmask(fl);
127 }catch(failed_lookup&) { } 125 }catch(failed_lookup&) { }
128 try { 126 try {
129 policy_url = inm.get_field(ins+".policy_url"); 127 policy_url = inm.get_field(ins+".policy_url");
130 }catch(failed_lookup&) { } 128 }catch(failed_lookup&) { }
131 } 129 }
132 130
133 void sreg_t::op_id_res_hook(basic_openid_message& oum) { 131 void sreg_t::op_id_res_hook(basic_openid_message& oum) {
134 string ons = oum.allocate_ns(OIURI_SREG11,"sreg"); 132 string ons = oum.allocate_ns(OIURI_SREG11,"sreg");
135 fields_response &= has_fields; 133 fields_response &= has_fields;
136 string signeds = "ns."+ons; 134 string signeds = "ns."+ons;
137 for(fields_iterator f=fields_BEGIN;f<fields_END;++f) { 135 for(fields_iterator f=fields_BEGIN;f<fields_END;++f) {
138 if(!(f->fieldbit&fields_response)) continue; 136 if(!(f->fieldbit&fields_response)) continue;
139 signeds +=','; 137 signeds +=',';
140 string pn = ons; pn += '.'; pn += f->fieldname; 138 string pn = ons; pn += '.'; pn += f->fieldname;
141 signeds += pn; 139 signeds += pn;
142 oum.set_field(pn,get_field(f->fieldbit)); 140 oum.set_field(pn,get_field(f->fieldbit));
143 } 141 }
144 oum.add_to_signed(signeds); 142 oum.add_to_signed(signeds);
145 } 143 }
146 144
147 void sreg_t::checkid_hook(const basic_openid_message& inm, 145 void sreg_t::checkid_hook(const basic_openid_message& inm,
148 basic_openid_message& oum) { 146 basic_openid_message& oum) {
149 op_checkid_hook(inm); 147 op_checkid_hook(inm);
150 setup_response(inm,oum); 148 setup_response(inm,oum);
151 op_id_res_hook(oum); 149 op_id_res_hook(oum);
152 } 150 }
153 151
154 void sreg_t::setup_response(const basic_openid_message& /* inm */,basic_openid_message& /* oum */) { 152 void sreg_t::setup_response(const basic_openid_message& /* inm */,basic_openid_message& /* oum */) {
155 setup_response(); 153 setup_response();
156 } 154 }
157 void sreg_t::setup_response() { 155 void sreg_t::setup_response() {
158 fields_response = (fields_required|fields_optional)&has_fields; 156 fields_response = (fields_required|fields_optional)&has_fields;
159 } 157 }
160} 158}
diff --git a/lib/verify_op.cc b/lib/verify_op.cc
index ab21b4f..c493c12 100644
--- a/lib/verify_op.cc
+++ b/lib/verify_op.cc
@@ -1,53 +1,53 @@
1#include <opkele/verify_op.h> 1#include <opkele/verify_op.h>
2#include <opkele/discovery.h> 2#include <opkele/discovery.h>
3#include <opkele/exception.h> 3#include <opkele/exception.h>
4#include <opkele/util.h> 4#include <opkele/util.h>
5#include <opkele/uris.h> 5#include <opkele/uris.h>
6 6
7namespace opkele { 7namespace opkele {
8 using std::output_iterator_tag; 8 using std::output_iterator_tag;
9 9
10 class __RP_verifier_good_input : public exception { 10 class __RP_verifier_good_input : public exception {
11 public: 11 public:
12 __RP_verifier_good_input(OPKELE_E_PARS) 12 __RP_verifier_good_input(OPKELE_E_PARS)
13 : exception(OPKELE_E_CONS) { } 13 : exception(OPKELE_E_CONS) { }
14 }; 14 };
15 15
16 class RP_verifier : public iterator<output_iterator_tag,openid_endpoint_t,void> { 16 class RP_verifier : public iterator<output_iterator_tag,openid_endpoint_t,void> {
17 public: 17 public:
18 int seen;
19 const string& return_to; 18 const string& return_to;
19 int seen;
20 20
21 RP_verifier(const string& rt) 21 RP_verifier(const string& rt)
22 : return_to(rt), seen(0) { } 22 : return_to(rt), seen(0) { }
23 23
24 RP_verifier& operator*() { return *this; } 24 RP_verifier& operator*() { return *this; }
25 RP_verifier& operator=(const openid_endpoint_t& oep) { 25 RP_verifier& operator=(const openid_endpoint_t& oep) {
26 if(util::uri_matches_realm(return_to,oep.uri)) 26 if(util::uri_matches_realm(return_to,oep.uri))
27 throw __RP_verifier_good_input(OPKELE_CP_ "Found matching realm"); 27 throw __RP_verifier_good_input(OPKELE_CP_ "Found matching realm");
28 return *this; 28 return *this;
29 } 29 }
30 30
31 RP_verifier& operator++() { ++seen; return *this; } 31 RP_verifier& operator++() { ++seen; return *this; }
32 RP_verifier& operator++(int) { +seen; return *this; } 32 RP_verifier& operator++(int) { ++seen; return *this; }
33 }; 33 };
34 34
35 void verify_OP::verify_return_to() { 35 void verify_OP::verify_return_to() {
36 basic_OP::verify_return_to(); 36 basic_OP::verify_return_to();
37 try { 37 try {
38 RP_verifier rpv(return_to); 38 RP_verifier rpv(return_to);
39 string drealm = realm; 39 string drealm = realm;
40 string::size_type csss = drealm.find("://*."); 40 string::size_type csss = drealm.find("://*.");
41 if(csss==4 || csss==5) 41 if(csss==4 || csss==5)
42 drealm.replace(csss+3,1,"www"); 42 drealm.replace(csss+3,1,"www");
43 const char *rtt[] = { STURI_OPENID20_RT, 0 }; 43 const char *rtt[] = { STURI_OPENID20_RT, 0 };
44 yadiscover(rpv,drealm,rtt,false); 44 yadiscover(rpv,drealm,rtt,false);
45 if(rpv.seen) 45 if(rpv.seen)
46 throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match any found while doing discovery on RP"); 46 throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match any found while doing discovery on RP");
47 }catch(__RP_verifier_good_input&) { 47 }catch(__RP_verifier_good_input&) {
48 }catch(bad_return_to& brt) { 48 }catch(bad_return_to& brt) {
49 throw; 49 throw;
50 }catch(exception_network&) { } 50 }catch(exception_network&) { }
51 } 51 }
52 52
53} 53}
diff --git a/test/OP.cc b/test/OP.cc
index 851d831..6012b2e 100644
--- a/test/OP.cc
+++ b/test/OP.cc
@@ -1,415 +1,415 @@
1#include <uuid/uuid.h> 1#include <uuid/uuid.h>
2#include <iostream> 2#include <iostream>
3#include <cassert> 3#include <cassert>
4#include <string> 4#include <string>
5#include <ext/algorithm> 5#include <ext/algorithm>
6using namespace std; 6using namespace std;
7#include <kingate/exception.h> 7#include <kingate/exception.h>
8#include <kingate/plaincgi.h> 8#include <kingate/plaincgi.h>
9#include <kingate/cgi_gateway.h> 9#include <kingate/cgi_gateway.h>
10#include <opkele/exception.h> 10#include <opkele/exception.h>
11#include <opkele/util.h> 11#include <opkele/util.h>
12#include <opkele/uris.h> 12#include <opkele/uris.h>
13#include <opkele/extension.h> 13#include <opkele/extension.h>
14#include <opkele/association.h> 14#include <opkele/association.h>
15#include <opkele/debug.h> 15#include <opkele/debug.h>
16#include <opkele/verify_op.h> 16#include <opkele/verify_op.h>
17#include <opkele/sreg.h> 17#include <opkele/sreg.h>
18 18
19#include "sqlite.h" 19#include "sqlite.h"
20#include "kingate_openid_message.h" 20#include "kingate_openid_message.h"
21 21
22static const string get_self_url(const kingate::cgi_gateway& gw) { 22static const string get_self_url(const kingate::cgi_gateway& gw) {
23 bool s = gw.has_meta("SSL_PROTOCOL_VERSION"); 23 bool s = gw.has_meta("SSL_PROTOCOL_VERSION");
24 string rv = s?"https://":"http://"; 24 string rv = s?"https://":"http://";
25 rv += gw.http_request_header("Host"); 25 rv += gw.http_request_header("Host");
26 const string& port = gw.get_meta("SERVER_PORT"); 26 const string& port = gw.get_meta("SERVER_PORT");
27 if( port!=(s?"443":"80") ) { 27 if( port!=(s?"443":"80") ) {
28 rv += ':'; rv += port; 28 rv += ':'; rv += port;
29 } 29 }
30 rv += gw.get_meta("REQUEST_URI"); 30 rv += gw.get_meta("REQUEST_URI");
31 string::size_type q = rv.find('?'); 31 string::size_type q = rv.find('?');
32 if(q!=string::npos) 32 if(q!=string::npos)
33 rv.erase(q); 33 rv.erase(q);
34 return rv; 34 return rv;
35} 35}
36 36
37class opdb_t : public sqlite3_t { 37class opdb_t : public sqlite3_t {
38 public: 38 public:
39 opdb_t() 39 opdb_t()
40 : sqlite3_t("/tmp/OP.db") { 40 : sqlite3_t("/tmp/OP.db") {
41 assert(_D); 41 assert(_D);
42 char **resp; int nr,nc; char *errm; 42 char **resp; int nr,nc; char *errm;
43 if(sqlite3_get_table( 43 if(sqlite3_get_table(
44 _D, "SELECT a_op FROM assoc LIMIT 0", 44 _D, "SELECT a_op FROM assoc LIMIT 0",
45 &resp,&nr,&nc,&errm)!=SQLITE_OK) { 45 &resp,&nr,&nc,&errm)!=SQLITE_OK) {
46 extern const char *__OP_db_bootstrap; 46 extern const char *__OP_db_bootstrap;
47 DOUT_("Bootstrapping DB"); 47 DOUT_("Bootstrapping DB");
48 if(sqlite3_exec(_D,__OP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK) 48 if(sqlite3_exec(_D,__OP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK)
49 throw opkele::exception(OPKELE_CP_ string("Failed to boostrap SQLite database: ")+errm); 49 throw opkele::exception(OPKELE_CP_ string("Failed to boostrap SQLite database: ")+errm);
50 }else 50 }else
51 sqlite3_free_table(resp); 51 sqlite3_free_table(resp);
52 } 52 }
53}; 53};
54 54
55class example_op_t : public opkele::verify_OP { 55class example_op_t : public opkele::verify_OP {
56 public: 56 public:
57 kingate::cgi_gateway& gw; 57 kingate::cgi_gateway& gw;
58 opdb_t db; 58 opdb_t db;
59 kingate::cookie htc; 59 kingate::cookie htc;
60 60
61 61
62 example_op_t(kingate::cgi_gateway& gw) 62 example_op_t(kingate::cgi_gateway& g)
63 : gw(gw) { 63 : gw(g) {
64 try { 64 try {
65 htc = gw.cookies.get_cookie("htop_session"); 65 htc = gw.cookies.get_cookie("htop_session");
66 sqlite3_mem_t<char*> S = sqlite3_mprintf( 66 sqlite3_mem_t<char*> S = sqlite3_mprintf(
67 "SELECT 1 FROM ht_sessions WHERE hts_id=%Q", 67 "SELECT 1 FROM ht_sessions WHERE hts_id=%Q",
68 htc.get_value().c_str()); 68 htc.get_value().c_str());
69 sqlite3_table_t T; int nr,nc; 69 sqlite3_table_t T; int nr,nc;
70 db.get_table(S,T,&nr,&nc); 70 db.get_table(S,T,&nr,&nc);
71 if(nr<1) 71 if(nr<1)
72 throw kingate::exception_notfound(CODEPOINT,"forcing cookie generation"); 72 throw kingate::exception_notfound(CODEPOINT,"forcing cookie generation");
73 }catch(kingate::exception_notfound& kenf) { 73 }catch(kingate::exception_notfound& kenf) {
74 uuid_t uuid; uuid_generate(uuid); 74 uuid_t uuid; uuid_generate(uuid);
75 htc = kingate::cookie("htop_session",opkele::util::encode_base64(uuid,sizeof(uuid))); 75 htc = kingate::cookie("htop_session",opkele::util::encode_base64(uuid,sizeof(uuid)));
76 sqlite3_mem_t<char*> S = sqlite3_mprintf( 76 sqlite3_mem_t<char*> S = sqlite3_mprintf(
77 "INSERT INTO ht_sessions (hts_id) VALUES (%Q)", 77 "INSERT INTO ht_sessions (hts_id) VALUES (%Q)",
78 htc.get_value().c_str()); 78 htc.get_value().c_str());
79 db.exec(S); 79 db.exec(S);
80 } 80 }
81 } 81 }
82 82
83 void set_authorized(bool a) { 83 void set_authorized(bool a) {
84 sqlite3_mem_t<char*> 84 sqlite3_mem_t<char*>
85 S = sqlite3_mprintf( 85 S = sqlite3_mprintf(
86 "UPDATE ht_sessions" 86 "UPDATE ht_sessions"
87 " SET authorized=%d" 87 " SET authorized=%d"
88 " WHERE hts_id=%Q", 88 " WHERE hts_id=%Q",
89 (int)a,htc.get_value().c_str()); 89 (int)a,htc.get_value().c_str());
90 db.exec(S); 90 db.exec(S);
91 } 91 }
92 bool get_authorized() { 92 bool get_authorized() {
93 sqlite3_mem_t<char*> 93 sqlite3_mem_t<char*>
94 S = sqlite3_mprintf( 94 S = sqlite3_mprintf(
95 "SELECT authorized" 95 "SELECT authorized"
96 " FROM ht_sessions" 96 " FROM ht_sessions"
97 " WHERE hts_id=%Q", 97 " WHERE hts_id=%Q",
98 htc.get_value().c_str()); 98 htc.get_value().c_str());
99 sqlite3_table_t T; int nr,nc; 99 sqlite3_table_t T; int nr,nc;
100 db.get_table(S,T,&nr,&nc); 100 db.get_table(S,T,&nr,&nc);
101 assert(nr==1); assert(nc=1); 101 assert(nr==1); assert(nc=1);
102 return opkele::util::string_to_long(T.get(1,0,nc)); 102 return opkele::util::string_to_long(T.get(1,0,nc));
103 } 103 }
104 104
105 ostream& cookie_header(ostream& o) const { 105 ostream& cookie_header(ostream& o) const {
106 o << "Set-Cookie: " << htc.set_cookie_header() << "\n"; 106 o << "Set-Cookie: " << htc.set_cookie_header() << "\n";
107 return o; 107 return o;
108 } 108 }
109 109
110 opkele::assoc_t alloc_assoc(const string& type,size_t klength,bool sl) { 110 opkele::assoc_t alloc_assoc(const string& type,size_t klength,bool sl) {
111 uuid_t uuid; uuid_generate(uuid); 111 uuid_t uuid; uuid_generate(uuid);
112 string a_handle = opkele::util::encode_base64(uuid,sizeof(uuid)); 112 string a_handle = opkele::util::encode_base64(uuid,sizeof(uuid));
113 opkele::secret_t a_secret; 113 opkele::secret_t a_secret;
114 generate_n( 114 generate_n(
115 back_insert_iterator<opkele::secret_t>(a_secret),klength, 115 back_insert_iterator<opkele::secret_t>(a_secret),klength,
116 rand ); 116 rand );
117 string ssecret; a_secret.to_base64(ssecret); 117 string ssecret; a_secret.to_base64(ssecret);
118 time_t now = time(0); 118 time_t now = time(0);
119 int expires_in = sl?3600*2:3600*24*7*2; 119 int expires_in = sl?3600*2:3600*24*7*2;
120 sqlite3_mem_t<char*> 120 sqlite3_mem_t<char*>
121 S = sqlite3_mprintf( 121 S = sqlite3_mprintf(
122 "INSERT INTO assoc" 122 "INSERT INTO assoc"
123 " (a_handle,a_type,a_ctime,a_etime,a_secret,a_stateless)" 123 " (a_handle,a_type,a_ctime,a_etime,a_secret,a_stateless)"
124 " VALUES (" 124 " VALUES ("
125 " %Q,%Q,datetime('now')," 125 " %Q,%Q,datetime('now'),"
126 " datetime('now','+%d seconds')," 126 " datetime('now','+%d seconds'),"
127 " %Q,%d );", 127 " %Q,%d );",
128 a_handle.c_str(), type.c_str(), 128 a_handle.c_str(), type.c_str(),
129 expires_in, 129 expires_in,
130 ssecret.c_str(), sl ); 130 ssecret.c_str(), sl );
131 db.exec(S); 131 db.exec(S);
132 return opkele::assoc_t(new opkele::association( 132 return opkele::assoc_t(new opkele::association(
133 "", 133 "",
134 a_handle, type, a_secret, 134 a_handle, type, a_secret,
135 now+expires_in, sl )); 135 now+expires_in, sl ));
136 } 136 }
137 137
138 opkele::assoc_t retrieve_assoc(const string& h) { 138 opkele::assoc_t retrieve_assoc(const string& h) {
139 sqlite3_mem_t<char*> 139 sqlite3_mem_t<char*>
140 S = sqlite3_mprintf( 140 S = sqlite3_mprintf(
141 "SELECT" 141 "SELECT"
142 " a_handle,a_type,a_secret,a_stateless," 142 " a_handle,a_type,a_secret,a_stateless,"
143 " strftime('%%s',a_etime) AS a_etime," 143 " strftime('%%s',a_etime) AS a_etime,"
144 " a_itime" 144 " a_itime"
145 " FROM assoc" 145 " FROM assoc"
146 " WHERE a_handle=%Q AND a_itime IS NULL" 146 " WHERE a_handle=%Q AND a_itime IS NULL"
147 " AND datetime('now') < a_etime" 147 " AND datetime('now') < a_etime"
148 " LIMIT 1", 148 " LIMIT 1",
149 h.c_str() ); 149 h.c_str() );
150 sqlite3_table_t T; 150 sqlite3_table_t T;
151 int nr,nc; 151 int nr,nc;
152 db.get_table(S,T,&nr,&nc); 152 db.get_table(S,T,&nr,&nc);
153 if(nr<1) 153 if(nr<1)
154 throw opkele::failed_lookup(OPKELE_CP_ 154 throw opkele::failed_lookup(OPKELE_CP_
155 "couldn't retrieve valid unexpired assoc"); 155 "couldn't retrieve valid unexpired assoc");
156 assert(nr==1); assert(nc==6); 156 assert(nr==1); assert(nc==6);
157 opkele::secret_t secret; opkele::util::decode_base64(T.get(1,2,nc),secret); 157 opkele::secret_t secret; opkele::util::decode_base64(T.get(1,2,nc),secret);
158 return opkele::assoc_t(new opkele::association( 158 return opkele::assoc_t(new opkele::association(
159 "", h, T.get(1,1,nc), secret, 159 "", h, T.get(1,1,nc), secret,
160 strtol(T.get(1,4,nc),0,0), 160 strtol(T.get(1,4,nc),0,0),
161 strtol(T.get(1,3,nc),0,0) )); 161 strtol(T.get(1,3,nc),0,0) ));
162 } 162 }
163 163
164 string& alloc_nonce(string& nonce) { 164 string& alloc_nonce(string& nonce) {
165 uuid_t uuid; uuid_generate(uuid); 165 uuid_t uuid; uuid_generate(uuid);
166 nonce += opkele::util::encode_base64(uuid,sizeof(uuid)); 166 nonce += opkele::util::encode_base64(uuid,sizeof(uuid));
167 sqlite3_mem_t<char*> 167 sqlite3_mem_t<char*>
168 S = sqlite3_mprintf( 168 S = sqlite3_mprintf(
169 "INSERT INTO nonces" 169 "INSERT INTO nonces"
170 " (n_once) VALUES (%Q)", 170 " (n_once) VALUES (%Q)",
171 nonce.c_str() ); 171 nonce.c_str() );
172 db.exec(S); 172 db.exec(S);
173 return nonce; 173 return nonce;
174 } 174 }
175 bool check_nonce(const string& nonce) { 175 bool check_nonce(const string& nonce) {
176 sqlite3_mem_t<char*> 176 sqlite3_mem_t<char*>
177 S = sqlite3_mprintf( 177 S = sqlite3_mprintf(
178 "SELECT 1" 178 "SELECT 1"
179 " FROM nonces" 179 " FROM nonces"
180 " WHERE n_once=%Q AND n_itime IS NULL", 180 " WHERE n_once=%Q AND n_itime IS NULL",
181 nonce.c_str()); 181 nonce.c_str());
182 sqlite3_table_t T; 182 sqlite3_table_t T;
183 int nr,nc; 183 int nr,nc;
184 db.get_table(S,T,&nr,&nc); 184 db.get_table(S,T,&nr,&nc);
185 return nr>=1; 185 return nr>=1;
186 } 186 }
187 void invalidate_nonce(const string& nonce) { 187 void invalidate_nonce(const string& nonce) {
188 sqlite3_mem_t<char*> 188 sqlite3_mem_t<char*>
189 S = sqlite3_mprintf( 189 S = sqlite3_mprintf(
190 "UPDATE nonces" 190 "UPDATE nonces"
191 " SET n_itime=datetime('now')" 191 " SET n_itime=datetime('now')"
192 " WHERE n_once=%Q", 192 " WHERE n_once=%Q",
193 nonce.c_str()); 193 nonce.c_str());
194 db.exec(S); 194 db.exec(S);
195 } 195 }
196 196
197 const string get_op_endpoint() const { 197 const string get_op_endpoint() const {
198 return get_self_url(gw); 198 return get_self_url(gw);
199 } 199 }
200 200
201}; 201};
202 202
203int main(int argc,char *argv[]) { 203int main(int,char **) {
204 try { 204 try {
205 kingate::plaincgi_interface ci; 205 kingate::plaincgi_interface ci;
206 kingate::cgi_gateway gw(ci); 206 kingate::cgi_gateway gw(ci);
207 string op; 207 string op;
208 try { op = gw.get_param("op"); }catch(kingate::exception_notfound&) { } 208 try { op = gw.get_param("op"); }catch(kingate::exception_notfound&) { }
209 string message; 209 string message;
210 if(op=="set_password") { 210 if(op=="set_password") {
211 example_op_t OP(gw); 211 example_op_t OP(gw);
212 string password = gw.get_param("password"); 212 string password = gw.get_param("password");
213 sqlite3_mem_t<char*> 213 sqlite3_mem_t<char*>
214 Sget = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1"); 214 Sget = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1");
215 sqlite3_table_t T; int nr,nc; 215 sqlite3_table_t T; int nr,nc;
216 OP.db.get_table(Sget,T,&nr,&nc); 216 OP.db.get_table(Sget,T,&nr,&nc);
217 if(nr>=1) 217 if(nr>=1)
218 throw opkele::exception(OPKELE_CP_ "Password already set"); 218 throw opkele::exception(OPKELE_CP_ "Password already set");
219 sqlite3_mem_t<char*> 219 sqlite3_mem_t<char*>
220 Sset = sqlite3_mprintf( 220 Sset = sqlite3_mprintf(
221 "INSERT INTO setup (s_password) VALUES (%Q)", 221 "INSERT INTO setup (s_password) VALUES (%Q)",
222 password.c_str()); 222 password.c_str());
223 OP.db.exec(Sset); 223 OP.db.exec(Sset);
224 op.clear(); 224 op.clear();
225 message = "password set"; 225 message = "password set";
226 }else if(op=="login") { 226 }else if(op=="login") {
227 example_op_t OP(gw); 227 example_op_t OP(gw);
228 string password = gw.get_param("password"); 228 string password = gw.get_param("password");
229 sqlite3_mem_t<char*> 229 sqlite3_mem_t<char*>
230 Sget = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1"); 230 Sget = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1");
231 sqlite3_table_t T; int nr,nc; 231 sqlite3_table_t T; int nr,nc;
232 OP.db.get_table(Sget,T,&nr,&nc); 232 OP.db.get_table(Sget,T,&nr,&nc);
233 if(nr<1) 233 if(nr<1)
234 throw opkele::exception(OPKELE_CP_ "no password set"); 234 throw opkele::exception(OPKELE_CP_ "no password set");
235 if(password!=T.get(1,0,nc)) 235 if(password!=T.get(1,0,nc))
236 throw opkele::exception(OPKELE_CP_ "wrong password"); 236 throw opkele::exception(OPKELE_CP_ "wrong password");
237 OP.set_authorized(true); 237 OP.set_authorized(true);
238 op.clear(); 238 op.clear();
239 message = "logged in"; 239 message = "logged in";
240 OP.cookie_header(cout); 240 OP.cookie_header(cout);
241 }else if(op=="logout") { 241 }else if(op=="logout") {
242 example_op_t OP(gw); 242 example_op_t OP(gw);
243 OP.set_authorized(false); 243 OP.set_authorized(false);
244 op.clear(); 244 op.clear();
245 message = "logged out"; 245 message = "logged out";
246 } 246 }
247 string om; 247 string omode;
248 try { om = gw.get_param("openid.mode"); }catch(kingate::exception_notfound&) { } 248 try { omode = gw.get_param("openid.mode"); }catch(kingate::exception_notfound&) { }
249 if(op=="xrds") { 249 if(op=="xrds") {
250 cout << 250 cout <<
251 "Content-type: application/xrds+xml\n\n" 251 "Content-type: application/xrds+xml\n\n"
252 "<?xml version='1.0' encoding='utf-8'?>" 252 "<?xml version='1.0' encoding='utf-8'?>"
253 "<xrds:XRDS xmlns:xrds='xri://$xrds' xmlns='xri://$xrd*($v*2.0)'>" 253 "<xrds:XRDS xmlns:xrds='xri://$xrds' xmlns='xri://$xrd*($v*2.0)'>"
254 "<XRD>" 254 "<XRD>"
255 "<Service>" 255 "<Service>"
256 "<Type>" STURI_OPENID20 "</Type>" 256 "<Type>" STURI_OPENID20 "</Type>"
257 "<URI>" << get_self_url(gw) << "</URI>" 257 "<URI>" << get_self_url(gw) << "</URI>"
258 "</Service>"; 258 "</Service>";
259 if(gw.has_param("idsel")){ 259 if(gw.has_param("idsel")){
260 cout << 260 cout <<
261 "<Service>" 261 "<Service>"
262 "<Type>" STURI_OPENID20_OP "</Type>" 262 "<Type>" STURI_OPENID20_OP "</Type>"
263 "<URI>" << get_self_url(gw) << "</URI>"; 263 "<URI>" << get_self_url(gw) << "</URI>";
264 } 264 }
265 cout << 265 cout <<
266 "</XRD>" 266 "</XRD>"
267 "</xrds:XRDS>"; 267 "</xrds:XRDS>";
268 }else if(op=="id_res" || op=="cancel") { 268 }else if(op=="id_res" || op=="cancel") {
269 kingate_openid_message_t inm(gw); 269 kingate_openid_message_t inm(gw);
270 example_op_t OP(gw); 270 example_op_t OP(gw);
271 if(gw.get_param("hts_id")!=OP.htc.get_value()) 271 if(gw.get_param("hts_id")!=OP.htc.get_value())
272 throw opkele::exception(OPKELE_CP_ "toying around, huh?"); 272 throw opkele::exception(OPKELE_CP_ "toying around, huh?");
273 opkele::sreg_t sreg; 273 opkele::sreg_t sreg;
274 OP.checkid_(inm,sreg); 274 OP.checkid_(inm,sreg);
275 OP.cookie_header(cout); 275 OP.cookie_header(cout);
276 opkele::openid_message_t om; 276 opkele::openid_message_t om;
277 if(op=="id_res") { 277 if(op=="id_res") {
278 if(!OP.get_authorized()) 278 if(!OP.get_authorized())
279 throw opkele::exception(OPKELE_CP_ "not logged in"); 279 throw opkele::exception(OPKELE_CP_ "not logged in");
280 if(OP.is_id_select()) { 280 if(OP.is_id_select()) {
281 OP.select_identity( get_self_url(gw), get_self_url(gw) ); 281 OP.select_identity( get_self_url(gw), get_self_url(gw) );
282 } 282 }
283 sreg.set_field(opkele::sreg_t::field_nickname,"anonymous"); 283 sreg.set_field(opkele::sreg_t::field_nickname,"anonymous");
284 sreg.set_field(opkele::sreg_t::field_fullname,"Ann O'Nymus"); 284 sreg.set_field(opkele::sreg_t::field_fullname,"Ann O'Nymus");
285 sreg.set_field(opkele::sreg_t::field_gender,"F"); 285 sreg.set_field(opkele::sreg_t::field_gender,"F");
286 sreg.setup_response(); 286 sreg.setup_response();
287 cout << 287 cout <<
288 "Status: 302 Going back to RP with id_res\n" 288 "Status: 302 Going back to RP with id_res\n"
289 "Location: " << OP.id_res(om,sreg).append_query(OP.get_return_to()) 289 "Location: " << OP.id_res(om,sreg).append_query(OP.get_return_to())
290 << "\n\n"; 290 << "\n\n";
291 }else{ 291 }else{
292 cout << 292 cout <<
293 "Status: 302 Going back to RP with cancel\n" 293 "Status: 302 Going back to RP with cancel\n"
294 "Location: " << OP.cancel(om).append_query(OP.get_return_to()) 294 "Location: " << OP.cancel(om).append_query(OP.get_return_to())
295 << "\n\n"; 295 << "\n\n";
296 } 296 }
297 om.to_keyvalues(clog); 297 om.to_keyvalues(clog);
298 }else if(om=="associate") { 298 }else if(omode=="associate") {
299 kingate_openid_message_t inm(gw); 299 kingate_openid_message_t inm(gw);
300 opkele::openid_message_t oum; 300 opkele::openid_message_t oum;
301 example_op_t OP(gw); 301 example_op_t OP(gw);
302 OP.associate(oum,inm); 302 OP.associate(oum,inm);
303 cout << "Content-type: text/plain\n\n"; 303 cout << "Content-type: text/plain\n\n";
304 oum.to_keyvalues(cout); 304 oum.to_keyvalues(cout);
305 }else if(om=="checkid_setup") { 305 }else if(omode=="checkid_setup") {
306 kingate_openid_message_t inm(gw); 306 kingate_openid_message_t inm(gw);
307 example_op_t OP(gw); 307 example_op_t OP(gw);
308 OP.checkid_(inm,0); 308 OP.checkid_(inm,0);
309 OP.cookie_header(cout) << 309 OP.cookie_header(cout) <<
310 "Content-type: text/html\n" 310 "Content-type: text/html\n"
311 "\n" 311 "\n"
312 312
313 "<html>" 313 "<html>"
314 "<head>" 314 "<head>"
315 "<title>test OP: confirm authentication</title>" 315 "<title>test OP: confirm authentication</title>"
316 "</head>" 316 "</head>"
317 "<body>" 317 "<body>"
318 "realm: " << OP.get_realm() << "<br/>" 318 "realm: " << OP.get_realm() << "<br/>"
319 "return_to: " << OP.get_return_to() << "<br/>" 319 "return_to: " << OP.get_return_to() << "<br/>"
320 "claimed_id: " << OP.get_claimed_id() << "<br/>" 320 "claimed_id: " << OP.get_claimed_id() << "<br/>"
321 "identity: " << OP.get_identity() << "<br/>"; 321 "identity: " << OP.get_identity() << "<br/>";
322 if(OP.is_id_select()) { 322 if(OP.is_id_select()) {
323 OP.select_identity( get_self_url(gw), get_self_url(gw) ); 323 OP.select_identity( get_self_url(gw), get_self_url(gw) );
324 cout << 324 cout <<
325 "selected claimed_id: " << OP.get_claimed_id() << "<br/>" 325 "selected claimed_id: " << OP.get_claimed_id() << "<br/>"
326 "selected identity: " << OP.get_identity() << "<br/>"; 326 "selected identity: " << OP.get_identity() << "<br/>";
327 } 327 }
328 cout << 328 cout <<
329 "<form method='post'>"; 329 "<form method='post'>";
330 inm.to_htmlhiddens(cout); 330 inm.to_htmlhiddens(cout);
331 cout << 331 cout <<
332 "<input type='hidden' name='hts_id'" 332 "<input type='hidden' name='hts_id'"
333 " value='" << opkele::util::attr_escape(OP.htc.get_value()) << "'/>" 333 " value='" << opkele::util::attr_escape(OP.htc.get_value()) << "'/>"
334 "<input type='submit' name='op' value='id_res'/>" 334 "<input type='submit' name='op' value='id_res'/>"
335 "<input type='submit' name='op' value='cancel'/>" 335 "<input type='submit' name='op' value='cancel'/>"
336 "</form>" 336 "</form>"
337 "</body>" 337 "</body>"
338 "</html>"; 338 "</html>";
339 }else if(om=="check_authentication") { 339 }else if(omode=="check_authentication") {
340 kingate_openid_message_t inm(gw); 340 kingate_openid_message_t inm(gw);
341 example_op_t OP(gw); 341 example_op_t OP(gw);
342 opkele::openid_message_t oum; 342 opkele::openid_message_t oum;
343 OP.check_authentication(oum,inm); 343 OP.check_authentication(oum,inm);
344 cout << "Content-type: text/plain\n\n"; 344 cout << "Content-type: text/plain\n\n";
345 oum.to_keyvalues(cout); 345 oum.to_keyvalues(cout);
346 oum.to_keyvalues(clog); 346 oum.to_keyvalues(clog);
347 }else{ 347 }else{
348 example_op_t OP(gw); 348 example_op_t OP(gw);
349 string idsel; 349 string idsel;
350 if(gw.has_param("idsel")) 350 if(gw.has_param("idsel"))
351 idsel = "&idsel=idsel"; 351 idsel = "&idsel=idsel";
352 OP.cookie_header(cout) << 352 OP.cookie_header(cout) <<
353 "Content-type: text/html\n" 353 "Content-type: text/html\n"
354 "X-XRDS-Location: " << get_self_url(gw) << "?op=xrds" << idsel << "\n" 354 "X-XRDS-Location: " << get_self_url(gw) << "?op=xrds" << idsel << "\n"
355 "\n" 355 "\n"
356 356
357 "<html>" 357 "<html>"
358 "<head>" 358 "<head>"
359 "<title>test OP</title>" 359 "<title>test OP</title>"
360 "<link rel='openid.server' href='" << get_self_url(gw) << "'/>" 360 "<link rel='openid.server' href='" << get_self_url(gw) << "'/>"
361 "</head>" 361 "</head>"
362 "<body>" 362 "<body>"
363 "test openid 2.0 endpoint" 363 "test openid 2.0 endpoint"
364 "<br/>" 364 "<br/>"
365 "<a href='" << get_self_url(gw) << "?op=xrds" << idsel << "'>XRDS document</a>" 365 "<a href='" << get_self_url(gw) << "?op=xrds" << idsel << "'>XRDS document</a>"
366 "<br/>" 366 "<br/>"
367 "<h1>" << message << "</h1>"; 367 "<h1>" << message << "</h1>";
368 sqlite3_mem_t<char*> 368 sqlite3_mem_t<char*>
369 S = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1"); 369 S = sqlite3_mprintf("SELECT s_password FROM setup LIMIT 1");
370 sqlite3_table_t T; int nr,nc; 370 sqlite3_table_t T; int nr,nc;
371 OP.db.get_table(S,T,&nr,&nc); 371 OP.db.get_table(S,T,&nr,&nc);
372 if(nr<1) { 372 if(nr<1) {
373 cout << 373 cout <<
374 "<form method='post'>" 374 "<form method='post'>"
375 "set password " 375 "set password "
376 "<input type='hidden' name='op' value='set_password'/>" 376 "<input type='hidden' name='op' value='set_password'/>"
377 "<input type='password' name='password' value=''/>" 377 "<input type='password' name='password' value=''/>"
378 "<input type='submit' name='submit' value='submit'/>" 378 "<input type='submit' name='submit' value='submit'/>"
379 "</form>"; 379 "</form>";
380 }else if(OP.get_authorized()) { 380 }else if(OP.get_authorized()) {
381 cout << 381 cout <<
382 "<br/>" 382 "<br/>"
383 "<a href='" << get_self_url(gw) << "?op=logout'>logout</a>"; 383 "<a href='" << get_self_url(gw) << "?op=logout'>logout</a>";
384 }else{ 384 }else{
385 cout << 385 cout <<
386 "<form method='post'>" 386 "<form method='post'>"
387 "login " 387 "login "
388 "<input type='hidden' name='op' value='login'/>" 388 "<input type='hidden' name='op' value='login'/>"
389 "<input type='password' name='password' value=''/>" 389 "<input type='password' name='password' value=''/>"
390 "<input type='submit' name='submit' value='submit'/>" 390 "<input type='submit' name='submit' value='submit'/>"
391 "</form>"; 391 "</form>";
392 } 392 }
393 cout << "</body>"; 393 cout << "</body>";
394 } 394 }
395#ifdef OPKELE_HAVE_KONFORKA 395#ifdef OPKELE_HAVE_KONFORKA
396 }catch(konforka::exception& e) { 396 }catch(konforka::exception& e) {
397#else 397#else
398 }catch(std::exception& e){ 398 }catch(std::exception& e){
399#endif 399#endif
400 DOUT_("Oops: " << e.what()); 400 DOUT_("Oops: " << e.what());
401 cout << "Content-Type: text/plain\n\n" 401 cout << "Content-Type: text/plain\n\n"
402 "Exception:\n" 402 "Exception:\n"
403 " what: " << e.what() << endl; 403 " what: " << e.what() << endl;
404#ifdef OPKELE_HAVE_KONFORKA 404#ifdef OPKELE_HAVE_KONFORKA
405 cout << " where: " << e.where() << endl; 405 cout << " where: " << e.where() << endl;
406 if(!e._seen.empty()) { 406 if(!e._seen.empty()) {
407 cout << " seen:" << endl; 407 cout << " seen:" << endl;
408 for(list<konforka::code_point>::const_iterator 408 for(list<konforka::code_point>::const_iterator
409 i=e._seen.begin();i!=e._seen.end();++i) { 409 i=e._seen.begin();i!=e._seen.end();++i) {
410 cout << " " << i->c_str() << endl; 410 cout << " " << i->c_str() << endl;
411 } 411 }
412 } 412 }
413#endif 413#endif
414 } 414 }
415} 415}
diff --git a/test/RP.cc b/test/RP.cc
index e9744a4..99a792c 100644
--- a/test/RP.cc
+++ b/test/RP.cc
@@ -1,430 +1,430 @@
1#include <uuid/uuid.h> 1#include <uuid/uuid.h>
2#include <iostream> 2#include <iostream>
3#include <cassert> 3#include <cassert>
4#include <stdexcept> 4#include <stdexcept>
5#include <string> 5#include <string>
6#include <set> 6#include <set>
7#include <iterator> 7#include <iterator>
8using namespace std; 8using namespace std;
9#include <kingate/exception.h> 9#include <kingate/exception.h>
10#include <kingate/plaincgi.h> 10#include <kingate/plaincgi.h>
11#include <kingate/cgi_gateway.h> 11#include <kingate/cgi_gateway.h>
12#include <opkele/exception.h> 12#include <opkele/exception.h>
13#include <opkele/types.h> 13#include <opkele/types.h>
14#include <opkele/util.h> 14#include <opkele/util.h>
15#include <opkele/uris.h> 15#include <opkele/uris.h>
16#include <opkele/discovery.h> 16#include <opkele/discovery.h>
17#include <opkele/association.h> 17#include <opkele/association.h>
18#include <opkele/sreg.h> 18#include <opkele/sreg.h>
19using namespace opkele; 19using namespace opkele;
20#include <opkele/prequeue_rp.h> 20#include <opkele/prequeue_rp.h>
21#include <opkele/debug.h> 21#include <opkele/debug.h>
22 22
23#include "sqlite.h" 23#include "sqlite.h"
24#include "kingate_openid_message.h" 24#include "kingate_openid_message.h"
25 25
26#undef DUMB_RP 26#undef DUMB_RP
27 27
28#ifdef DUMB_RP 28#ifdef DUMB_RP
29# define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb") 29# define DUMBTHROW throw opkele::dumb_RP(OPKELE_CP_ "This RP is dumb")
30#else 30#else
31# define DUMBTHROW (void)0 31# define DUMBTHROW (void)0
32#endif 32#endif
33 33
34class rpdb_t : public sqlite3_t { 34class rpdb_t : public sqlite3_t {
35 public: 35 public:
36 rpdb_t() 36 rpdb_t()
37 : sqlite3_t("/tmp/RP.db") { 37 : sqlite3_t("/tmp/RP.db") {
38 assert(_D); 38 assert(_D);
39 char **resp; int nrow,ncol; char *errm; 39 char **resp; int nrow,ncol; char *errm;
40 if(sqlite3_get_table( 40 if(sqlite3_get_table(
41 _D,"SELECT a_op FROM assoc LIMIT 0", 41 _D,"SELECT a_op FROM assoc LIMIT 0",
42 &resp,&nrow,&ncol,&errm)!=SQLITE_OK) { 42 &resp,&nrow,&ncol,&errm)!=SQLITE_OK) {
43 extern const char *__RP_db_bootstrap; 43 extern const char *__RP_db_bootstrap;
44 DOUT_("Bootstrapping DB"); 44 DOUT_("Bootstrapping DB");
45 if(sqlite3_exec(_D,__RP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK) 45 if(sqlite3_exec(_D,__RP_db_bootstrap,NULL,NULL,&errm)!=SQLITE_OK)
46 throw opkele::exception(OPKELE_CP_ string("Failed to bootstrap SQLite database: ")+errm); 46 throw opkele::exception(OPKELE_CP_ string("Failed to bootstrap SQLite database: ")+errm);
47 }else 47 }else
48 sqlite3_free_table(resp); 48 sqlite3_free_table(resp);
49 49
50 } 50 }
51}; 51};
52 52
53class example_rp_t : public opkele::prequeue_RP { 53class example_rp_t : public opkele::prequeue_RP {
54 public: 54 public:
55 mutable rpdb_t db; 55 mutable rpdb_t db;
56 kingate::cookie htc; 56 kingate::cookie htc;
57 long as_id; 57 long as_id;
58 int ordinal; 58 int ordinal;
59 kingate::cgi_gateway& gw; 59 kingate::cgi_gateway& gw;
60 60
61 example_rp_t(kingate::cgi_gateway& gw) 61 example_rp_t(kingate::cgi_gateway& g)
62 : ordinal(0), have_eqtop(false), gw(gw), as_id(-1) { 62 : as_id(-1), ordinal(0), gw(g), have_eqtop(false) {
63 try { 63 try {
64 htc = gw.cookies.get_cookie("ht_session"); 64 htc = gw.cookies.get_cookie("ht_session");
65 as_id = opkele::util::string_to_long(gw.get_param("asid")); 65 as_id = opkele::util::string_to_long(gw.get_param("asid"));
66 }catch(kingate::exception_notfound& kenf) { 66 }catch(kingate::exception_notfound& kenf) {
67 uuid_t uuid; uuid_generate(uuid); 67 uuid_t uuid; uuid_generate(uuid);
68 htc = kingate::cookie("ht_session",util::encode_base64(uuid,sizeof(uuid))); 68 htc = kingate::cookie("ht_session",util::encode_base64(uuid,sizeof(uuid)));
69 sqlite3_mem_t<char*> S = sqlite3_mprintf( 69 sqlite3_mem_t<char*> S = sqlite3_mprintf(
70 "INSERT INTO ht_sessions (hts_id) VALUES (%Q)", 70 "INSERT INTO ht_sessions (hts_id) VALUES (%Q)",
71 htc.get_value().c_str()); 71 htc.get_value().c_str());
72 db.exec(S); 72 db.exec(S);
73 } 73 }
74 } 74 }
75 75
76 /* Global persistent store */ 76 /* Global persistent store */
77 77
78 opkele::assoc_t store_assoc( 78 opkele::assoc_t store_assoc(
79 const string& OP,const string& handle, 79 const string& OP,const string& handle,
80 const string& type,const secret_t& secret, 80 const string& type,const secret_t& secret,
81 int expires_in) { 81 int expires_in) {
82 DUMBTHROW; 82 DUMBTHROW;
83 DOUT_("Storing '" << handle << "' assoc with '" << OP << "'"); 83 DOUT_("Storing '" << handle << "' assoc with '" << OP << "'");
84 time_t exp = time(0)+expires_in; 84 time_t exp = time(0)+expires_in;
85 sqlite3_mem_t<char*> 85 sqlite3_mem_t<char*>
86 S = sqlite3_mprintf( 86 S = sqlite3_mprintf(
87 "INSERT INTO assoc" 87 "INSERT INTO assoc"
88 " (a_op,a_handle,a_type,a_ctime,a_etime,a_secret)" 88 " (a_op,a_handle,a_type,a_ctime,a_etime,a_secret)"
89 " VALUES (" 89 " VALUES ("
90 " %Q,%Q,%Q," 90 " %Q,%Q,%Q,"
91 " datetime('now'), datetime('now','+%d seconds')," 91 " datetime('now'), datetime('now','+%d seconds'),"
92 " %Q" 92 " %Q"
93 " );", OP.c_str(), handle.c_str(), type.c_str(), 93 " );", OP.c_str(), handle.c_str(), type.c_str(),
94 expires_in, 94 expires_in,
95 util::encode_base64(&(secret.front()),secret.size()).c_str() ); 95 util::encode_base64(&(secret.front()),secret.size()).c_str() );
96 db.exec(S); 96 db.exec(S);
97 return opkele::assoc_t(new opkele::association( 97 return opkele::assoc_t(new opkele::association(
98 OP, handle, type, secret, exp, false )); 98 OP, handle, type, secret, exp, false ));
99 } 99 }
100 100
101 opkele::assoc_t find_assoc( 101 opkele::assoc_t find_assoc(
102 const string& OP) { 102 const string& OP) {
103 DUMBTHROW; 103 DUMBTHROW;
104 DOUT_("Looking for an assoc with '" << OP << '\''); 104 DOUT_("Looking for an assoc with '" << OP << '\'');
105 sqlite3_mem_t<char*> 105 sqlite3_mem_t<char*>
106 S = sqlite3_mprintf( 106 S = sqlite3_mprintf(
107 "SELECT" 107 "SELECT"
108 " a_op,a_handle,a_type,a_secret," 108 " a_op,a_handle,a_type,a_secret,"
109 " strftime('%%s',a_etime) AS a_etime" 109 " strftime('%%s',a_etime) AS a_etime"
110 " FROM assoc" 110 " FROM assoc"
111 " WHERE a_op=%Q AND a_itime IS NULL AND NOT a_stateless" 111 " WHERE a_op=%Q AND a_itime IS NULL AND NOT a_stateless"
112 " AND ( a_etime > datetime('now','-30 seconds') )" 112 " AND ( a_etime > datetime('now','-30 seconds') )"
113 " LIMIT 1", 113 " LIMIT 1",
114 OP.c_str()); 114 OP.c_str());
115 sqlite3_table_t T; 115 sqlite3_table_t T;
116 int nr,nc; 116 int nr,nc;
117 db.get_table(S,T,&nr,&nc); 117 db.get_table(S,T,&nr,&nc);
118 if(nr<1) 118 if(nr<1)
119 throw opkele::failed_lookup(OPKELE_CP_ "Couldn't find unexpired handle"); 119 throw opkele::failed_lookup(OPKELE_CP_ "Couldn't find unexpired handle");
120 assert(nr==1); 120 assert(nr==1);
121 assert(nc==5); 121 assert(nc==5);
122 secret_t secret; 122 secret_t secret;
123 util::decode_base64(T.get(1,3,nc),secret); 123 util::decode_base64(T.get(1,3,nc),secret);
124 DOUT_(" found '" << T.get(1,1,nc) << '\''); 124 DOUT_(" found '" << T.get(1,1,nc) << '\'');
125 return opkele::assoc_t(new opkele::association( 125 return opkele::assoc_t(new opkele::association(
126 T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), 126 T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc),
127 secret, strtol(T.get(1,4,nc),0,0), false )); 127 secret, strtol(T.get(1,4,nc),0,0), false ));
128 } 128 }
129 129
130 opkele::assoc_t retrieve_assoc( 130 opkele::assoc_t retrieve_assoc(
131 const string& OP,const string& handle) { 131 const string& OP,const string& handle) {
132 DUMBTHROW; 132 DUMBTHROW;
133 DOUT_("Retrieving assoc '" << handle << "' with '" << OP << '\''); 133 DOUT_("Retrieving assoc '" << handle << "' with '" << OP << '\'');
134 sqlite3_mem_t<char*> 134 sqlite3_mem_t<char*>
135 S = sqlite3_mprintf( 135 S = sqlite3_mprintf(
136 "SELECT" 136 "SELECT"
137 " a_op,a_handle,a_type,a_secret," 137 " a_op,a_handle,a_type,a_secret,"
138 " strftime('%%s',a_etime) AS a_etime" 138 " strftime('%%s',a_etime) AS a_etime"
139 " FROM assoc" 139 " FROM assoc"
140 " WHERE a_op=%Q AND a_handle=%Q" 140 " WHERE a_op=%Q AND a_handle=%Q"
141 " AND a_itime IS NULL AND NOT a_stateless" 141 " AND a_itime IS NULL AND NOT a_stateless"
142 " LIMIT 1", 142 " LIMIT 1",
143 OP.c_str(),handle.c_str()); 143 OP.c_str(),handle.c_str());
144 sqlite3_table_t T; 144 sqlite3_table_t T;
145 int nr,nc; 145 int nr,nc;
146 db.get_table(S,T,&nr,&nc); 146 db.get_table(S,T,&nr,&nc);
147 if(nr<1) 147 if(nr<1)
148 throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid association"); 148 throw opkele::failed_lookup(OPKELE_CP_ "couldn't retrieve valid association");
149 assert(nr==1); assert(nc==5); 149 assert(nr==1); assert(nc==5);
150 secret_t secret; util::decode_base64(T.get(1,3,nc),secret); 150 secret_t secret; util::decode_base64(T.get(1,3,nc),secret);
151 DOUT_(" found. type=" << T.get(1,2,nc) << '\''); 151 DOUT_(" found. type=" << T.get(1,2,nc) << '\'');
152 return opkele::assoc_t(new opkele::association( 152 return opkele::assoc_t(new opkele::association(
153 T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc), 153 T.get(1,0,nc), T.get(1,1,nc), T.get(1,2,nc),
154 secret, strtol(T.get(1,4,nc),0,0), false )); 154 secret, strtol(T.get(1,4,nc),0,0), false ));
155 } 155 }
156 156
157 void invalidate_assoc( 157 void invalidate_assoc(
158 const string& OP,const string& handle) { 158 const string& OP,const string& handle) {
159 DUMBTHROW; 159 DUMBTHROW;
160 DOUT_("Invalidating assoc '" << handle << "' with '" << OP << '\''); 160 DOUT_("Invalidating assoc '" << handle << "' with '" << OP << '\'');
161 sqlite3_mem_t<char*> 161 sqlite3_mem_t<char*>
162 S = sqlite3_mprintf( 162 S = sqlite3_mprintf(
163 "UPDATE assoc SET a_itime=datetime('now')" 163 "UPDATE assoc SET a_itime=datetime('now')"
164 " WHERE a_op=%Q AND a_handle=%Q", 164 " WHERE a_op=%Q AND a_handle=%Q",
165 OP.c_str(), handle.c_str() ); 165 OP.c_str(), handle.c_str() );
166 db.exec(S); 166 db.exec(S);
167 } 167 }
168 168
169 void check_nonce(const string& OP,const string& nonce) { 169 void check_nonce(const string& OP,const string& nonce) {
170 DOUT_("Checking nonce '" << nonce << "' from '" << OP << '\''); 170 DOUT_("Checking nonce '" << nonce << "' from '" << OP << '\'');
171 sqlite3_mem_t<char*> 171 sqlite3_mem_t<char*>
172 S = sqlite3_mprintf( 172 S = sqlite3_mprintf(
173 "SELECT 1 FROM nonces WHERE n_op=%Q AND n_once=%Q", 173 "SELECT 1 FROM nonces WHERE n_op=%Q AND n_once=%Q",
174 OP.c_str(), nonce.c_str()); 174 OP.c_str(), nonce.c_str());
175 sqlite3_table_t T; 175 sqlite3_table_t T;
176 int nr,nc; 176 int nr,nc;
177 db.get_table(S,T,&nr,&nc); 177 db.get_table(S,T,&nr,&nc);
178 if(nr) 178 if(nr)
179 throw opkele::id_res_bad_nonce(OPKELE_CP_ "already seen that nonce"); 179 throw opkele::id_res_bad_nonce(OPKELE_CP_ "already seen that nonce");
180 sqlite3_mem_t<char*> 180 sqlite3_mem_t<char*>
181 SS = sqlite3_mprintf( 181 SS = sqlite3_mprintf(
182 "INSERT INTO nonces (n_op,n_once) VALUES (%Q,%Q)", 182 "INSERT INTO nonces (n_op,n_once) VALUES (%Q,%Q)",
183 OP.c_str(), nonce.c_str()); 183 OP.c_str(), nonce.c_str());
184 db.exec(SS); 184 db.exec(SS);
185 } 185 }
186 186
187 /* Session perisistent store */ 187 /* Session perisistent store */
188 188
189 void begin_queueing() { 189 void begin_queueing() {
190 assert(as_id>=0); 190 assert(as_id>=0);
191 DOUT_("Resetting queue for session '" << htc.get_value() << "'/" << as_id); 191 DOUT_("Resetting queue for session '" << htc.get_value() << "'/" << as_id);
192 sqlite3_mem_t<char*> S = sqlite3_mprintf( 192 sqlite3_mem_t<char*> S = sqlite3_mprintf(
193 "DELETE FROM endpoints_queue" 193 "DELETE FROM endpoints_queue"
194 " WHERE as_id=%ld", 194 " WHERE as_id=%ld",
195 as_id); 195 as_id);
196 db.exec(S); 196 db.exec(S);
197 } 197 }
198 198
199 void queue_endpoint(const opkele::openid_endpoint_t& ep) { 199 void queue_endpoint(const opkele::openid_endpoint_t& ep) {
200 assert(as_id>=0); 200 assert(as_id>=0);
201 DOUT_("Queueing endpoint " << ep.claimed_id << " : " << ep.local_id << " @ " << ep.uri); 201 DOUT_("Queueing endpoint " << ep.claimed_id << " : " << ep.local_id << " @ " << ep.uri);
202 sqlite3_mem_t<char*> S = sqlite3_mprintf( 202 sqlite3_mem_t<char*> S = sqlite3_mprintf(
203 "INSERT INTO endpoints_queue" 203 "INSERT INTO endpoints_queue"
204 " (as_id,eq_ctime,eq_ordinal,eq_uri,eq_claimed_id,eq_local_id)" 204 " (as_id,eq_ctime,eq_ordinal,eq_uri,eq_claimed_id,eq_local_id)"
205 " VALUES (%ld,strftime('%%s','now'),%d,%Q,%Q,%Q)", 205 " VALUES (%ld,strftime('%%s','now'),%d,%Q,%Q,%Q)",
206 as_id,ordinal++, 206 as_id,ordinal++,
207 ep.uri.c_str(),ep.claimed_id.c_str(),ep.local_id.c_str()); 207 ep.uri.c_str(),ep.claimed_id.c_str(),ep.local_id.c_str());
208 db.exec(S); 208 db.exec(S);
209 } 209 }
210 210
211 mutable openid_endpoint_t eqtop; 211 mutable openid_endpoint_t eqtop;
212 mutable bool have_eqtop; 212 mutable bool have_eqtop;
213 213
214 const openid_endpoint_t& get_endpoint() const { 214 const openid_endpoint_t& get_endpoint() const {
215 assert(as_id>=0); 215 assert(as_id>=0);
216 if(!have_eqtop) { 216 if(!have_eqtop) {
217 sqlite3_mem_t<char*> 217 sqlite3_mem_t<char*>
218 S = sqlite3_mprintf( 218 S = sqlite3_mprintf(
219 "SELECT" 219 "SELECT"
220 " eq_uri, eq_claimed_id, eq_local_id" 220 " eq_uri, eq_claimed_id, eq_local_id"
221 " FROM endpoints_queue" 221 " FROM endpoints_queue"
222 " JOIN auth_sessions USING(as_id)" 222 " JOIN auth_sessions USING(as_id)"
223 " WHERE hts_id=%Q AND as_id=%ld" 223 " WHERE hts_id=%Q AND as_id=%ld"
224 " ORDER BY eq_ctime,eq_ordinal" 224 " ORDER BY eq_ctime,eq_ordinal"
225 " LIMIT 1",htc.get_value().c_str(),as_id); 225 " LIMIT 1",htc.get_value().c_str(),as_id);
226 sqlite3_table_t T; int nr,nc; 226 sqlite3_table_t T; int nr,nc;
227 db.get_table(S,T,&nr,&nc); 227 db.get_table(S,T,&nr,&nc);
228 if(nr<1) 228 if(nr<1)
229 throw opkele::exception(OPKELE_CP_ "No more endpoints queued"); 229 throw opkele::exception(OPKELE_CP_ "No more endpoints queued");
230 assert(nr==1); assert(nc==3); 230 assert(nr==1); assert(nc==3);
231 eqtop.uri = T.get(1,0,nc); 231 eqtop.uri = T.get(1,0,nc);
232 eqtop.claimed_id = T.get(1,1,nc); 232 eqtop.claimed_id = T.get(1,1,nc);
233 eqtop.local_id = T.get(1,2,nc); 233 eqtop.local_id = T.get(1,2,nc);
234 have_eqtop = true; 234 have_eqtop = true;
235 } 235 }
236 return eqtop; 236 return eqtop;
237 } 237 }
238 238
239 void next_endpoint() { 239 void next_endpoint() {
240 assert(as_id>=0); 240 assert(as_id>=0);
241 get_endpoint(); 241 get_endpoint();
242 have_eqtop = false; 242 have_eqtop = false;
243 sqlite3_mem_t<char*> S = sqlite3_mprintf( 243 sqlite3_mem_t<char*> S = sqlite3_mprintf(
244 "DELETE FROM endpoints_queue" 244 "DELETE FROM endpoints_queue"
245 " WHERE as_id=%ld AND eq_uri=%Q AND eq_local_id=%Q", 245 " WHERE as_id=%ld AND eq_uri=%Q AND eq_local_id=%Q",
246 htc.get_value().c_str(),as_id, 246 htc.get_value().c_str(),as_id,
247 eqtop.uri.c_str()); 247 eqtop.uri.c_str());
248 db.exec(S); 248 db.exec(S);
249 } 249 }
250 250
251 mutable string _cid; 251 mutable string _cid;
252 mutable string _nid; 252 mutable string _nid;
253 253
254 void set_claimed_id(const string& cid) { 254 void set_claimed_id(const string& cid) {
255 assert(as_id>=0); 255 assert(as_id>=0);
256 sqlite3_mem_t<char*> S = sqlite3_mprintf( 256 sqlite3_mem_t<char*> S = sqlite3_mprintf(
257 "UPDATE auth_sessions" 257 "UPDATE auth_sessions"
258 " SET as_claimed_id=%Q" 258 " SET as_claimed_id=%Q"
259 " WHERE hts_id=%Q and as_id=%ld", 259 " WHERE hts_id=%Q and as_id=%ld",
260 cid.c_str(), 260 cid.c_str(),
261 htc.get_value().c_str(),as_id); 261 htc.get_value().c_str(),as_id);
262 db.exec(S); 262 db.exec(S);
263 _cid = cid; 263 _cid = cid;
264 } 264 }
265 const string get_claimed_id() const { 265 const string get_claimed_id() const {
266 assert(as_id>=0); 266 assert(as_id>=0);
267 if(_cid.empty()) { 267 if(_cid.empty()) {
268 sqlite3_mem_t<char*> S = sqlite3_mprintf( 268 sqlite3_mem_t<char*> S = sqlite3_mprintf(
269 "SELECT as_claimed_id" 269 "SELECT as_claimed_id"
270 " FROM" 270 " FROM"
271 " auth_sessions" 271 " auth_sessions"
272 " WHERE" 272 " WHERE"
273 " hts_id=%Q AND as_id=%ld", 273 " hts_id=%Q AND as_id=%ld",
274 htc.get_value().c_str(),as_id); 274 htc.get_value().c_str(),as_id);
275 sqlite3_table_t T; int nr,nc; 275 sqlite3_table_t T; int nr,nc;
276 db.get_table(S,T,&nr,&nc); 276 db.get_table(S,T,&nr,&nc);
277 assert(nr==1); assert(nc==1); 277 assert(nr==1); assert(nc==1);
278 _cid = T.get(1,0,nc); 278 _cid = T.get(1,0,nc);
279 } 279 }
280 return _cid; 280 return _cid;
281 } 281 }
282 void set_normalized_id(const string& nid) { 282 void set_normalized_id(const string& nid) {
283 assert(as_id>=0); 283 assert(as_id>=0);
284 sqlite3_mem_t<char*> S = sqlite3_mprintf( 284 sqlite3_mem_t<char*> S = sqlite3_mprintf(
285 "UPDATE auth_sessions" 285 "UPDATE auth_sessions"
286 " SET as_normalized_id=%Q" 286 " SET as_normalized_id=%Q"
287 " WHERE hts_id=%Q and as_id=%ld", 287 " WHERE hts_id=%Q and as_id=%ld",
288 nid.c_str(), 288 nid.c_str(),
289 htc.get_value().c_str(),as_id); 289 htc.get_value().c_str(),as_id);
290 db.exec(S); 290 db.exec(S);
291 _nid = nid; 291 _nid = nid;
292 } 292 }
293 const string get_normalized_id() const { 293 const string get_normalized_id() const {
294 assert(as_id>=0); 294 assert(as_id>=0);
295 if(_nid.empty()) { 295 if(_nid.empty()) {
296 sqlite3_mem_t<char*> S = sqlite3_mprintf( 296 sqlite3_mem_t<char*> S = sqlite3_mprintf(
297 "SELECT as_normalized_id" 297 "SELECT as_normalized_id"
298 " FROM" 298 " FROM"
299 " auth_sessions" 299 " auth_sessions"
300 " WHERE" 300 " WHERE"
301 " hts_id=%Q AND as_id=%ld", 301 " hts_id=%Q AND as_id=%ld",
302 htc.get_value().c_str(),as_id); 302 htc.get_value().c_str(),as_id);
303 sqlite3_table_t T; int nr,nc; 303 sqlite3_table_t T; int nr,nc;
304 db.get_table(S,T,&nr,&nc); 304 db.get_table(S,T,&nr,&nc);
305 assert(nr==1); assert(nc==1); 305 assert(nr==1); assert(nc==1);
306 _nid = T.get(1,0,nc); 306 _nid = T.get(1,0,nc);
307 } 307 }
308 return _nid; 308 return _nid;
309 } 309 }
310 310
311 const string get_this_url() const { 311 const string get_this_url() const {
312 bool s = gw.has_meta("SSL_PROTOCOL_VERSION"); 312 bool s = gw.has_meta("SSL_PROTOCOL_VERSION");
313 string rv = s?"https://":"http://"; 313 string rv = s?"https://":"http://";
314 rv += gw.http_request_header("Host"); 314 rv += gw.http_request_header("Host");
315 const string& port = gw.get_meta("SERVER_PORT"); 315 const string& port = gw.get_meta("SERVER_PORT");
316 if( port!=(s?"443":"80") ) { 316 if( port!=(s?"443":"80") ) {
317 rv += ':'; rv += port; 317 rv += ':'; rv += port;
318 } 318 }
319 rv += gw.get_meta("REQUEST_URI"); 319 rv += gw.get_meta("REQUEST_URI");
320 return rv; 320 return rv;
321 } 321 }
322 322
323 void initiate(const string& usi) { 323 void initiate(const string& usi) {
324 allocate_asid(); 324 allocate_asid();
325 prequeue_RP::initiate(usi); 325 prequeue_RP::initiate(usi);
326 } 326 }
327 327
328 string get_self_url() const { 328 string get_self_url() const {
329 string rv = get_this_url(); 329 string rv = get_this_url();
330 string::size_type q = rv.find('?'); 330 string::size_type q = rv.find('?');
331 if(q!=string::npos) 331 if(q!=string::npos)
332 rv.erase(q); 332 rv.erase(q);
333 return rv; 333 return rv;
334 } 334 }
335 335
336 void allocate_asid() { 336 void allocate_asid() {
337 sqlite3_mem_t<char*> S = sqlite3_mprintf( 337 sqlite3_mem_t<char*> S = sqlite3_mprintf(
338 "INSERT INTO auth_sessions (hts_id)" 338 "INSERT INTO auth_sessions (hts_id)"
339 " VALUES (%Q)", 339 " VALUES (%Q)",
340 htc.get_value().c_str()); 340 htc.get_value().c_str());
341 db.exec(S); 341 db.exec(S);
342 as_id = sqlite3_last_insert_rowid(db); 342 as_id = sqlite3_last_insert_rowid(db);
343 DOUT_("Allocated authentication session id "<<as_id); 343 DOUT_("Allocated authentication session id "<<as_id);
344 assert(as_id>=0); 344 assert(as_id>=0);
345 } 345 }
346 346
347#ifdef DUMB_RP 347#ifdef DUMB_RP
348 virtual assoc_t associate(const string& OP) { 348 virtual assoc_t associate(const string& OP) {
349 DUMBTHROW; 349 DUMBTHROW;
350 } 350 }
351#endif 351#endif
352}; 352};
353 353
354int main(int argc,char *argv[]) { 354int main(int,char **) {
355 try { 355 try {
356 kingate::plaincgi_interface ci; 356 kingate::plaincgi_interface ci;
357 kingate::cgi_gateway gw(ci); 357 kingate::cgi_gateway gw(ci);
358 string op; 358 string op;
359 try { op = gw.get_param("op"); }catch(kingate::exception_notfound&) { } 359 try { op = gw.get_param("op"); }catch(kingate::exception_notfound&) { }
360 if(op=="initiate") { 360 if(op=="initiate") {
361 example_rp_t rp(gw); 361 example_rp_t rp(gw);
362 string usi = gw.get_param("openid_identity"); 362 string usi = gw.get_param("openid_identity");
363 rp.initiate(usi); 363 rp.initiate(usi);
364 opkele::sreg_t sreg(opkele::sreg_t::fields_NONE,opkele::sreg_t::fields_ALL); 364 opkele::sreg_t sreg(opkele::sreg_t::fields_NONE,opkele::sreg_t::fields_ALL);
365 opkele::openid_message_t cm; 365 opkele::openid_message_t cm;
366 string loc; 366 string loc;
367 cout << 367 cout <<
368 "Set-Cookie: " << rp.htc.set_cookie_header() << "\n" 368 "Set-Cookie: " << rp.htc.set_cookie_header() << "\n"
369 "Status: 302 Going to OP\n" 369 "Status: 302 Going to OP\n"
370 "Location: " << ( 370 "Location: " << (
371 loc = rp.checkid_(cm,opkele::mode_checkid_setup, 371 loc = rp.checkid_(cm,opkele::mode_checkid_setup,
372 rp.get_self_url()+ 372 rp.get_self_url()+
373 "?op=confirm&asid="+opkele::util::long_to_string(rp.as_id), 373 "?op=confirm&asid="+opkele::util::long_to_string(rp.as_id),
374 rp.get_self_url(),&sreg).append_query(rp.get_endpoint().uri) 374 rp.get_self_url(),&sreg).append_query(rp.get_endpoint().uri)
375 ) 375 )
376 << "\n\n"; 376 << "\n\n";
377 DOUT_("Going to " << loc); 377 DOUT_("Going to " << loc);
378 }else if(op=="confirm") { 378 }else if(op=="confirm") {
379 kingate_openid_message_t om(gw); 379 kingate_openid_message_t om(gw);
380 example_rp_t rp(gw); 380 example_rp_t rp(gw);
381 opkele::sreg_t sreg(opkele::sreg_t::fields_NONE,opkele::sreg_t::fields_ALL); 381 opkele::sreg_t sreg(opkele::sreg_t::fields_NONE,opkele::sreg_t::fields_ALL);
382 rp.id_res(om,&sreg); 382 rp.id_res(om,&sreg);
383 cout << 383 cout <<
384 "Content-Type: text/plain\n\n"; 384 "Content-Type: text/plain\n\n";
385 for(opkele::basic_openid_message::fields_iterator i=om.fields_begin(); 385 for(opkele::basic_openid_message::fields_iterator i=om.fields_begin();
386 i!=om.fields_end();++i) { 386 i!=om.fields_end();++i) {
387 cout << *i << '=' << om.get_field(*i) << endl; 387 cout << *i << '=' << om.get_field(*i) << endl;
388 } 388 }
389 cout << endl 389 cout << endl
390 << "SREG fields: " << sreg.has_fields << endl; 390 << "SREG fields: " << sreg.has_fields << endl;
391 }else{ 391 }else{
392 cout << 392 cout <<
393 "Content-type: text/html\n\n" 393 "Content-type: text/html\n\n"
394 394
395 "<html>" 395 "<html>"
396 "<head><title>test RP</title></head>" 396 "<head><title>test RP</title></head>"
397 "<body>" 397 "<body>"
398 "<form action='' method='post'>" 398 "<form action='' method='post'>"
399 "<input type='hidden' name='op' value='initiate' />" 399 "<input type='hidden' name='op' value='initiate' />"
400 "<input type='text' name='openid_identity'/>" 400 "<input type='text' name='openid_identity'/>"
401 "<input type='submit' name='submit' value='submit' />" 401 "<input type='submit' name='submit' value='submit' />"
402 "</form>" 402 "</form>"
403 "<br/><br/>" 403 "<br/><br/>"
404 "<a href='?op=initiate&amp;openid_identity=www.myopenid.com&amp;dummy=" << time(0) << "'>login with myopenid.com account</a>" 404 "<a href='?op=initiate&amp;openid_identity=www.myopenid.com&amp;dummy=" << time(0) << "'>login with myopenid.com account</a>"
405 "<br/>" 405 "<br/>"
406 "</body" 406 "</body"
407 "</html>" 407 "</html>"
408 ; 408 ;
409 } 409 }
410#ifdef OPKELE_HAVE_KONFORKA 410#ifdef OPKELE_HAVE_KONFORKA
411 }catch(konforka::exception& e) { 411 }catch(konforka::exception& e) {
412#else 412#else
413 }catch(std::exception& e){ 413 }catch(std::exception& e){
414#endif 414#endif
415 DOUT_("Oops: " << e.what()); 415 DOUT_("Oops: " << e.what());
416 cout << "Content-Type: text/plain\n\n" 416 cout << "Content-Type: text/plain\n\n"
417 "Exception:\n" 417 "Exception:\n"
418 " what: " << e.what() << endl; 418 " what: " << e.what() << endl;
419#ifdef OPKELE_HAVE_KONFORKA 419#ifdef OPKELE_HAVE_KONFORKA
420 cout << " where: " << e.where() << endl; 420 cout << " where: " << e.where() << endl;
421 if(!e._seen.empty()) { 421 if(!e._seen.empty()) {
422 cout << " seen:" << endl; 422 cout << " seen:" << endl;
423 for(list<konforka::code_point>::const_iterator 423 for(list<konforka::code_point>::const_iterator
424 i=e._seen.begin();i!=e._seen.end();++i) { 424 i=e._seen.begin();i!=e._seen.end();++i) {
425 cout << " " << i->c_str() << endl; 425 cout << " " << i->c_str() << endl;
426 } 426 }
427 } 427 }
428#endif 428#endif
429 } 429 }
430} 430}
diff --git a/test/kingate_openid_message.h b/test/kingate_openid_message.h
index 37dcdfa..7029ff7 100644
--- a/test/kingate_openid_message.h
+++ b/test/kingate_openid_message.h
@@ -1,109 +1,109 @@
1template<typename IT> 1template<typename IT>
2class join_iterator : public iterator< 2class join_iterator : public iterator<
3 input_iterator_tag,typename IT::value_type, 3 input_iterator_tag,typename IT::value_type,
4 void,typename IT::pointer,typename IT::reference> { 4 void,typename IT::pointer,typename IT::reference> {
5 public: 5 public:
6 typedef pair<IT,IT> range_t; 6 typedef pair<IT,IT> range_t;
7 typedef list<range_t> ranges_t; 7 typedef list<range_t> ranges_t;
8 ranges_t ranges; 8 ranges_t ranges;
9 9
10 join_iterator() { } 10 join_iterator() { }
11 11
12 bool cleanup() { 12 bool cleanup() {
13 bool rv = false; 13 bool rv = false;
14 while(!(ranges.empty() || ranges.front().first!=ranges.front().second)) { 14 while(!(ranges.empty() || ranges.front().first!=ranges.front().second)) {
15 ranges.pop_front(); rv = true; 15 ranges.pop_front(); rv = true;
16 } 16 }
17 return rv; 17 return rv;
18 } 18 }
19 19
20 join_iterator<IT>& add_range(const IT& b,const IT& e) { 20 join_iterator<IT>& add_range(const IT& b,const IT& e) {
21 ranges.push_back(typename ranges_t::value_type(b,e)); 21 ranges.push_back(typename ranges_t::value_type(b,e));
22 cleanup(); 22 cleanup();
23 return *this; 23 return *this;
24 } 24 }
25 25
26 bool operator==(const join_iterator<IT>& x) const { 26 bool operator==(const join_iterator<IT>& x) const {
27 return ranges==x.ranges; } 27 return ranges==x.ranges; }
28 bool operator!=(const join_iterator<IT>& x) const { 28 bool operator!=(const join_iterator<IT>& x) const {
29 return ranges!=x.ranges; } 29 return ranges!=x.ranges; }
30 30
31 typename IT::reference operator*() const { 31 typename IT::reference operator*() const {
32 assert(!ranges.empty()); 32 assert(!ranges.empty());
33 assert(ranges.front().first!=ranges.front().second); 33 assert(ranges.front().first!=ranges.front().second);
34 return *ranges.front().first; } 34 return *ranges.front().first; }
35 typename IT::pointer operator->() const { 35 typename IT::pointer operator->() const {
36 assert(!ranges.empty()); 36 assert(!ranges.empty());
37 assert(ranges.front().first!=ranges.front().second); 37 assert(ranges.front().first!=ranges.front().second);
38 return ranges.front().first.operator->(); } 38 return ranges.front().first.operator->(); }
39 39
40 join_iterator<IT>& operator++() { 40 join_iterator<IT>& operator++() {
41 cleanup(); 41 cleanup();
42 if(ranges.empty()) return *this; 42 if(ranges.empty()) return *this;
43 do { 43 do {
44 ++ranges.front().first; 44 ++ranges.front().first;
45 }while(cleanup() && !ranges.empty()); 45 }while(cleanup() && !ranges.empty());
46 return *this; 46 return *this;
47 } 47 }
48 join_iterator<IT> operator++(int) { 48 join_iterator<IT> operator++(int) {
49 join_iterator<IT> rv(*this); 49 join_iterator<IT> rv(*this);
50 ++(*this); return rv; } 50 ++(*this); return rv; }
51}; 51};
52 52
53template<typename IT> 53template<typename IT>
54class cut_prefix_filterator : public opkele::util::basic_filterator<IT> { 54class cut_prefix_filterator : public opkele::util::basic_filterator<IT> {
55 public: 55 public:
56 string pfx; 56 string pfx;
57 mutable string tmp; 57 mutable string tmp;
58 58
59 cut_prefix_filterator() { } 59 cut_prefix_filterator() { }
60 cut_prefix_filterator(const IT& bi,const IT&ei,const string& pfx) 60 cut_prefix_filterator(const IT& _bi,const IT&_ei,const string& p)
61 : opkele::util::basic_filterator<IT>(bi,ei), pfx(pfx) { 61 : opkele::util::basic_filterator<IT>(_bi,_ei), pfx(p) {
62 this->prepare(); 62 this->prepare();
63 } 63 }
64 64
65 bool is_interesting() const { 65 bool is_interesting() const {
66 return pfx.length()==0 || !strncmp(this->it->c_str(),pfx.c_str(),pfx.length()); 66 return pfx.length()==0 || !strncmp(this->it->c_str(),pfx.c_str(),pfx.length());
67 } 67 }
68 68
69 typename IT::reference operator*() const { 69 typename IT::reference operator*() const {
70 assert(!this->empty); 70 assert(!this->empty);
71 tmp = *this->it; tmp.erase(0,pfx.length()); 71 tmp = *this->it; tmp.erase(0,pfx.length());
72 return tmp; } 72 return tmp; }
73 typename IT::pointer operator->() const { 73 typename IT::pointer operator->() const {
74 assert(!this->empty); 74 assert(!this->empty);
75 return &this->operator*(); } 75 return &this->operator*(); }
76}; 76};
77 77
78class kingate_openid_message_t : public opkele::basic_openid_message { 78class kingate_openid_message_t : public opkele::basic_openid_message {
79 typedef join_iterator<kingate::cgi_gateway::params_t::const_iterator> jitterator; 79 typedef join_iterator<kingate::cgi_gateway::params_t::const_iterator> jitterator;
80 typedef opkele::util::map_keys_iterator< 80 typedef opkele::util::map_keys_iterator<
81 jitterator, 81 jitterator,
82 fields_iterator::value_type, 82 fields_iterator::value_type,
83 fields_iterator::reference, 83 fields_iterator::reference,
84 fields_iterator::pointer> keys_iterator; 84 fields_iterator::pointer> keys_iterator;
85 typedef cut_prefix_filterator<keys_iterator> pfilterator; 85 typedef cut_prefix_filterator<keys_iterator> pfilterator;
86 public: 86 public:
87 const kingate::cgi_gateway& gw; 87 const kingate::cgi_gateway& gw;
88 88
89 kingate_openid_message_t(const kingate::cgi_gateway& g) : gw(g) { } 89 kingate_openid_message_t(const kingate::cgi_gateway& g) : gw(g) { }
90 90
91 bool has_field(const string& n) const { 91 bool has_field(const string& n) const {
92 return gw.has_param("openid."+n); } 92 return gw.has_param("openid."+n); }
93 const string& get_field(const string& n) const try { 93 const string& get_field(const string& n) const try {
94 return gw.get_param("openid."+n); }catch(kingate::exception_notfound& nf) { 94 return gw.get_param("openid."+n); }catch(kingate::exception_notfound& nf) {
95 throw opkele::failed_lookup(OPKELE_CP_ nf.what()); } 95 throw opkele::failed_lookup(OPKELE_CP_ nf.what()); }
96 96
97 fields_iterator fields_begin() const { 97 fields_iterator fields_begin() const {
98 return 98 return
99 pfilterator( keys_iterator( 99 pfilterator( keys_iterator(
100 jitterator() 100 jitterator()
101 .add_range( gw.get.begin(), gw.get.end() ) 101 .add_range( gw.get.begin(), gw.get.end() )
102 .add_range( gw.post.begin(), gw.post.end() ), 102 .add_range( gw.post.begin(), gw.post.end() ),
103 jitterator() 103 jitterator()
104 ), keys_iterator(), "openid." ); 104 ), keys_iterator(), "openid." );
105 } 105 }
106 fields_iterator fields_end() const { 106 fields_iterator fields_end() const {
107 return pfilterator(); 107 return pfilterator();
108 } 108 }
109}; 109};