-rw-r--r-- | include/opkele/basic_op.h | 2 | ||||
-rw-r--r-- | include/opkele/expat.h | 16 | ||||
-rw-r--r-- | include/opkele/iterator.h | 19 | ||||
-rw-r--r-- | include/opkele/types.h | 1 | ||||
-rw-r--r-- | lib/basic_op.cc | 29 | ||||
-rw-r--r-- | lib/basic_rp.cc | 10 | ||||
-rw-r--r-- | lib/discovery.cc | 2 | ||||
-rw-r--r-- | lib/expat.cc | 1 | ||||
-rw-r--r-- | lib/extension.cc | 2 | ||||
-rw-r--r-- | lib/openid_message.cc | 32 | ||||
-rw-r--r-- | lib/prequeue_rp.cc | 4 | ||||
-rw-r--r-- | lib/sreg.cc | 6 | ||||
-rw-r--r-- | lib/verify_op.cc | 4 | ||||
-rw-r--r-- | test/OP.cc | 16 | ||||
-rw-r--r-- | test/RP.cc | 6 | ||||
-rw-r--r-- | test/kingate_openid_message.h | 4 |
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 | ||
8 | namespace opkele { | 8 | namespace 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 | ||
7 | namespace opkele { | 7 | namespace 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 | ||
7 | namespace opkele { | 7 | namespace 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 | ||
19 | namespace opkele { | 19 | namespace 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 | ||
11 | namespace opkele { | 11 | namespace 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 | ||
10 | namespace opkele { | 11 | namespace 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 | ||
3 | namespace opkele { | 3 | namespace 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 | ||
4 | namespace opkele { | 4 | namespace 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 | ||
9 | namespace opkele { | 9 | namespace 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 | ||
13 | namespace opkele { | 13 | namespace 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 | ||
6 | namespace opkele { | 6 | namespace 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 | ||
7 | namespace opkele { | 7 | namespace 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 | } |
@@ -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> |
6 | using namespace std; | 6 | using 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 | ||
22 | static const string get_self_url(const kingate::cgi_gateway& gw) { | 22 | static 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 | ||
37 | class opdb_t : public sqlite3_t { | 37 | class 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 | ||
55 | class example_op_t : public opkele::verify_OP { | 55 | class 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 | ||
203 | int main(int argc,char *argv[]) { | 203 | int 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 | } |
@@ -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> |
8 | using namespace std; | 8 | using 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> |
19 | using namespace opkele; | 19 | using 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 | ||
34 | class rpdb_t : public sqlite3_t { | 34 | class 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 | ||
53 | class example_rp_t : public opkele::prequeue_RP { | 53 | class 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 | ||
354 | int main(int argc,char *argv[]) { | 354 | int 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&openid_identity=www.myopenid.com&dummy=" << time(0) << "'>login with myopenid.com account</a>" | 404 | "<a href='?op=initiate&openid_identity=www.myopenid.com&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 @@ | |||
1 | template<typename IT> | 1 | template<typename IT> |
2 | class join_iterator : public iterator< | 2 | class 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 | ||
53 | template<typename IT> | 53 | template<typename IT> |
54 | class cut_prefix_filterator : public opkele::util::basic_filterator<IT> { | 54 | class 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 | ||
78 | class kingate_openid_message_t : public opkele::basic_openid_message { | 78 | class 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 | }; |