summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--include/opkele/util.h18
-rw-r--r--lib/basic_rp.cc21
2 files changed, 20 insertions, 19 deletions
diff --git a/include/opkele/util.h b/include/opkele/util.h
index e9176b0..6f3ddf6 100644
--- a/include/opkele/util.h
+++ b/include/opkele/util.h
@@ -51,101 +51,119 @@ namespace opkele {
51 operator const DH*(void) const { return _dh; } 51 operator const DH*(void) const { return _dh; }
52 operator DH*(void) { return _dh; } 52 operator DH*(void) { return _dh; }
53 53
54 DH* operator->() { return _dh; } 54 DH* operator->() { return _dh; }
55 const DH* operator->() const { return _dh; } 55 const DH* operator->() const { return _dh; }
56 }; 56 };
57 57
58 /** 58 /**
59 * Convert base64-encoded SSL BIGNUM to internal representation. 59 * Convert base64-encoded SSL BIGNUM to internal representation.
60 * @param b64 base64-encoded number 60 * @param b64 base64-encoded number
61 * @return SSL BIGNUM 61 * @return SSL BIGNUM
62 * @throw failed_conversion in case of error 62 * @throw failed_conversion in case of error
63 */ 63 */
64 BIGNUM *base64_to_bignum(const string& b64); 64 BIGNUM *base64_to_bignum(const string& b64);
65 /** 65 /**
66 * Convert decimal representation to SSL BIGNUM. 66 * Convert decimal representation to SSL BIGNUM.
67 * @param dec decimal representation 67 * @param dec decimal representation
68 * @return resulting BIGNUM 68 * @return resulting BIGNUM
69 * @throw failed_conversion in case of error 69 * @throw failed_conversion in case of error
70 */ 70 */
71 BIGNUM *dec_to_bignum(const string& dec); 71 BIGNUM *dec_to_bignum(const string& dec);
72 /** 72 /**
73 * Convert SSL BIGNUM data to base64 encoded string. 73 * Convert SSL BIGNUM data to base64 encoded string.
74 * @param bn BIGNUM 74 * @param bn BIGNUM
75 * @return base64encoded string 75 * @return base64encoded string
76 */ 76 */
77 string bignum_to_base64(const BIGNUM *bn); 77 string bignum_to_base64(const BIGNUM *bn);
78 78
79 /** 79 /**
80 * Convert internal time representation to w3c format 80 * Convert internal time representation to w3c format
81 * @param t internal representation 81 * @param t internal representation
82 * @return w3c time 82 * @return w3c time
83 * @throw failed_conversion in case of error 83 * @throw failed_conversion in case of error
84 */ 84 */
85 string time_to_w3c(time_t t); 85 string time_to_w3c(time_t t);
86 /** 86 /**
87 * Convert W3C time representation to internal time_t 87 * Convert W3C time representation to internal time_t
88 * @param w w3c representation 88 * @param w w3c representation
89 * @return converted time 89 * @return converted time
90 * @throw failed_conversion in case of error 90 * @throw failed_conversion in case of error
91 */ 91 */
92 time_t w3c_to_time(const string& w); 92 time_t w3c_to_time(const string& w);
93 93
94 /** 94 /**
95 * Encode string to the representation suitable for using in URL. 95 * Encode string to the representation suitable for using in URL.
96 * @param str string to encode 96 * @param str string to encode
97 * @return encoded string 97 * @return encoded string
98 * @throw failed_conversion in case of failure 98 * @throw failed_conversion in case of failure
99 */ 99 */
100 string url_encode(const string& str); 100 string url_encode(const string& str);
101 101
102 /** 102 /**
103 * Convert number to string 103 * Convert number to string
104 * @param l number 104 * @param l number
105 * @return string representation 105 * @return string representation
106 * @throw failed_conversion in case of failure 106 * @throw failed_conversion in case of failure
107 */ 107 */
108 string long_to_string(long l); 108 string long_to_string(long l);
109 /** 109 /**
110 * Convert string to number 110 * Convert string to number
111 * @param s string, containing the number 111 * @param s string, containing the number
112 * @return the number 112 * @return the number
113 * @throw failed_conversion in case of failure 113 * @throw failed_conversion in case of failure
114 */ 114 */
115 long string_to_long(const string& s); 115 long string_to_long(const string& s);
116 116
117 /** 117 /**
118 * Encode binary data using base64. 118 * Encode binary data using base64.
119 * @param data pointer to binary data 119 * @param data pointer to binary data
120 * @param length length of data 120 * @param length length of data
121 * @return encoded data 121 * @return encoded data
122 */ 122 */
123 string encode_base64(const void *data,size_t length); 123 string encode_base64(const void *data,size_t length);
124 /** 124 /**
125 * Decode binary data from base64 representation. 125 * Decode binary data from base64 representation.
126 * @param data base64-encoded data 126 * @param data base64-encoded data
127 * @param rv container for decoded binary 127 * @param rv container for decoded binary
128 */ 128 */
129 void decode_base64(const string& data,vector<unsigned char>& rv); 129 void decode_base64(const string& data,vector<unsigned char>& rv);
130 130
131 /** 131 /**
132 * Normalize http(s) URI according to RFC3986, section 6. URI is 132 * Normalize http(s) URI according to RFC3986, section 6. URI is
133 * expected to have scheme: in front of it. 133 * expected to have scheme: in front of it.
134 * @param uri URI 134 * @param uri URI
135 * @return normalized URI 135 * @return normalized URI
136 * @throw not_implemented in case of non-httpi(s) URI 136 * @throw not_implemented in case of non-httpi(s) URI
137 * @throw bad_input in case of malformed URI 137 * @throw bad_input in case of malformed URI
138 */ 138 */
139 string rfc_3986_normalize_uri(const string& uri); 139 string rfc_3986_normalize_uri(const string& uri);
140 140
141 string& strip_uri_fragment_part(string& uri); 141 string& strip_uri_fragment_part(string& uri);
142 142
143 string abi_demangle(const char* mn); 143 string abi_demangle(const char* mn);
144 144
145 string base64_signature(const assoc_t& assoc,const basic_openid_message& om); 145 string base64_signature(const assoc_t& assoc,const basic_openid_message& om);
146 146
147 class change_mode_message_proxy : public basic_openid_message {
148 public:
149 const basic_openid_message& x;
150 const string& mode;
151
152 change_mode_message_proxy(const basic_openid_message& xx,const string& m) : x(xx), mode(m) { }
153
154 bool has_field(const string& n) const { return x.has_field(n); }
155 const string& get_field(const string& n) const {
156 return (n=="mode")?mode:x.get_field(n); }
157 bool has_ns(const string& uri) const {return x.has_ns(uri); }
158 string get_ns(const string& uri) const { return x.get_ns(uri); }
159 fields_iterator fields_begin() const {
160 return x.fields_begin(); }
161 fields_iterator fields_end() const {
162 return x.fields_end(); }
163 };
164
147 } 165 }
148 166
149} 167}
150 168
151#endif /* __OPKELE_UTIL_H */ 169#endif /* __OPKELE_UTIL_H */
diff --git a/lib/basic_rp.cc b/lib/basic_rp.cc
index 2da8416..a884583 100644
--- a/lib/basic_rp.cc
+++ b/lib/basic_rp.cc
@@ -185,130 +185,113 @@ namespace opkele {
185 if(eq==string::npos || eq>am) { 185 if(eq==string::npos || eq>am) {
186 p[""] = u.substr(q,eq-q); 186 p[""] = u.substr(q,eq-q);
187 }else{ 187 }else{
188 p[u.substr(q,eq-q)] = u.substr(eq+1,am-eq-1); 188 p[u.substr(q,eq-q)] = u.substr(eq+1,am-eq-1);
189 } 189 }
190 q = ++am; 190 q = ++am;
191 } 191 }
192 } 192 }
193 } 193 }
194 194
195 void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) { 195 void basic_RP::id_res(const basic_openid_message& om,extension_t *ext) {
196 bool o2 = om.has_field("ns") 196 bool o2 = om.has_field("ns")
197 && om.get_field("ns")==OIURI_OPENID20; 197 && om.get_field("ns")==OIURI_OPENID20;
198 if( (!o2) && om.has_field("user_setup_url")) 198 if( (!o2) && om.has_field("user_setup_url"))
199 throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided", 199 throw id_res_setup(OPKELE_CP_ "assertion failed, setup url provided",
200 om.get_field("user_setup_url")); 200 om.get_field("user_setup_url"));
201 string m = om.get_field("mode"); 201 string m = om.get_field("mode");
202 if(o2 && m=="setup_needed") 202 if(o2 && m=="setup_needed")
203 throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided"); 203 throw id_res_setup(OPKELE_CP_ "setup needed, no setup url provided");
204 if(m=="cancel") 204 if(m=="cancel")
205 throw id_res_cancel(OPKELE_CP_ "authentication cancelled"); 205 throw id_res_cancel(OPKELE_CP_ "authentication cancelled");
206 bool go_dumb=false; 206 bool go_dumb=false;
207 try { 207 try {
208 string OP = o2 208 string OP = o2
209 ?om.get_field("op_endpoint") 209 ?om.get_field("op_endpoint")
210 :get_endpoint().uri; 210 :get_endpoint().uri;
211 assoc_t assoc = retrieve_assoc( 211 assoc_t assoc = retrieve_assoc(
212 OP,om.get_field("assoc_handle")); 212 OP,om.get_field("assoc_handle"));
213 if(om.get_field("sig")!=util::base64_signature(assoc,om)) 213 if(om.get_field("sig")!=util::base64_signature(assoc,om))
214 throw id_res_mismatch(OPKELE_CP_ "signature mismatch"); 214 throw id_res_mismatch(OPKELE_CP_ "signature mismatch");
215 }catch(dumb_RP& drp) { 215 }catch(dumb_RP& drp) {
216 go_dumb=true; 216 go_dumb=true;
217 }catch(failed_lookup& e) { 217 }catch(failed_lookup& e) {
218 go_dumb=true; 218 go_dumb=true;
219 } OPKELE_RETHROW 219 } OPKELE_RETHROW
220 if(go_dumb) { 220 if(go_dumb) {
221 try { 221 try {
222 string OP = o2 222 string OP = o2
223 ?om.get_field("op_endpoint") 223 ?om.get_field("op_endpoint")
224 :get_endpoint().uri; 224 :get_endpoint().uri;
225 check_authentication(OP,om); 225 check_authentication(OP,om);
226 }catch(failed_check_authentication& fca) { 226 }catch(failed_check_authentication& fca) {
227 throw id_res_failed(OPKELE_CP_ "failed to check_authentication()"); 227 throw id_res_failed(OPKELE_CP_ "failed to check_authentication()");
228 } OPKELE_RETHROW 228 } OPKELE_RETHROW
229 } 229 }
230 signed_part_message_proxy signeds(om); 230 signed_part_message_proxy signeds(om);
231 if(o2) { 231 if(o2) {
232 check_nonce(om.get_field("op_endpoint"), 232 check_nonce(om.get_field("op_endpoint"),
233 om.get_field("response_nonce")); 233 om.get_field("response_nonce"));
234 static const char *mustsign[] = { 234 static const char *mustsign[] = {
235 "op_endpoint", "return_to", "response_nonce", "assoc_handle", 235 "op_endpoint", "return_to", "response_nonce", "assoc_handle",
236 "claimed_id", "identity" }; 236 "claimed_id", "identity" };
237 for(int ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) { 237 for(int ms=0;ms<(sizeof(mustsign)/sizeof(*mustsign));++ms) {
238 if(om.has_field(mustsign[ms]) && !signeds.has_field(mustsign[ms])) 238 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"); 239 throw bad_input(OPKELE_CP_ string("Field '")+mustsign[ms]+"' is not signed against the specs");
240 } 240 }
241 if( ( 241 if( (
242 (om.has_field("claimed_id")?1:0) 242 (om.has_field("claimed_id")?1:0)
243 ^ 243 ^
244 (om.has_field("identity")?1:0) 244 (om.has_field("identity")?1:0)
245 )&1 ) 245 )&1 )
246 throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent"); 246 throw bad_input(OPKELE_CP_ "claimed_id and identity must be either both present or both absent");
247 247
248 string turl = util::rfc_3986_normalize_uri(get_this_url()); 248 string turl = util::rfc_3986_normalize_uri(get_this_url());
249 util::strip_uri_fragment_part(turl); 249 util::strip_uri_fragment_part(turl);
250 string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to")); 250 string rurl = util::rfc_3986_normalize_uri(om.get_field("return_to"));
251 util::strip_uri_fragment_part(rurl); 251 util::strip_uri_fragment_part(rurl);
252 string::size_type 252 string::size_type
253 tq = turl.find('?'), rq = rurl.find('?'); 253 tq = turl.find('?'), rq = rurl.find('?');
254 if( 254 if(
255 ((tq==string::npos)?turl:turl.substr(0,tq)) 255 ((tq==string::npos)?turl:turl.substr(0,tq))
256 != 256 !=
257 ((rq==string::npos)?rurl:rurl.substr(0,rq)) 257 ((rq==string::npos)?rurl:rurl.substr(0,rq))
258 ) 258 )
259 throw id_res_bad_return_to(OPKELE_CP_ "return_to url doesn't match request url"); 259 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); 260 map<string,string> tp; parse_query(turl,tq,tp);
261 map<string,string> rp; parse_query(rurl,rq,rp); 261 map<string,string> rp; parse_query(rurl,rq,rp);
262 for(map<string,string>::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) { 262 for(map<string,string>::const_iterator rpi=rp.begin();rpi!=rp.end();++rpi) {
263 map<string,string>::const_iterator tpi = tp.find(rpi->first); 263 map<string,string>::const_iterator tpi = tp.find(rpi->first);
264 if(tpi==tp.end()) 264 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"); 265 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) 266 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"); 267 throw id_res_bad_return_to(OPKELE_CP_ string("Parameter '")+rpi->first+"' from return_to doesn't matche the request");
268 } 268 }
269 269
270 if(om.has_field("claimed_id")) { 270 if(om.has_field("claimed_id")) {
271 verify_OP( 271 verify_OP(
272 om.get_field("op_endpoint"), 272 om.get_field("op_endpoint"),
273 om.get_field("claimed_id"), 273 om.get_field("claimed_id"),
274 om.get_field("identity") ); 274 om.get_field("identity") );
275 } 275 }
276 276
277 } 277 }
278 if(ext) ext->id_res_hook(om,signeds); 278 if(ext) ext->id_res_hook(om,signeds);
279 } 279 }
280 280
281 class check_auth_message_proxy : public basic_openid_message {
282 public:
283 const basic_openid_message& x;
284
285 check_auth_message_proxy(const basic_openid_message& xx) : x(xx) { }
286
287 bool has_field(const string& n) const { return x.has_field(n); }
288 const string& get_field(const string& n) const {
289 static const string checkauthmode="check_authentication";
290 return (n=="mode")?checkauthmode:x.get_field(n); }
291 bool has_ns(const string& uri) const {return x.has_ns(uri); }
292 string get_ns(const string& uri) const { return x.get_ns(uri); }
293 fields_iterator fields_begin() const {
294 return x.fields_begin(); }
295 fields_iterator fields_end() const {
296 return x.fields_end(); }
297 };
298
299 void basic_RP::check_authentication(const string& OP, 281 void basic_RP::check_authentication(const string& OP,
300 const basic_openid_message& om){ 282 const basic_openid_message& om){
301 openid_message_t res; 283 openid_message_t res;
302 direct_request(res,check_auth_message_proxy(om),OP); 284 static const string checkauthmode = "check_authentication";
285 direct_request(res,util::change_mode_message_proxy(om,checkauthmode),OP);
303 if(res.has_field("is_valid")) { 286 if(res.has_field("is_valid")) {
304 if(res.get_field("is_valid")=="true") { 287 if(res.get_field("is_valid")=="true") {
305 if(res.has_field("invalidate_handle")) 288 if(res.has_field("invalidate_handle"))
306 invalidate_assoc(OP,res.get_field("invalidate_handle")); 289 invalidate_assoc(OP,res.get_field("invalidate_handle"));
307 return; 290 return;
308 } 291 }
309 } 292 }
310 throw failed_check_authentication( 293 throw failed_check_authentication(
311 OPKELE_CP_ "failed to verify response"); 294 OPKELE_CP_ "failed to verify response");
312 } 295 }
313 296
314} 297}