summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/opkele/basic_op.h119
-rw-r--r--include/opkele/verify_op.h2
-rw-r--r--lib/basic_op.cc38
-rw-r--r--lib/verify_op.cc2
-rw-r--r--test/OP.cc2
5 files changed, 134 insertions, 29 deletions
diff --git a/include/opkele/basic_op.h b/include/opkele/basic_op.h
index 5bba1bf..4daed02 100644
--- a/include/opkele/basic_op.h
+++ b/include/opkele/basic_op.h
@@ -1,69 +1,174 @@
1#ifndef __OPKELE_BASIC_OP_H 1#ifndef __OPKELE_BASIC_OP_H
2#define __OPKELE_BASIC_OP_H 2#define __OPKELE_BASIC_OP_H
3 3
4#include <string> 4#include <string>
5#include <opkele/types.h> 5#include <opkele/types.h>
6#include <opkele/extension.h> 6#include <opkele/extension.h>
7 7
8namespace opkele { 8namespace opkele {
9 using std::string; 9 using std::string;
10 10
11 class basic_op { 11 class basic_OP {
12 public: 12 public:
13 mode_t mode; 13 mode_t mode;
14 assoc_t assoc; 14 assoc_t assoc;
15 bool openid2; 15 bool openid2;
16 string return_to; 16 string return_to;
17 string realm; 17 string realm;
18 string claimed_id; 18 string claimed_id;
19 string identity; 19 string identity;
20 string invalidate_handle; 20 string invalidate_handle;
21 21
22 void reset_vars(); 22 void reset_vars();
23 23
24 bool has_return_to() const; 24 bool has_return_to() const;
25 const string& get_return_to() const; 25 const string& get_return_to() const;
26 26
27 const string& get_realm() const; 27 const string& get_realm() const;
28 28
29 bool has_identity() const; 29 bool has_identity() const;
30 const string& get_claimed_id() const; 30 const string& get_claimed_id() const;
31 const string& get_identity() const; 31 const string& get_identity() const;
32 32
33 bool is_id_select() const; 33 bool is_id_select() const;
34 34
35 void select_identity(const string& c,const string& i); 35 void select_identity(const string& c,const string& i);
36 void set_claimed_id(const string& c); 36 void set_claimed_id(const string& c);
37 37
38 /** @name OpenID operations
39 * @{
40 */
41 /**
42 * Establish association with RP
43 * @param oum reply message
44 * @param inm request message
45 */
38 basic_openid_message& associate( 46 basic_openid_message& associate(
39 basic_openid_message& oum, 47 basic_openid_message& oum,
40 const basic_openid_message& inm); 48 const basic_openid_message& inm);
41 49
50 /**
51 * Parse the checkid_* request. The function parses input message,
52 * retrieves the information needed for further processing,
53 * verifies what can be verified at this stage.
54 * @param inm incoming OpenID message
55 * @param ext extension/chain of extensions supported
56 */
42 void checkid_(const basic_openid_message& inm,extension_t *ext=0); 57 void checkid_(const basic_openid_message& inm,extension_t *ext=0);
58 /**
59 * Build and sign a positive assertion message
60 * @param om outpu OpenID message
61 * @param ext extension/chain of extensions supported
62 * @return reference to om
63 */
43 basic_openid_message& id_res(basic_openid_message& om, 64 basic_openid_message& id_res(basic_openid_message& om,
44 extension_t *ext=0); 65 extension_t *ext=0);
66 /**
67 * Build a 'cancel' negative assertion
68 * @param om output OpenID message
69 * @return reference to om
70 */
45 basic_openid_message& cancel(basic_openid_message& om); 71 basic_openid_message& cancel(basic_openid_message& om);
72 /**
73 * Build an 'error' reply
74 * @param om output OpenID message
75 * @param error a human-readable message indicating the cause
76 * @param contact contact address for the server administrator (can be empty)
77 * @param reference a reference token (can be empty)
78 * @return reference to om
79 */
46 basic_openid_message& error(basic_openid_message& om, 80 basic_openid_message& error(basic_openid_message& om,
47 const string& error,const string& contact, 81 const string& error,const string& contact,
48 const string& reference ); 82 const string& reference );
83 /**
84 * Build a setup_needed reply to checkid_immediate request
85 * @param oum output OpenID message
86 * @param inm incoming OpenID request being processed
87 * @return reference to oum
88 */
49 basic_openid_message& setup_needed( 89 basic_openid_message& setup_needed(
50 basic_openid_message& oum,const basic_openid_message& inm); 90 basic_openid_message& oum,const basic_openid_message& inm);
51 91
92 /**
93 * Process check_authentication request
94 * @param oum output OpenID message
95 * @param inm incoming request
96 * @return reference to oum
97 */
52 basic_openid_message& check_authentication( 98 basic_openid_message& check_authentication(
53 basic_openid_message& oum,const basic_openid_message& inm); 99 basic_openid_message& oum,const basic_openid_message& inm);
54 100 /**
101 * @}
102 */
103
104 /**
105 * Verify return_to url. The default implementation checks whether
106 * return_to URI matches the realm
107 * @throw bad_realm in case of invalid realm
108 * @throw bad_return_to if return_to doesn't match the realm
109 * @see verify_op::verify_return_to()
110 */
55 virtual void verify_return_to(); 111 virtual void verify_return_to();
56 112
57 virtual assoc_t alloc_assoc(const string& t,size_t kl,bool sl) = 0; 113 /**
58 virtual assoc_t retrieve_assoc(const string& h) = 0; 114 * @name Global persistent store API
59 115 * These functions are related to the associations with RPs storage
60 virtual string& alloc_nonce(string& nonce,bool sl) = 0; 116 * and retrieval and nonce management.
117 * @{
118 */
119 /**
120 * Allocate association.
121 * @param type association type
122 * @param kl association key length
123 * @param sl true if the association is stateless
124 * @return association object
125 */
126 virtual assoc_t alloc_assoc(const string& type,size_t kl,bool sl) = 0;
127 /**
128 * Retrieve valid unexpired association
129 * @param handle association handle
130 * @return association object
131 */
132 virtual assoc_t retrieve_assoc(const string& handle) = 0;
133 /**
134 * Allocate nonce.
135 * @param nonce input-output parameter containing timestamp part of
136 * the nonce on input
137 * @param sl true if the nonce is
138 * @return reference to nonce
139 * @throw failed_lookup if no such valid unexpired association
140 * could be retrieved
141 */
142 virtual string& alloc_nonce(string& nonce) = 0;
143 /**
144 * Check nonce validity
145 * @param nonce nonce to check
146 * @return true if nonce found and isn't yet invalidated
147 */
61 virtual bool check_nonce(const string& nonce) = 0; 148 virtual bool check_nonce(const string& nonce) = 0;
149 /**
150 * Invalidate nonce
151 * @param nonce nonce to check
152 */
62 virtual void invalidate_nonce(const string& nonce) = 0; 153 virtual void invalidate_nonce(const string& nonce) = 0;
63 154 /**
155 * @}
156 */
157
158 /**
159 * @name Site particulars API
160 * @{
161 */
162 /**
163 * Query the absolute URL of the op endpoint
164 * @return fully qualified url of the OP endpoint
165 */
64 virtual const string get_op_endpoint() const = 0; 166 virtual const string get_op_endpoint() const = 0;
167 /**
168 * @}
169 */
65 170
66 }; 171 };
67} 172}
68 173
69#endif /* __OPKELE_BASIC_OP_H */ 174#endif /* __OPKELE_BASIC_OP_H */
diff --git a/include/opkele/verify_op.h b/include/opkele/verify_op.h
index f5c97b2..6c3c386 100644
--- a/include/opkele/verify_op.h
+++ b/include/opkele/verify_op.h
@@ -1,16 +1,16 @@
1#ifndef __OPKELE_VERIFY_OP_H 1#ifndef __OPKELE_VERIFY_OP_H
2#define __OPKELE_VERIFY_OP_H 2#define __OPKELE_VERIFY_OP_H
3 3
4#include <opkele/basic_op.h> 4#include <opkele/basic_op.h>
5 5
6namespace opkele { 6namespace opkele {
7 7
8 class verify_op : public basic_op { 8 class verify_op : public basic_OP {
9 public: 9 public:
10 10
11 void verify_return_to(); 11 void verify_return_to();
12 }; 12 };
13 13
14} 14}
15 15
16#endif /* __OPKELE_VERIFY_OP_H */ 16#endif /* __OPKELE_VERIFY_OP_H */
diff --git a/lib/basic_op.cc b/lib/basic_op.cc
index 7a2dbd2..18446dc 100644
--- a/lib/basic_op.cc
+++ b/lib/basic_op.cc
@@ -1,330 +1,330 @@
1#include <time.h> 1#include <time.h>
2#include <cassert> 2#include <cassert>
3#include <openssl/sha.h> 3#include <openssl/sha.h>
4#include <openssl/hmac.h> 4#include <openssl/hmac.h>
5#include <opkele/data.h> 5#include <opkele/data.h>
6#include <opkele/basic_op.h> 6#include <opkele/basic_op.h>
7#include <opkele/exception.h> 7#include <opkele/exception.h>
8#include <opkele/util.h> 8#include <opkele/util.h>
9#include <opkele/uris.h> 9#include <opkele/uris.h>
10 10
11namespace opkele { 11namespace opkele {
12 12
13 void basic_op::reset_vars() { 13 void basic_OP::reset_vars() {
14 assoc.reset(); 14 assoc.reset();
15 return_to.clear(); realm.clear(); 15 return_to.clear(); realm.clear();
16 claimed_id.clear(); identity.clear(); 16 claimed_id.clear(); identity.clear();
17 invalidate_handle.clear(); 17 invalidate_handle.clear();
18 } 18 }
19 19
20 bool basic_op::has_return_to() const { 20 bool basic_OP::has_return_to() const {
21 return !return_to.empty(); 21 return !return_to.empty();
22 } 22 }
23 const string& basic_op::get_return_to() const { 23 const string& basic_OP::get_return_to() const {
24 if(return_to.empty()) 24 if(return_to.empty())
25 throw no_return_to(OPKELE_CP_ "No return_to URL provided with request"); 25 throw no_return_to(OPKELE_CP_ "No return_to URL provided with request");
26 return return_to; 26 return return_to;
27 } 27 }
28 28
29 const string& basic_op::get_realm() const { 29 const string& basic_OP::get_realm() const {
30 assert(!realm.empty()); 30 assert(!realm.empty());
31 return realm; 31 return realm;
32 } 32 }
33 33
34 bool basic_op::has_identity() const { 34 bool basic_OP::has_identity() const {
35 return !identity.empty(); 35 return !identity.empty();
36 } 36 }
37 const string& basic_op::get_claimed_id() const { 37 const string& basic_OP::get_claimed_id() const {
38 if(claimed_id.empty()) 38 if(claimed_id.empty())
39 throw non_identity(OPKELE_CP_ "attempting to retrieve claimed_id of non-identity related request"); 39 throw non_identity(OPKELE_CP_ "attempting to retrieve claimed_id of non-identity related request");
40 assert(!identity.empty()); 40 assert(!identity.empty());
41 return claimed_id; 41 return claimed_id;
42 } 42 }
43 const string& basic_op::get_identity() const { 43 const string& basic_OP::get_identity() const {
44 if(identity.empty()) 44 if(identity.empty())
45 throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related request"); 45 throw non_identity(OPKELE_CP_ "attempting to retrieve identity of non-identity related request");
46 assert(!claimed_id.empty()); 46 assert(!claimed_id.empty());
47 return identity; 47 return identity;
48 } 48 }
49 49
50 bool basic_op::is_id_select() const { 50 bool basic_OP::is_id_select() const {
51 return identity==IDURI_SELECT20; 51 return identity==IDURI_SELECT20;
52 } 52 }
53 53
54 void basic_op::select_identity(const string& c,const string& i) { 54 void basic_OP::select_identity(const string& c,const string& i) {
55 claimed_id = c; identity = i; 55 claimed_id = c; identity = i;
56 } 56 }
57 void basic_op::set_claimed_id(const string& c) { 57 void basic_OP::set_claimed_id(const string& c) {
58 claimed_id = c; 58 claimed_id = c;
59 } 59 }
60 60
61 basic_openid_message& basic_op::associate( 61 basic_openid_message& basic_OP::associate(
62 basic_openid_message& oum, 62 basic_openid_message& oum,
63 const basic_openid_message& inm) try { 63 const basic_openid_message& inm) try {
64 assert(inm.get_field("mode")=="associate"); 64 assert(inm.get_field("mode")=="associate");
65 util::dh_t dh; 65 util::dh_t dh;
66 util::bignum_t c_pub; 66 util::bignum_t c_pub;
67 unsigned char key_digest[SHA256_DIGEST_LENGTH]; 67 unsigned char key_digest[SHA256_DIGEST_LENGTH];
68 size_t d_len = 0; 68 size_t d_len = 0;
69 enum { 69 enum {
70 sess_cleartext, sess_dh_sha1, sess_dh_sha256 70 sess_cleartext, sess_dh_sha1, sess_dh_sha256
71 } st = sess_cleartext; 71 } st = sess_cleartext;
72 string sts = inm.get_field("session_type"); 72 string sts = inm.get_field("session_type");
73 string ats = inm.get_field("assoc_type"); 73 string ats = inm.get_field("assoc_type");
74 if(sts=="DH-SHA1" || sts=="DH-SHA256") { 74 if(sts=="DH-SHA1" || sts=="DH-SHA256") {
75 if(!(dh = DH_new())) 75 if(!(dh = DH_new()))
76 throw exception_openssl(OPKELE_CP_ "failed to DH_new()"); 76 throw exception_openssl(OPKELE_CP_ "failed to DH_new()");
77 c_pub = util::base64_to_bignum(inm.get_field("dh_consumer_public")); 77 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")); 78 try { dh->p = util::base64_to_bignum(inm.get_field("dh_modulus"));
79 }catch(failed_lookup&) { 79 }catch(failed_lookup&) {
80 dh->p = util::dec_to_bignum(data::_default_p); } 80 dh->p = util::dec_to_bignum(data::_default_p); }
81 try { dh->g = util::base64_to_bignum(inm.get_field("dh_gen")); 81 try { dh->g = util::base64_to_bignum(inm.get_field("dh_gen"));
82 }catch(failed_lookup&) { 82 }catch(failed_lookup&) {
83 dh->g = util::dec_to_bignum(data::_default_g); } 83 dh->g = util::dec_to_bignum(data::_default_g); }
84 if(!DH_generate_key(dh)) 84 if(!DH_generate_key(dh))
85 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()"); 85 throw exception_openssl(OPKELE_CP_ "failed to DH_generate_key()");
86 vector<unsigned char> ck(DH_size(dh)+1); 86 vector<unsigned char> ck(DH_size(dh)+1);
87 unsigned char *ckptr = &(ck.front())+1; 87 unsigned char *ckptr = &(ck.front())+1;
88 int cklen = DH_compute_key(ckptr,c_pub,dh); 88 int cklen = DH_compute_key(ckptr,c_pub,dh);
89 if(cklen<0) 89 if(cklen<0)
90 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()"); 90 throw exception_openssl(OPKELE_CP_ "failed to DH_compute_key()");
91 if(cklen && (*ckptr)&0x80) { 91 if(cklen && (*ckptr)&0x80) {
92 (*(--ckptr)) = 0; ++cklen; } 92 (*(--ckptr)) = 0; ++cklen; }
93 if(sts=="DH-SHA1") { 93 if(sts=="DH-SHA1") {
94 SHA1(ckptr,cklen,key_digest); d_len = SHA_DIGEST_LENGTH; 94 SHA1(ckptr,cklen,key_digest); d_len = SHA_DIGEST_LENGTH;
95 }else if(sts=="DH-SHA256") { 95 }else if(sts=="DH-SHA256") {
96 SHA256(ckptr,cklen,key_digest); d_len = SHA256_DIGEST_LENGTH; 96 SHA256(ckptr,cklen,key_digest); d_len = SHA256_DIGEST_LENGTH;
97 }else 97 }else
98 throw internal_error(OPKELE_CP_ "I thought I knew the session type"); 98 throw internal_error(OPKELE_CP_ "I thought I knew the session type");
99 }else 99 }else
100 throw unsupported(OPKELE_CP_ "Unsupported session_type"); 100 throw unsupported(OPKELE_CP_ "Unsupported session_type");
101 assoc_t assoc; 101 assoc_t assoc;
102 if(ats=="HMAC-SHA1") 102 if(ats=="HMAC-SHA1")
103 assoc = alloc_assoc(ats,SHA_DIGEST_LENGTH,true); 103 assoc = alloc_assoc(ats,SHA_DIGEST_LENGTH,true);
104 else if(ats=="HMAC-SHA256") 104 else if(ats=="HMAC-SHA256")
105 assoc = alloc_assoc(ats,SHA256_DIGEST_LENGTH,true); 105 assoc = alloc_assoc(ats,SHA256_DIGEST_LENGTH,true);
106 else 106 else
107 throw unsupported(OPKELE_CP_ "Unsupported assoc_type"); 107 throw unsupported(OPKELE_CP_ "Unsupported assoc_type");
108 oum.reset_fields(); 108 oum.reset_fields();
109 oum.set_field("ns",OIURI_OPENID20); 109 oum.set_field("ns",OIURI_OPENID20);
110 oum.set_field("assoc_type",assoc->assoc_type()); 110 oum.set_field("assoc_type",assoc->assoc_type());
111 oum.set_field("assoc_handle",assoc->handle()); 111 oum.set_field("assoc_handle",assoc->handle());
112 oum.set_field("expires_in",util::long_to_string(assoc->expires_in())); 112 oum.set_field("expires_in",util::long_to_string(assoc->expires_in()));
113 secret_t secret = assoc->secret(); 113 secret_t secret = assoc->secret();
114 if(sts=="DH-SHA1" || sts=="DH-SHA256") { 114 if(sts=="DH-SHA1" || sts=="DH-SHA256") {
115 if(d_len != secret.size()) 115 if(d_len != secret.size())
116 throw bad_input(OPKELE_CP_ "Association secret and session MAC are not of the same size"); 116 throw bad_input(OPKELE_CP_ "Association secret and session MAC are not of the same size");
117 oum.set_field("session_type",sts); 117 oum.set_field("session_type",sts);
118 oum.set_field("dh_server_public",util::bignum_to_base64(dh->pub_key)); 118 oum.set_field("dh_server_public",util::bignum_to_base64(dh->pub_key));
119 string b64; secret.enxor_to_base64(key_digest,b64); 119 string b64; secret.enxor_to_base64(key_digest,b64);
120 oum.set_field("enc_mac_key",b64); 120 oum.set_field("enc_mac_key",b64);
121 }else /* TODO: support cleartext over encrypted connection */ 121 }else /* TODO: support cleartext over encrypted connection */
122 throw unsupported(OPKELE_CP_ "Unsupported session type"); 122 throw unsupported(OPKELE_CP_ "Unsupported session type");
123 return oum; 123 return oum;
124 } catch(unsupported& u) { 124 } catch(unsupported& u) {
125 oum.reset_fields(); 125 oum.reset_fields();
126 oum.set_field("ns",OIURI_OPENID20); 126 oum.set_field("ns",OIURI_OPENID20);
127 oum.set_field("error",u.what()); 127 oum.set_field("error",u.what());
128 oum.set_field("error_code","unsupported-type"); 128 oum.set_field("error_code","unsupported-type");
129 oum.set_field("session_type","DH-SHA256"); 129 oum.set_field("session_type","DH-SHA256");
130 oum.set_field("assoc_type","HMAC-SHA256"); 130 oum.set_field("assoc_type","HMAC-SHA256");
131 return oum; 131 return oum;
132 } 132 }
133 133
134 void basic_op::checkid_(const basic_openid_message& inm, 134 void basic_OP::checkid_(const basic_openid_message& inm,
135 extension_t *ext) { 135 extension_t *ext) {
136 reset_vars(); 136 reset_vars();
137 string mode = inm.get_field("mode"); 137 string mode = inm.get_field("mode");
138 if(mode=="checkid_setup") 138 if(mode=="checkid_setup")
139 mode = mode_checkid_setup; 139 mode = mode_checkid_setup;
140 else if(mode=="checkid_immediate") 140 else if(mode=="checkid_immediate")
141 mode = mode_checkid_immediate; 141 mode = mode_checkid_immediate;
142 else 142 else
143 throw bad_input(OPKELE_CP_ "Invalid checkid_* mode"); 143 throw bad_input(OPKELE_CP_ "Invalid checkid_* mode");
144 try { 144 try {
145 assoc = retrieve_assoc(invalidate_handle=inm.get_field("assoc_handle")); 145 assoc = retrieve_assoc(invalidate_handle=inm.get_field("assoc_handle"));
146 invalidate_handle.clear(); 146 invalidate_handle.clear();
147 }catch(failed_lookup&) { } 147 }catch(failed_lookup&) { }
148 try { 148 try {
149 openid2 = (inm.get_field("ns")==OIURI_OPENID20); 149 openid2 = (inm.get_field("ns")==OIURI_OPENID20);
150 }catch(failed_lookup&) { openid2 = false; } 150 }catch(failed_lookup&) { openid2 = false; }
151 try { 151 try {
152 return_to = inm.get_field("return_to"); 152 return_to = inm.get_field("return_to");
153 }catch(failed_lookup&) { } 153 }catch(failed_lookup&) { }
154 if(openid2) { 154 if(openid2) {
155 try { 155 try {
156 realm = inm.get_field("realm"); 156 realm = inm.get_field("realm");
157 }catch(failed_lookup&) { 157 }catch(failed_lookup&) {
158 try { 158 try {
159 realm = inm.get_field("trust_root"); 159 realm = inm.get_field("trust_root");
160 }catch(failed_lookup&) { 160 }catch(failed_lookup&) {
161 if(return_to.empty()) 161 if(return_to.empty())
162 throw bad_input(OPKELE_CP_ 162 throw bad_input(OPKELE_CP_
163 "Both realm and return_to are unset"); 163 "Both realm and return_to are unset");
164 realm = return_to; 164 realm = return_to;
165 } 165 }
166 } 166 }
167 }else{ 167 }else{
168 try { 168 try {
169 realm = inm.get_field("trust_root"); 169 realm = inm.get_field("trust_root");
170 }catch(failed_lookup&) { 170 }catch(failed_lookup&) {
171 if(return_to.empty()) 171 if(return_to.empty())
172 throw bad_input(OPKELE_CP_ 172 throw bad_input(OPKELE_CP_
173 "Both realm and return_to are unset"); 173 "Both realm and return_to are unset");
174 realm = return_to; 174 realm = return_to;
175 } 175 }
176 } 176 }
177 try { 177 try {
178 identity = inm.get_field("identity"); 178 identity = inm.get_field("identity");
179 try { 179 try {
180 claimed_id = inm.get_field("claimed_id"); 180 claimed_id = inm.get_field("claimed_id");
181 }catch(failed_lookup&) { 181 }catch(failed_lookup&) {
182 if(openid2) 182 if(openid2)
183 throw bad_input(OPKELE_CP_ 183 throw bad_input(OPKELE_CP_
184 "claimed_id and identity must be either both present or both absent"); 184 "claimed_id and identity must be either both present or both absent");
185 claimed_id = identity; 185 claimed_id = identity;
186 } 186 }
187 }catch(failed_lookup&) { 187 }catch(failed_lookup&) {
188 if(openid2 && inm.has_field("claimed_id")) 188 if(openid2 && inm.has_field("claimed_id"))
189 throw bad_input(OPKELE_CP_ 189 throw bad_input(OPKELE_CP_
190 "claimed_id and identity must be either both present or both absent"); 190 "claimed_id and identity must be either both present or both absent");
191 } 191 }
192 verify_return_to(); 192 verify_return_to();
193 if(ext) ext->op_checkid_hook(inm); 193 if(ext) ext->op_checkid_hook(inm);
194 } 194 }
195 195
196 basic_openid_message& basic_op::id_res(basic_openid_message& om, 196 basic_openid_message& basic_OP::id_res(basic_openid_message& om,
197 extension_t *ext) { 197 extension_t *ext) {
198 assert(!return_to.empty()); 198 assert(!return_to.empty());
199 assert(!is_id_select()); 199 assert(!is_id_select());
200 if(!assoc) { 200 if(!assoc) {
201 assoc = alloc_assoc("HMAC-SHA256",SHA256_DIGEST_LENGTH,true); 201 assoc = alloc_assoc("HMAC-SHA256",SHA256_DIGEST_LENGTH,true);
202 } 202 }
203 time_t now = time(0); 203 time_t now = time(0);
204 struct tm gmt; gmtime_r(&now,&gmt); 204 struct tm gmt; gmtime_r(&now,&gmt);
205 char w3timestr[24]; 205 char w3timestr[24];
206 if(!strftime(w3timestr,sizeof(w3timestr),"%Y-%m-%dT%H:%M:%SZ",&gmt)) 206 if(!strftime(w3timestr,sizeof(w3timestr),"%Y-%m-%dT%H:%M:%SZ",&gmt))
207 throw failed_conversion(OPKELE_CP_ 207 throw failed_conversion(OPKELE_CP_
208 "Failed to build time string for nonce" ); 208 "Failed to build time string for nonce" );
209 om.set_field("ns",OIURI_OPENID20); 209 om.set_field("ns",OIURI_OPENID20);
210 om.set_field("mode","id_res"); 210 om.set_field("mode","id_res");
211 om.set_field("op_endpoint",get_op_endpoint()); 211 om.set_field("op_endpoint",get_op_endpoint());
212 string ats = "ns,mode,op_endpoint,return_to,response_nonce," 212 string ats = "ns,mode,op_endpoint,return_to,response_nonce,"
213 "assoc_handle,signed"; 213 "assoc_handle,signed";
214 if(!identity.empty()) { 214 if(!identity.empty()) {
215 om.set_field("identity",identity); 215 om.set_field("identity",identity);
216 om.set_field("claimed_id",claimed_id); 216 om.set_field("claimed_id",claimed_id);
217 ats += ",identity,claimed_id"; 217 ats += ",identity,claimed_id";
218 } 218 }
219 om.set_field("return_to",return_to); 219 om.set_field("return_to",return_to);
220 string nonce = w3timestr; 220 string nonce = w3timestr;
221 om.set_field("response_nonce",alloc_nonce(nonce,assoc->stateless())); 221 om.set_field("response_nonce",alloc_nonce(nonce));
222 if(!invalidate_handle.empty()) { 222 if(!invalidate_handle.empty()) {
223 om.set_field("invalidate_handle",invalidate_handle); 223 om.set_field("invalidate_handle",invalidate_handle);
224 ats += ",invalidate_handle"; 224 ats += ",invalidate_handle";
225 } 225 }
226 om.set_field("assoc_handle",assoc->handle()); 226 om.set_field("assoc_handle",assoc->handle());
227 om.add_to_signed(ats); 227 om.add_to_signed(ats);
228 if(ext) ext->op_id_res_hook(om); 228 if(ext) ext->op_id_res_hook(om);
229 om.set_field("sig",util::base64_signature(assoc,om)); 229 om.set_field("sig",util::base64_signature(assoc,om));
230 return om; 230 return om;
231 } 231 }
232 232
233 basic_openid_message& basic_op::cancel(basic_openid_message& om) { 233 basic_openid_message& basic_OP::cancel(basic_openid_message& om) {
234 assert(!return_to.empty()); 234 assert(!return_to.empty());
235 om.set_field("ns",OIURI_OPENID20); 235 om.set_field("ns",OIURI_OPENID20);
236 om.set_field("mode","cancel"); 236 om.set_field("mode","cancel");
237 return om; 237 return om;
238 } 238 }
239 239
240 basic_openid_message& basic_op::error(basic_openid_message& om, 240 basic_openid_message& basic_OP::error(basic_openid_message& om,
241 const string& error,const string& contact, 241 const string& error,const string& contact,
242 const string& reference ) { 242 const string& reference ) {
243 assert(!return_to.empty()); 243 assert(!return_to.empty());
244 om.set_field("ns",OIURI_OPENID20); 244 om.set_field("ns",OIURI_OPENID20);
245 om.set_field("mode","error"); 245 om.set_field("mode","error");
246 om.set_field("error",error); 246 om.set_field("error",error);
247 om.set_field("contact",contact); 247 om.set_field("contact",contact);
248 om.set_field("reference",reference); 248 om.set_field("reference",reference);
249 return om; 249 return om;
250 } 250 }
251 251
252 basic_openid_message& basic_op::setup_needed( 252 basic_openid_message& basic_OP::setup_needed(
253 basic_openid_message& oum,const basic_openid_message& inm) { 253 basic_openid_message& oum,const basic_openid_message& inm) {
254 assert(mode==mode_checkid_immediate); 254 assert(mode==mode_checkid_immediate);
255 assert(!return_to.empty()); 255 assert(!return_to.empty());
256 if(openid2) { 256 if(openid2) {
257 oum.set_field("ns",OIURI_OPENID20); 257 oum.set_field("ns",OIURI_OPENID20);
258 oum.set_field("mode","setup_needed"); 258 oum.set_field("mode","setup_needed");
259 }else{ 259 }else{
260 oum.set_field("mode","id_res"); 260 oum.set_field("mode","id_res");
261 static const string setupmode = "checkid_setup"; 261 static const string setupmode = "checkid_setup";
262 oum.set_field("user_setup_url", 262 oum.set_field("user_setup_url",
263 util::change_mode_message_proxy(inm,setupmode) 263 util::change_mode_message_proxy(inm,setupmode)
264 .append_query(get_op_endpoint())); 264 .append_query(get_op_endpoint()));
265 } 265 }
266 return oum; 266 return oum;
267 } 267 }
268 268
269 basic_openid_message& basic_op::check_authentication( 269 basic_openid_message& basic_OP::check_authentication(
270 basic_openid_message& oum, 270 basic_openid_message& oum,
271 const basic_openid_message& inm) try { 271 const basic_openid_message& inm) try {
272 assert(inm.get_field("mode")=="check_authentication"); 272 assert(inm.get_field("mode")=="check_authentication");
273 oum.reset_fields(); 273 oum.reset_fields();
274 oum.set_field("ns",OIURI_OPENID20); 274 oum.set_field("ns",OIURI_OPENID20);
275 bool o2; 275 bool o2;
276 try { 276 try {
277 o2 = (inm.get_field("ns")==OIURI_OPENID20); 277 o2 = (inm.get_field("ns")==OIURI_OPENID20);
278 }catch(failed_lookup&) { o2 = false; } 278 }catch(failed_lookup&) { o2 = false; }
279 string nonce; 279 string nonce;
280 if(o2) { 280 if(o2) {
281 try { 281 try {
282 if(!check_nonce(nonce = inm.get_field("response_nonce"))) 282 if(!check_nonce(nonce = inm.get_field("response_nonce")))
283 throw failed_check_authentication(OPKELE_CP_ "Invalid nonce"); 283 throw failed_check_authentication(OPKELE_CP_ "Invalid nonce");
284 }catch(failed_lookup&) { 284 }catch(failed_lookup&) {
285 throw failed_check_authentication(OPKELE_CP_ "No nonce provided with check_authentication request"); 285 throw failed_check_authentication(OPKELE_CP_ "No nonce provided with check_authentication request");
286 } 286 }
287 } 287 }
288 try { 288 try {
289 assoc = retrieve_assoc(inm.get_field("assoc_handle")); 289 assoc = retrieve_assoc(inm.get_field("assoc_handle"));
290 if(!assoc->stateless()) 290 if(!assoc->stateless())
291 throw failed_check_authentication(OPKELE_CP_ "Will not do check_authentication on a stateful handle"); 291 throw failed_check_authentication(OPKELE_CP_ "Will not do check_authentication on a stateful handle");
292 }catch(failed_lookup&) { 292 }catch(failed_lookup&) {
293 throw failed_check_authentication(OPKELE_CP_ "No assoc_handle or invalid assoc_handle specified with check_authentication request"); 293 throw failed_check_authentication(OPKELE_CP_ "No assoc_handle or invalid assoc_handle specified with check_authentication request");
294 } 294 }
295 static const string idresmode = "id_res"; 295 static const string idresmode = "id_res";
296 try { 296 try {
297 if(util::base64_signature(assoc,util::change_mode_message_proxy(inm,idresmode))!=inm.get_field("sig")) 297 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"); 298 throw failed_check_authentication(OPKELE_CP_ "Signature mismatch");
299 }catch(failed_lookup&) { 299 }catch(failed_lookup&) {
300 throw failed_check_authentication(OPKELE_CP_ "failed to calculate signature"); 300 throw failed_check_authentication(OPKELE_CP_ "failed to calculate signature");
301 } 301 }
302 oum.set_field("is_valid","true"); 302 oum.set_field("is_valid","true");
303 try { 303 try {
304 string h = inm.get_field("invalidate_handle"); 304 string h = inm.get_field("invalidate_handle");
305 try { 305 try {
306 assoc_t ih = retrieve_assoc(h); 306 assoc_t ih = retrieve_assoc(h);
307 }catch(invalid_handle& ih) { 307 }catch(invalid_handle& ih) {
308 oum.set_field("invalidate_handle",h); 308 oum.set_field("invalidate_handle",h);
309 }catch(failed_lookup& ih) { 309 }catch(failed_lookup& ih) {
310 oum.set_field("invalidate_handle",h); 310 oum.set_field("invalidate_handle",h);
311 } 311 }
312 }catch(failed_lookup&) { } 312 }catch(failed_lookup&) { }
313 if(o2) { 313 if(o2) {
314 assert(!nonce.empty()); 314 assert(!nonce.empty());
315 invalidate_nonce(nonce); 315 invalidate_nonce(nonce);
316 } 316 }
317 return oum; 317 return oum;
318 }catch(failed_check_authentication& ) { 318 }catch(failed_check_authentication& ) {
319 oum.set_field("is_valid","false"); 319 oum.set_field("is_valid","false");
320 return oum; 320 return oum;
321 } 321 }
322 322
323 void basic_op::verify_return_to() { 323 void basic_OP::verify_return_to() {
324 if(realm.find('#')!=string::npos) 324 if(realm.find('#')!=string::npos)
325 throw opkele::bad_realm(OPKELE_CP_ "authentication realm contains URI fragment"); 325 throw opkele::bad_realm(OPKELE_CP_ "authentication realm contains URI fragment");
326 if(!util::uri_matches_realm(return_to,realm)) 326 if(!util::uri_matches_realm(return_to,realm))
327 throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match realm"); 327 throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match realm");
328 } 328 }
329 329
330} 330}
diff --git a/lib/verify_op.cc b/lib/verify_op.cc
index e7c26b5..0beca2d 100644
--- a/lib/verify_op.cc
+++ b/lib/verify_op.cc
@@ -1,53 +1,53 @@
1#include <opkele/verify_op.h> 1#include <opkele/verify_op.h>
2#include <opkele/discovery.h> 2#include <opkele/discovery.h>
3#include <opkele/exception.h> 3#include <opkele/exception.h>
4#include <opkele/util.h> 4#include <opkele/util.h>
5#include <opkele/uris.h> 5#include <opkele/uris.h>
6 6
7namespace opkele { 7namespace opkele {
8 using std::output_iterator_tag; 8 using std::output_iterator_tag;
9 9
10 class __RP_verifier_good_input : public exception { 10 class __RP_verifier_good_input : public exception {
11 public: 11 public:
12 __RP_verifier_good_input(OPKELE_E_PARS) 12 __RP_verifier_good_input(OPKELE_E_PARS)
13 : exception(OPKELE_E_CONS) { } 13 : exception(OPKELE_E_CONS) { }
14 }; 14 };
15 15
16 class RP_verifier : public iterator<output_iterator_tag,openid_endpoint_t,void> { 16 class RP_verifier : public iterator<output_iterator_tag,openid_endpoint_t,void> {
17 public: 17 public:
18 int seen; 18 int seen;
19 const string& return_to; 19 const string& return_to;
20 20
21 RP_verifier(const string& rt) 21 RP_verifier(const string& rt)
22 : return_to(rt), seen(0) { } 22 : return_to(rt), seen(0) { }
23 23
24 RP_verifier& operator*() { return *this; } 24 RP_verifier& operator*() { return *this; }
25 RP_verifier& operator=(const openid_endpoint_t& oep) { 25 RP_verifier& operator=(const openid_endpoint_t& oep) {
26 if(util::uri_matches_realm(return_to,oep.uri)) 26 if(util::uri_matches_realm(return_to,oep.uri))
27 throw __RP_verifier_good_input(OPKELE_CP_ "Found matching realm"); 27 throw __RP_verifier_good_input(OPKELE_CP_ "Found matching realm");
28 return *this; 28 return *this;
29 } 29 }
30 30
31 RP_verifier& operator++() { ++seen; return *this; } 31 RP_verifier& operator++() { ++seen; return *this; }
32 RP_verifier& operator++(int) { +seen; return *this; } 32 RP_verifier& operator++(int) { +seen; return *this; }
33 }; 33 };
34 34
35 void verify_op::verify_return_to() { 35 void verify_op::verify_return_to() {
36 basic_op::verify_return_to(); 36 basic_OP::verify_return_to();
37 try { 37 try {
38 RP_verifier rpv(return_to); 38 RP_verifier rpv(return_to);
39 string drealm = realm; 39 string drealm = realm;
40 string::size_type csss = drealm.find("://*."); 40 string::size_type csss = drealm.find("://*.");
41 if(csss==4 || csss==5) 41 if(csss==4 || csss==5)
42 drealm.replace(csss+3,1,"www"); 42 drealm.replace(csss+3,1,"www");
43 const char *rtt[] = { STURI_OPENID20_RT, 0 }; 43 const char *rtt[] = { STURI_OPENID20_RT, 0 };
44 yadiscover(rpv,drealm,rtt,false); 44 yadiscover(rpv,drealm,rtt,false);
45 if(rpv.seen) 45 if(rpv.seen)
46 throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match any found while doing discovery on RP"); 46 throw bad_return_to(OPKELE_CP_ "return_to URL doesn't match any found while doing discovery on RP");
47 }catch(__RP_verifier_good_input&) { 47 }catch(__RP_verifier_good_input&) {
48 }catch(bad_return_to& brt) { 48 }catch(bad_return_to& brt) {
49 throw; 49 throw;
50 }catch(exception_network&) { } 50 }catch(exception_network&) { }
51 } 51 }
52 52
53} 53}
diff --git a/test/OP.cc b/test/OP.cc
index c919d7f..ce54d92 100644
--- a/test/OP.cc
+++ b/test/OP.cc
@@ -68,193 +68,193 @@ class example_op_t : public opkele::verify_op {
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,bool stateless) { 164 string& alloc_nonce(string& nonce) {
165 uuid_t uuid; uuid_generate(uuid); 165 uuid_t uuid; uuid_generate(uuid);
166 nonce += opkele::util::encode_base64(uuid,sizeof(uuid)); 166 nonce += opkele::util::encode_base64(uuid,sizeof(uuid));
167 sqlite3_mem_t<char*> 167 sqlite3_mem_t<char*>
168 S = sqlite3_mprintf( 168 S = sqlite3_mprintf(
169 "INSERT INTO nonces" 169 "INSERT INTO nonces"
170 " (n_once) VALUES (%Q)", 170 " (n_once) VALUES (%Q)",
171 nonce.c_str() ); 171 nonce.c_str() );
172 db.exec(S); 172 db.exec(S);
173 return nonce; 173 return nonce;
174 } 174 }
175 bool check_nonce(const string& nonce) { 175 bool check_nonce(const string& nonce) {
176 sqlite3_mem_t<char*> 176 sqlite3_mem_t<char*>
177 S = sqlite3_mprintf( 177 S = sqlite3_mprintf(
178 "SELECT 1" 178 "SELECT 1"
179 " FROM nonces" 179 " FROM nonces"
180 " WHERE n_once=%Q AND n_itime IS NULL", 180 " WHERE n_once=%Q AND n_itime IS NULL",
181 nonce.c_str()); 181 nonce.c_str());
182 sqlite3_table_t T; 182 sqlite3_table_t T;
183 int nr,nc; 183 int nr,nc;
184 db.get_table(S,T,&nr,&nc); 184 db.get_table(S,T,&nr,&nc);
185 return nr>=1; 185 return nr>=1;
186 } 186 }
187 void invalidate_nonce(const string& nonce) { 187 void invalidate_nonce(const string& nonce) {
188 sqlite3_mem_t<char*> 188 sqlite3_mem_t<char*>
189 S = sqlite3_mprintf( 189 S = sqlite3_mprintf(
190 "UPDATE nonces" 190 "UPDATE nonces"
191 " SET n_itime=datetime('now')" 191 " SET n_itime=datetime('now')"
192 " WHERE n_once=%Q", 192 " WHERE n_once=%Q",
193 nonce.c_str()); 193 nonce.c_str());
194 db.exec(S); 194 db.exec(S);
195 } 195 }
196 196
197 const string get_op_endpoint() const { 197 const string get_op_endpoint() const {
198 return get_self_url(gw); 198 return get_self_url(gw);
199 } 199 }
200 200
201}; 201};
202 202
203int main(int argc,char *argv[]) { 203int main(int argc,char *argv[]) {
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 om;
248 try { om = gw.get_param("openid.mode"); }catch(kingate::exception_notfound&) { } 248 try { om = 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 <<