1 /* zxidps.c - People Service
2 * Copyright (c) 2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3 * Copyright (c) 2010 Risaris Ltd, All Rights Reserved.
4 * Author: Sampo Kellomaki (sampo@iki.fi)
5 * This is confidential unpublished proprietary source code of the author.
6 * NO WARRANTY, not even implied warranties. Contains trade secrets.
7 * Distribution prohibited unless authorized in writing.
8 * Licensed under Apache License 2.0, see file COPYING.
9 * $Id: zxiddi.c,v 1.2 2009-11-24 23:53:40 sampo Exp $
10 *
11 * 16.9.2010, created --Sampo
12 *
13 * See also zxcall for client
14 * - liberty-idwsf-overview-v2.0.pdf sec 2.3 and 2.4 (pp.15-31) for use cases
15 * - liberty-idwsf-people-service-v1.0.pdf, sec 4.4 Elements Supporting Invitation (pp.53-57)
16 *
17 * zxcot -e http://idp.tas3.pt:8081/zxididp?o=S 'People Svc' \
18 * http://idp.tas3.pt:8081/zxididp?o=B urn:liberty:ps:2006-08 \
19 * | zxcot -b /var/zxid/idpdimd
20 */
21
22 #include "platform.h" /* for dirent.h */
23 #include "errmac.h"
24 #include "zxid.h"
25 #include "zxidpriv.h"
26 #include "zxidutil.h"
27 #include "zxidconf.h"
28 #include "saml2.h"
29 #include "wsf.h"
30 #include "c/zx-const.h"
31 #include "c/zx-ns.h"
32 #include "c/zx-data.h"
33
34 /* Called by: zxid_psobj_dec, zxid_psobj_enc */
zxid_psobj_key_setup(zxid_conf * cf,struct zx_str * eid,char * symkey)35 static int zxid_psobj_key_setup(zxid_conf* cf, struct zx_str* eid, char* symkey)
36 {
37 if (!cf->psobj_symkey[0])
38 zx_get_symkey(cf, "psobj-enc.key", cf->psobj_symkey);
39 zx_raw_digest2(cf->ctx, symkey, "SHA1", strlen(cf->psobj_symkey), cf->psobj_symkey, eid->len, eid->s);
40 return 20;
41 }
42
43 /*() Encrypt and safe_base64 encode psobj identifier for an entity.
44 *
45 * ObjectID (psobj) has particlar privacy threat in that several WSCs may
46 * see them and be able to correlate about the user that the object refers
47 * to (see brief discussion in sec 2.1.4 "<ObjectID> Element", ll.278-281,
48 * of [PeopleSvc].
49 *
50 * We adopt solution where psobj issued towards an entity (SP, WSC) is
51 * the psobj encrypted (AES-128-CBC) with key consisting of concatenation
52 * of secret (/var/zxid/pem/psobj-enc.key) known to ps server (i.e. the
53 * zxididp) and the Entity ID of the entity. */
54
55 /* Called by: zxid_mk_an_stmt, zxid_ps_addent_invite */
zxid_psobj_enc(zxid_conf * cf,struct zx_str * eid,const char * prefix,struct zx_str * psobj)56 struct zx_str* zxid_psobj_enc(zxid_conf* cf, struct zx_str* eid, const char* prefix, struct zx_str* psobj)
57 {
58 char* lim;
59 char symkey[20];
60 struct zx_str key;
61 struct zx_str* ss;
62 struct zx_str* rr;
63 int prefix_len = strlen(prefix);
64 zxid_psobj_key_setup(cf, eid, symkey);
65 key.len = 16;
66 key.s = symkey;
67 ss = zx_raw_cipher(cf->ctx, "AES-128-CBC", 1, &key, psobj->len, psobj->s, 16, 0);
68 if (!ss) {
69 ERR("Symmetric encryption failed %d", 0);
70 return 0;
71 }
72 rr = zx_new_len_str(cf->ctx, prefix_len+SIMPLE_BASE64_LEN(ss->len)+1);
73 strcpy(rr->s, prefix);
74 lim = base64_fancy_raw(ss->s, ss->len, rr->s+prefix_len, safe_basis_64, 1<<31, 0, "", '=');
75 *lim = 0;
76 rr->len = lim - rr->s;
77 zx_str_free(cf->ctx, ss);
78 return rr;
79 }
80
81 /*() Decrypt psobj identifier from an entity. */
82
83 /* Called by: zxid_idp_slo_do, zxid_ps_addent_invite */
zxid_psobj_dec(zxid_conf * cf,struct zx_str * eid,const char * prefix,struct zx_str * psobj)84 struct zx_str* zxid_psobj_dec(zxid_conf* cf, struct zx_str* eid, const char* prefix, struct zx_str* psobj)
85 {
86 char* lim;
87 char symkey[20];
88 struct zx_str key;
89 struct zx_str* ss;
90 struct zx_str* rr;
91 int prefix_len = strlen(prefix);
92 if (!eid || !psobj || psobj->len < prefix_len) {
93 ERR("Null eid or psobj, or too short psobj %p", psobj);
94 return 0;
95 }
96 if (memcmp(prefix, psobj->s, prefix_len)) {
97 ERR("psobj(%.*s) does not match prefix(%s)", psobj->len, psobj->s, prefix);
98 return 0;
99 }
100 zxid_psobj_key_setup(cf, eid, symkey);
101 key.len = 16;
102 key.s = symkey;
103 rr = zx_new_len_str(cf->ctx, SIMPLE_BASE64_PESSIMISTIC_DECODE_LEN(psobj->len));
104 lim = unbase64_raw(psobj->s+prefix_len, psobj->s+psobj->len, rr->s, zx_std_index_64);
105 rr->len = lim - rr->s;
106 ss = zx_raw_cipher(cf->ctx, "AES-128-CBC", 0, &key, rr->len-16, rr->s+16, 16, rr->s);
107 zx_str_free(cf->ctx, rr);
108 return ss;
109 }
110
111 /*() Render the linked list of delegated permissions to a string */
112
113 /* Called by: zxid_put_invite, zxid_put_psobj */
zxid_render_perms(zxid_conf * cf,struct zxid_perm * perms)114 char* zxid_render_perms(zxid_conf* cf, struct zxid_perm* perms)
115 {
116 int n, len = 0;
117 struct zxid_perm* perm;
118 char* ret;
119 char* p;
120
121 /* Length computation phase */
122
123 for (perm = perms; perm; perm = perm->n)
124 len += sizeof("perm: ")-1 + (perm->eid?perm->eid->len:0) + 1 + (perm->qs?perm->qs->len:0) + 1;
125
126 ret = p = ZX_ALLOC(cf->ctx, len+1);
127
128 /* Rendering phase */
129
130 for (perm = perms; perm; perm = perm->n) {
131 n = sprintf(p, "perm: %.*s$%.*s\n",
132 perm->eid?perm->eid->len:0, perm->eid?perm->eid->s:"",
133 perm->qs?perm->qs->len:0, perm->qs?perm->qs->s:"");
134 p += n;
135 }
136
137 ASSERTOPI(p-ret, ==, len);
138 *p = 0; /* nul terminate */
139 return ret;
140 }
141
142 /*() Render the linked list of invitation IDs to a string */
143
144 /* Called by: zxid_put_psobj x2 */
zxid_render_str_list(zxid_conf * cf,struct zx_str * strs,const char * attr_name)145 char* zxid_render_str_list(zxid_conf* cf, struct zx_str* strs, const char* attr_name)
146 {
147 int n, len = 0, atn_len = strlen(attr_name);
148 struct zx_str* str;
149 char* ret;
150 char* p;
151
152 /* Length computation phase */
153
154 for (str = strs; str; str = str->n)
155 len += atn_len + sizeof(": ")-1 + str->len + 1;
156
157 ret = p = ZX_ALLOC(cf->ctx, len+1);
158
159 /* Rendering phase */
160
161 for (str = strs; str; str = str->n) {
162 n = sprintf(p, "%s: %.*s\n", attr_name, str->len, str->s);
163 p += n;
164 }
165
166 ASSERTOPI(p-ret, ==, len);
167 *p = 0; /* nul terminate */
168 return ret;
169 }
170
171 /*() Create new invitation in file system. */
172
173 /* Called by: zxid_ps_addent_invite */
zxid_put_invite(zxid_conf * cf,struct zxid_invite * inv)174 int zxid_put_invite(zxid_conf* cf, struct zxid_invite* inv)
175 {
176 char buf[ZXID_MAX_USER];
177 char invid_c[ZXID_MAX_USER];
178 char* perms = zxid_render_perms(cf, inv->perms);
179 memcpy(invid_c, inv->invid->s, MIN(inv->invid->len, sizeof(invid_c)-1));
180 invid_c[sizeof(invid_c)-1] = 0;
181
182 write_all_path_fmt("put_inv", ZXID_MAX_USER, buf,
183 "%s" ZXID_INV_DIR "%s", cf->cpath, invid_c,
184 "dn: invid=%.*s\ninvid: %.*s\nuid: %s\ndesc: %.*s\npsobj: %.*s\nps2spredir: %.*s\nmaxusage: %d\nusage: %d\nstarts: %s\nexpires: %s\n%s\n\n",
185 inv->invid->len, inv->invid->s,
186 inv->invid->len, inv->invid->s,
187 inv->uid,
188 inv->desc?inv->desc->len:0, inv->desc?inv->desc->s:"",
189 inv->psobj?inv->psobj->len:0, inv->psobj?inv->psobj->s:"",
190 inv->ps2spredir?inv->ps2spredir->len:0, inv->ps2spredir?inv->ps2spredir->s:"",
191 inv->maxusage,
192 inv->usage,
193 zxid_date_time(cf, inv->starts),
194 zxid_date_time(cf, inv->expires),
195 STRNULLCHK(perms));
196 D("PUT INVITATION invid(%s)", invid_c);
197 return 1;
198 }
199
200 /*() Create new People Service Object in file system. */
201
202 /* Called by: zxid_ps_addent_invite */
zxid_put_psobj(zxid_conf * cf,struct zxid_psobj * obj)203 int zxid_put_psobj(zxid_conf* cf, struct zxid_psobj* obj)
204 {
205 char* buf = ZX_ALLOC(cf->ctx, ZXID_MAX_USER);
206 char* children = 0; /* *** groups and children not supported yet. */
207 char* tags = zxid_render_str_list(cf, obj->invids, "tag");
208 char* invids = zxid_render_str_list(cf, obj->invids, "invid");
209 char* perms = zxid_render_perms(cf, obj->perms);
210 obj->mod_secs = time(0);
211
212 write_all_path_fmt("put_psobj", ZXID_MAX_USER, buf,
213 "%s" ZXID_UID_DIR "%s", cf->cpath, obj->uid,
214 "dn: psobj=%.*s,uid=%s\npsobj: %.*s\nowner: %s\nidpnid: %.*s\ndispname: %.*s\nnodetype: %d\ncreated: %s\nmodified: %s\n%s%s%s%s\n\n",
215 obj->psobj->len, obj->psobj->s, obj->uid,
216 obj->psobj->len, obj->psobj->s, obj->uid,
217 obj->idpnid?obj->idpnid->len:0, obj->idpnid?obj->idpnid->s:"",
218 obj->dispname?obj->dispname->len:0, obj->dispname?obj->dispname->s:"", /* *** Should really support multiple */
219 obj->nodetype,
220 zxid_date_time(cf, obj->create_secs),
221 zxid_date_time(cf, obj->mod_secs),
222 STRNULLCHK(children),
223 STRNULLCHK(tags),
224 STRNULLCHK(invids),
225 STRNULLCHK(perms));
226 ZX_FREE(cf->ctx, buf);
227 D("PUT PSOBJ(%.*s)", obj->psobj->len, obj->psobj->s);
228 return 1;
229 }
230
231 /*() Populate psobj from LDIF. Parse LDIF format and insert attributes to struct.
232 * The input is temporarily modified and then restored. Do not pass const string. */
233
234 /* Called by: */
zxid_parse_psobj(zxid_conf * cf,struct zxid_psobj * obj,char * p,const char * lk)235 int zxid_parse_psobj(zxid_conf* cf, struct zxid_psobj* obj, char* p, const char* lk)
236 {
237 char* name;
238 char* val;
239 char* q;
240 struct zx_str* ss;
241 struct zxid_perm* perm;
242
243 for (; p; ++p) {
244 name = p;
245 p = strstr(p, ": ");
246 if (!p)
247 break;
248 *p = 0;
249 val = p+2;
250 p = strchr(val, '\n'); /* *** parsing LDIF is fragile if values are multiline */
251 if (p)
252 *p = 0;
253
254 D("%s: ATTR(%s)=VAL(%s)", lk, name, val);
255
256 switch (name[0]) {
257 case 'd':
258 if (!strcmp(name, "dn"))
259 goto next;
260 if (!strcmp(name, "dispname")) {
261 obj->dispname = zx_dup_str(cf->ctx, val);
262 goto next;
263 }
264 break;
265 case 'i':
266 if (!strcmp(name, "idpnid")) {
267 obj->idpnid = zx_dup_str(cf->ctx, val);
268 goto next;
269 }
270 if (!strcmp(name, "invid")) {
271 ss = zx_dup_str(cf->ctx, val);
272 ss->n = obj->invids;
273 obj->invids = ss;
274 goto next;
275 }
276 break;
277 case 'p':
278 if (!strcmp(name, "psobj")) {
279 obj->psobj = zx_dup_str(cf->ctx, val);
280 goto next;
281 }
282 if (!strcmp(name, "psobjref")) {
283 ERR("%s: *** Child objects not yet supported (%s: %s)", lk, name, val);
284 /*obj->child = zx_dup_str(cf->ctx, val); *** */
285 goto next;
286 }
287 if (!strcmp(name, "perm")) {
288 perm = ZX_ZALLOC(cf->ctx, struct zxid_perm);
289 q = strchr(val, '$');
290 if (q) {
291 perm->eid = zx_dup_len_str(cf->ctx, q-val, val);
292 perm->qs = zx_dup_str(cf->ctx, q);
293 } else
294 perm->eid = zx_dup_str(cf->ctx, val);
295 perm->n = obj->perms;
296 obj->perms = perm;
297 goto next;
298 }
299 break;
300 case 't':
301 if (!strcmp(name, "tag")) {
302 ss = zx_dup_str(cf->ctx, val);
303 ss->n = obj->tags;
304 obj->tags = ss;
305 goto next;
306 }
307 break;
308 case 'u':
309 if (!strcmp(name, "uid")) {
310 obj->uid = zx_dup_cstr(cf->ctx, val);
311 goto next;
312 }
313 break;
314 }
315 ERR("%s: Unknown name(%s) val(%s) in psobj LDIF file. Ignored.", lk, name, val);
316
317 next:
318 val[-2] = ':'; /* restore */
319 if (p)
320 *p = '\n';
321 else
322 break;
323 }
324 return 1;
325 }
326
327 /*() Populate invitation from LDIF. Parse LDIF format and insert attributes to struct.
328 * The input is temporarily modified and then restored. Do not pass const string. */
329
330 /* Called by: zxid_ps_accept_invite, zxid_ps_finalize_invite */
zxid_parse_invite(zxid_conf * cf,struct zxid_invite * inv,char * p,const char * lk)331 int zxid_parse_invite(zxid_conf* cf, struct zxid_invite* inv, char* p, const char* lk)
332 {
333 char* name;
334 char* val;
335 char* q;
336 struct zxid_perm* perm;
337
338 for (; p; ++p) {
339 name = p;
340 p = strstr(p, ": ");
341 if (!p)
342 break;
343 *p = 0;
344 val = p+2;
345 p = strchr(val, '\n'); /* *** parsing LDIF is fragile if values are multiline */
346 if (p)
347 *p = 0;
348
349 D("%s: ATTR(%s)=VAL(%s)", lk, name, val);
350
351 switch (name[0]) {
352 case 'd':
353 if (!strcmp(name, "dn"))
354 goto next;
355 if (!strcmp(name, "desc")) {
356 inv->desc = zx_dup_str(cf->ctx, val);
357 goto next;
358 }
359 break;
360 case 'e':
361 if (!strcmp(name, "expires")) {
362 inv->expires = zx_date_time_to_secs(val);
363 goto next;
364 }
365 break;
366 case 'i':
367 if (!strcmp(name, "invid")) {
368 inv->invid = zx_dup_str(cf->ctx, val);
369 goto next;
370 }
371 break;
372 case 'm':
373 if (!strcmp(name, "maxusage")) {
374 sscanf(val, "%i", &inv->maxusage);
375 goto next;
376 }
377 break;
378 case 'p':
379 if (!strcmp(name, "psobj")) {
380 inv->psobj = zx_dup_str(cf->ctx, val);
381 goto next;
382 }
383 if (!strcmp(name, "ps2spredir")) {
384 inv->ps2spredir = zx_dup_str(cf->ctx, val);
385 goto next;
386 }
387 if (!strcmp(name, "perm")) {
388 perm = ZX_ZALLOC(cf->ctx, struct zxid_perm);
389 q = strchr(val, '$');
390 if (q) {
391 perm->eid = zx_dup_len_str(cf->ctx, q-val, val);
392 perm->qs = zx_dup_str(cf->ctx, q);
393 } else
394 perm->eid = zx_dup_str(cf->ctx, val);
395 perm->n = inv->perms;
396 inv->perms = perm;
397 goto next;
398 }
399 break;
400 case 's':
401 if (!strcmp(name, "starts")) {
402 inv->starts = zx_date_time_to_secs(val);
403 goto next;
404 }
405 break;
406 case 'u':
407 if (!strcmp(name, "uid")) {
408 inv->uid = zx_dup_cstr(cf->ctx, val);
409 goto next;
410 }
411 if (!strcmp(name, "usage")) {
412 sscanf(val, "%i", &inv->usage);
413 goto next;
414 }
415 break;
416 }
417 ERR("%s: Unknown name(%s) val(%s) in invite LDIF file. Ignored.", lk, name, val);
418
419 next:
420 val[-2] = ':'; /* restore */
421 if (p)
422 *p = '\n';
423 else
424 break;
425 }
426 return 1;
427 }
428
429 /*() Accept an invitation. Process a URL of form https://idp.tas3.pt/zxididp?o=D&inv=i123431
430 * Both logged in and not yet logged in cases are possible. */
431
432 /* Called by: zxid_simple_no_ses_cf, zxid_simple_ses_active_cf */
zxid_ps_accept_invite(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses,int * res_len,int auto_flags)433 char* zxid_ps_accept_invite(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, int* res_len, int auto_flags)
434 {
435 int now = time(0);
436 struct zxid_invite inv;
437 char buf[ZXID_MAX_BUF];
438 int got = read_all(sizeof(buf), buf, "accept_invite", 1, "%s" ZXID_INV_DIR "%s",cf->cpath,cgi->inv);
439 if (!got) {
440 ERR("Invitation not found(%s)", cgi->inv);
441 cgi->err = "Invitation not found.";
442 return zxid_simple_show_err(cf, cgi, res_len, auto_flags);
443 }
444 zxid_parse_invite(cf, &inv, buf, "accept_invite");
445 if (inv.maxusage <= inv.usage) {
446 ERR("Invitation(%s) has already been used (max_usage=%d, usage=%d)", cgi->inv, inv.maxusage, inv.usage);
447 cgi->err = "Invitation has already been used.";
448 return zxid_simple_show_err(cf, cgi, res_len, auto_flags);
449 }
450 if (inv.starts > now) {
451 ERR("Invitation(%s) is not active yet (starts=%d, now=%d)", cgi->inv, inv.starts, now);
452 cgi->err = "Invitation is not active yet.";
453 return zxid_simple_show_err(cf, cgi, res_len, auto_flags);
454 }
455 if (inv.expires <= now) {
456 ERR("Invitation(%s) has expired (expire=%d, now=%d)", cgi->inv, inv.expires, now);
457 cgi->err = "Invitation has expired.";
458 return zxid_simple_show_err(cf, cgi, res_len, auto_flags);
459 }
460
461 cgi->msg = "This screen aims to complete the invitation process you started by clicking on the invitation link. Once completed, you will be redirected to the web site where the delegated resource is available. To complete invitation, People Service needs to authenticate you with your Identity Provider (IdP). Please choose your Identity Provider from popup menu (or enter the IdP URL in the space provided) and click Login.";
462
463 cgi->rs = zx_alloc_sprintf(cf->ctx, 0, "o=G&inv=%s", cgi->inv);
464 return zxid_simple_show_idp_sel(cf, cgi, res_len, auto_flags);
465 }
466
467 /*() Finalize an invitation. This function is invoked after zxid_ps_accept_invite() (o=D)
468 * when user is returning from IdP, by way of o=G placed in RelayState. */
469
470 /* Called by: zxid_simple_ses_active_cf */
zxid_ps_finalize_invite(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses,int * res_len,int auto_flags)471 char* zxid_ps_finalize_invite(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, int* res_len, int auto_flags)
472 {
473 int now = time(0);
474 struct zxid_invite inv;
475 char buf[ZXID_MAX_BUF];
476 int got = read_all(sizeof(buf), buf, "finalize_invite", 1, "%s" ZXID_INV_DIR "%s",cf->cpath,cgi->inv);
477 if (!got) {
478 ERR("Invitation not found(%s)", cgi->inv);
479 cgi->err = "Invitation not found.";
480 return zxid_simple_show_err(cf, cgi, res_len, auto_flags);
481 }
482 zxid_parse_invite(cf, &inv, buf, "accept_invite");
483 if (inv.maxusage <= inv.usage) {
484 ERR("Invitation(%s) has already been used (max_usage=%d, usage=%d)", cgi->inv, inv.maxusage, inv.usage);
485 cgi->err = "Invitation has already been used.";
486 return zxid_simple_show_err(cf, cgi, res_len, auto_flags);
487 }
488 if (inv.starts > now) {
489 ERR("Invitation(%s) is not active yet (starts=%d, now=%d)", cgi->inv, inv.starts, now);
490 cgi->err = "Invitation is not active yet.";
491 return zxid_simple_show_err(cf, cgi, res_len, auto_flags);
492 }
493 if (inv.expires <= now) {
494 ERR("Invitation(%s) has expired (expire=%d, now=%d)", cgi->inv, inv.expires, now);
495 cgi->err = "Invitation has expired.";
496 return zxid_simple_show_err(cf, cgi, res_len, auto_flags);
497 }
498
499 cgi->msg = "This screen aims to complete the invitation process you started by clicking on the invitation link. Once completed, you will be redirected to the web site where the delegated resource is available. To complete invitation, People Service needs to authenticate you with your Identity Provider (IdP). Please choose your Identity Provider from popup menu (or enter the IdP URL in the space provided) and click Login.";
500
501 cgi->rs = zx_alloc_sprintf(cf->ctx, 0, "o=G&inv=%s", cgi->inv);
502 return zxid_simple_show_idp_sel(cf, cgi, res_len, auto_flags);
503 }
504
505 /*() Add an entity to buddy store and obtain an invitation token.
506 * In fact this call just adds the invitation as we can not know
507 * who will respond to the invitation. The actual object will be
508 * created in zxid_ps_accept_invite(). If object repesenting the
509 * user already exists, that will be reused. Otherwise new
510 * object will be created.
511 * The permissions are expected to be passed in as special
512 * tag "perm". */
513
514 /* Called by: zxid_sp_soap_dispatch */
zxid_ps_addent_invite(zxid_conf * cf,zxid_ses * ses,struct zx_ps_AddEntityRequest_s * req)515 struct zx_ps_AddEntityResponse_s* zxid_ps_addent_invite(zxid_conf* cf, zxid_ses* ses, struct zx_ps_AddEntityRequest_s* req)
516 {
517 struct zx_str* tag;
518 struct zx_ps_AddEntityResponse_s* resp = zx_NEW_ps_AddEntityResponse(cf->ctx,0);
519 struct zxid_invite* inv;
520 struct zxid_psobj* obj;
521 char uid[ZXID_MAX_USER];
522 D_INDENT("ps_inv: ");
523
524 if (!req || !req->Object) {
525 ERR("Malformed request (%p): Object missing.", req);
526 resp->Status = zxid_mk_lu_Status(cf, &resp->gg, "Fail", 0, 0, 0);
527 D_DEDENT("ps_inv: ");
528 return resp;
529 }
530
531 if (!zxid_idp_map_nid2uid(cf, sizeof(uid), uid, ses->tgtnameid, &resp->Status)) {
532 D_DEDENT("ps_inv: ");
533 return resp;
534 }
535
536 inv = ZX_ZALLOC(cf->ctx, struct zxid_invite);
537 inv->invid = zxid_mk_id(cf, "i", 48); /* What is secure and sufficient space? */
538 inv->uid = uid;
539 inv->maxusage = 1;
540 inv->starts = time(0);
541 inv->expires = time(0) + 86400 * 30; /* *** make configurable (about a month) */
542 inv->ps2spredir = ZX_GET_CONTENT(req->PStoSPRedirectURL);
543 inv->perms = ZX_ZALLOC(cf->ctx, struct zxid_perm);
544 inv->perms->eid = ses->issuer;
545
546 obj = ZX_ZALLOC(cf->ctx, struct zxid_psobj);
547 #if 0
548 obj->psobj = req->Object->ObjectID ? zxid_psobj_dec(cf, ses->issuer, "ZO", req->Object->ObjectID) : zxid_mk_id(cf, "o", 48); /* What is secure and sufficient space? */
549 #else
550 if (req->Object->ObjectID) {
551 ERR("AddEntityRequest contained ObjectID(%.*s), but AddEntity is about creating new objects and the object IDs are assigned by People Service, not client. Ignoring ObjectID.", ZX_GET_CONTENT_LEN(req->Object->ObjectID), ZX_GET_CONTENT_S(req->Object->ObjectID));
552 }
553 obj->psobj = zxid_mk_id(cf, "o", 48); /* What is secure and sufficient space? */
554 #endif
555 obj->uid = uid;
556 obj->dispname = ZX_GET_CONTENT(req->Object->DisplayName);
557 obj->tags = ZX_GET_CONTENT(req->Object->Tag);
558 obj->invids = inv->invid;
559 obj->create_secs = time(0);
560
561 inv->psobj = obj->psobj;
562 zxid_put_invite(cf, inv);
563 zxid_put_psobj(cf, obj);
564
565 /* The invitation URL will be processed by zxid_ps_accept_invite(), see above. */
566 resp->SPtoPSRedirectURL
567 = zx_new_str_elem(cf->ctx, &resp->gg, zx_ps_SPtoPSRedirectURL_ELEM,
568 zx_strf(cf->ctx, "%s?o=D&inv=%.*s", cf->burl, inv->invid->len, inv->invid->s));
569 resp->Object = zx_NEW_ps_Object(cf->ctx, &resp->gg);
570 resp->Object->ObjectID = zx_new_str_elem(cf->ctx, &resp->Object->gg, zx_ps_ObjectID_ELEM, zxid_psobj_enc(cf, ses->issuer, "ZO", obj->psobj));
571 resp->Object->DisplayName = zx_NEW_ps_DisplayName(cf->ctx, &resp->Object->gg);
572 zx_add_content(cf->ctx, &resp->Object->DisplayName->gg, obj->dispname);
573 resp->Object->DisplayName->Locale = zx_ref_attr(cf->ctx, &resp->Object->DisplayName->gg, zx_Locale_ATTR, "xx"); /* unknown locale */
574 for (tag = obj->tags; tag; tag = tag->n) {
575 resp->Object->Tag = zx_NEW_ps_Tag(cf->ctx, &resp->Object->gg);
576 zx_add_content(cf->ctx, &resp->Object->Tag->gg, tag);
577 }
578 resp->Object->NodeType = zx_ref_attr(cf->ctx, &resp->Object->gg, zx_NodeType_ATTR, obj->nodetype?PS_COL:PS_ENT);
579 resp->Object->CreatedDateTime = zxid_date_time_attr(cf, &resp->Object->gg, zx_CreatedDateTime_ATTR, obj->create_secs);
580 resp->Object->ModifiedDateTime = zxid_date_time_attr(cf, &resp->Object->gg, zx_TimeStamp_ATTR, obj->mod_secs);
581 resp->TimeStamp = resp->Object->CreatedDateTime;
582 resp->id = zx_ref_len_attr(cf->ctx, &resp->gg, zx_id_ATTR, inv->invid->len, inv->invid->s); /* *** why is ID requred by schema at all? */
583 resp->Status = zxid_mk_lu_Status(cf, &resp->gg, "OK", 0, 0, 0);
584 zxlogwsp(cf, ses, "K", "PSINV", 0, "inv=%.*s", inv->invid->len, inv->invid->s);
585 D_DEDENT("ps_inv: ");
586 return resp;
587 }
588
589 /*() Resolve an invitation token to identity */
590
591 /* Called by: zxid_sp_soap_dispatch */
zxid_ps_resolv_id(zxid_conf * cf,zxid_ses * ses,struct zx_ps_ResolveIdentifierRequest_s * req)592 struct zx_ps_ResolveIdentifierResponse_s* zxid_ps_resolv_id(zxid_conf* cf, zxid_ses* ses, struct zx_ps_ResolveIdentifierRequest_s* req)
593 {
594 struct zx_ps_ResolveIdentifierResponse_s* resp = zx_NEW_ps_ResolveIdentifierResponse(cf->ctx,0);
595 struct zx_ps_ResolveInput_s* inp;
596 //struct zx_ps_ResolveOutput_s* out;
597 int n_resolv = 0;
598 char uid[ZXID_MAX_USER];
599 D_INDENT("ps_resolv: ");
600
601 //resp->ID = zxid_mk_id(cf, "DIR", ZXID_ID_BITS);
602
603 if (!zxid_idp_map_nid2uid(cf, sizeof(uid), uid, ses->tgtnameid, &resp->Status)) {
604 D_DEDENT("ps_resolv: ");
605 return resp;
606 }
607
608 for (inp = req->ResolveInput;
609 inp && inp->gg.g.tok == zx_ps_ResolveInput_ELEM;
610 inp = (struct zx_ps_ResolveInput_s*)inp->gg.g.n) {
611 // ***
612 }
613
614 resp->Status = zxid_mk_lu_Status(cf, &resp->gg, "OK", 0, 0, 0);
615 zxlogwsp(cf, ses, "K", "PSRESOLVOK", 0, "n=%d", n_resolv);
616 D_DEDENT("ps_resolv: ");
617 return resp;
618 }
619
620 /* EOF -- zxidps.c */
621