summaryrefslogtreecommitdiffabout
path: root/lib/openid_message.cc
Unidiff
Diffstat (limited to 'lib/openid_message.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--lib/openid_message.cc228
1 files changed, 228 insertions, 0 deletions
diff --git a/lib/openid_message.cc b/lib/openid_message.cc
new file mode 100644
index 0000000..3b08748
--- a/dev/null
+++ b/lib/openid_message.cc
@@ -0,0 +1,228 @@
1#include <cassert>
2#include <opkele/types.h>
3#include <opkele/exception.h>
4#include <opkele/util.h>
5#include <opkele/debug.h>
6
7#include "config.h"
8
9namespace opkele {
10 using std::input_iterator_tag;
11 using std::unary_function;
12
13 struct __om_copier : public unary_function<const string&,void> {
14 public:
15 const basic_openid_message& from;
16 basic_openid_message& to;
17
18 __om_copier(basic_openid_message& to,const basic_openid_message& from)
19 : from(from), to(to) {
20 to.reset_fields();
21 }
22
23 result_type operator()(argument_type f) {
24 to.set_field(f,from.get_field(f)); }
25 };
26
27 basic_openid_message::basic_openid_message(const basic_openid_message& x) {
28 x.copy_to(*this);
29 }
30 void basic_openid_message::copy_to(basic_openid_message& x) const {
31 for_each(fields_begin(),fields_end(),
32 __om_copier(x,*this) );
33 }
34
35 struct __om_ns_finder : public unary_function<const string&,bool> {
36 public:
37 const basic_openid_message& om;
38 const string& uri;
39
40 __om_ns_finder(const basic_openid_message& om,
41 const string& uri) : om(om), uri(uri) { }
42
43 result_type operator()(argument_type f) {
44 return
45 (!strncmp(f.c_str(),"ns.",sizeof("ns.")-1))
46 && om.get_field(f)==uri ;
47 }
48 };
49
50 bool basic_openid_message::has_ns(const string& uri) const {
51 fields_iterator ei = fields_end();
52 fields_iterator i = find_if(fields_begin(),fields_end(),
53 __om_ns_finder(*this,uri));
54 return !(i==ei);
55 }
56 string basic_openid_message::get_ns(const string& uri) const {
57 fields_iterator ei = fields_end();
58 fields_iterator i = find_if(fields_begin(),fields_end(),
59 __om_ns_finder(*this,uri));
60 if(i==ei)
61 throw failed_lookup(OPKELE_CP_ string("failed to find namespace ")+uri);
62 return i->substr(3);
63 }
64
65 struct __om_query_builder : public unary_function<const string&,void> {
66 public:
67 const basic_openid_message& om;
68 string& rv;
69 bool first;
70
71 __om_query_builder(string& rv,const basic_openid_message& om)
72 : om(om), first(true), rv(rv) {
73 for_each(om.fields_begin(),om.fields_end(),*this);
74 }
75 __om_query_builder(string& rv,const basic_openid_message& om,const string& url)
76 : om(om), first(true), rv(rv) {
77 rv = url;
78 if(rv.find('?')==string::npos)
79 rv += '?';
80 else
81 first = false;
82 for_each(om.fields_begin(),om.fields_end(),*this);
83 }
84
85 result_type operator()(argument_type f) {
86 if(first)
87 first = false;
88 else
89 rv += '&';
90 rv += "openid."; rv+= f;
91 rv += '=';
92 rv += util::url_encode(om.get_field(f));
93 }
94 };
95
96 string basic_openid_message::append_query(const string& url) const {
97 string rv;
98 return __om_query_builder(rv,*this,url).rv;
99 }
100 string basic_openid_message::query_string() const {
101 string rv;
102 return __om_query_builder(rv,*this).rv;
103 }
104
105 void basic_openid_message::reset_fields() {
106 throw not_implemented(OPKELE_CP_ "reset_fields() not implemented");
107 }
108 void basic_openid_message::set_field(const string& n,const string& v) {
109 throw not_implemented(OPKELE_CP_ "set_field() not implemented");
110 }
111 void basic_openid_message::reset_field(const string& n) {
112 throw not_implemented(OPKELE_CP_ "reset_field() not implemented");
113 }
114
115 void basic_openid_message::from_keyvalues(const string& kv) {
116 reset_fields();
117 string::size_type p = 0;
118 while(true) {
119 string::size_type co = kv.find(':',p);
120 if(co==string::npos)
121 break;
122#ifndef POSTELS_LAW
123 string::size_type nl = kv.find('\n',co+1);
124 if(nl==string::npos)
125 throw bad_input(OPKELE_CP_ "malformed input");
126 if(nl>co)
127 insert(value_type(kv.substr(p,co-p),kv.substr(co+1,nl-co-1)));
128 p = nl+1;
129#else /* POSTELS_LAW */
130 string::size_type lb = kv.find_first_of("\r\n",co+1);
131 if(lb==string::npos) {
132 set_field(kv.substr(p,co-p),kv.substr(co+1));
133 break;
134 }
135 if(lb>co)
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);
138 if(nolb==string::npos)
139 break;
140 p = nolb;
141#endif /* POSTELS_LAW */
142 }
143 }
144
145 void basic_openid_message::add_to_signed(const string& fields) {
146 string::size_type fnc = fields.find_first_not_of(",");
147 if(fnc==string::npos)
148 throw bad_input(OPKELE_CP_ "Trying to add nothing in particular to the list of signed fields");
149 string signeds;
150 try {
151 signeds = get_field("signed");
152 string::size_type lnc = signeds.find_last_not_of(",");
153 if(lnc==string::npos)
154 signeds.assign(fields,fnc,fields.size()-fnc);
155 else{
156 string::size_type ss = signeds.size();
157 if(lnc==(ss-1)) {
158 signeds+= ',';
159 signeds.append(fields,fnc,fields.size()-fnc);
160 }else{
161 if(lnc<(ss-2))
162 signeds.replace(lnc+2,ss-lnc-2,
163 fields,fnc,fields.size()-fnc);
164 else
165 signeds.append(fields,fnc,fields.size()-fnc);
166 }
167 }
168 }catch(failed_lookup&) {
169 signeds.assign(fields,fnc,fields.size()-fnc);
170 }
171 set_field("signed",signeds);
172 }
173
174 string basic_openid_message::find_ns(const string& uri,const char *pfx) const {
175 if(has_field("ns"))
176 return get_ns(uri);
177 return pfx;
178 }
179 string basic_openid_message::allocate_ns(const string& uri,const char *pfx) {
180 if(!has_field("ns"))
181 return pfx;
182 if(has_ns(uri))
183 throw bad_input(OPKELE_CP_ "OpenID message already contains namespace");
184 string rv = pfx;
185 if(has_field("ns."+rv)) {
186 string::reference c=rv[rv.length()];
187 for(c='a';c<='z' && has_field("ns."+rv);++c);
188 if(c=='z')
189 throw exception(OPKELE_CP_ "Failed to allocate namespace");
190 }
191 set_field("ns."+rv,uri);
192 return rv;
193 }
194
195 void openid_message_t::copy_to(basic_openid_message& x) const {
196 x.reset_fields();
197 for(const_iterator i=begin();i!=end();++i)
198 x.set_field(i->first,i->second);
199 }
200
201 bool openid_message_t::has_field(const string& n) const {
202 return find(n)!=end();
203 }
204 const string& openid_message_t::get_field(const string& n) const {
205 const_iterator i=find(n);
206 if(i==end())
207 throw failed_lookup(OPKELE_CP_ n+": no such field");
208 return i->second;
209 }
210
211 openid_message_t::fields_iterator openid_message_t::fields_begin() const {
212 return util::map_keys_iterator<const_iterator,string,const string&,const string*>(begin(),end());
213 }
214 openid_message_t::fields_iterator openid_message_t::fields_end() const {
215 return util::map_keys_iterator<const_iterator,string,const string&,const string*>(end(),end());
216 }
217
218 void openid_message_t::reset_fields() {
219 clear();
220 }
221 void openid_message_t::set_field(const string& n,const string& v) {
222 insert(value_type(n,v));
223 }
224 void openid_message_t::reset_field(const string& n) {
225 erase(n);
226 }
227
228}