1 /* zxidim.c - Identity Mapping 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-authn-svc-v2.0.pdf sec 7 "Identity Mapping Service"
15 *
16 * zxcot -e http://idp.tas3.pt:8081/zxididp?o=S 'IDMap Svc' \
17 * http://idp.tas3.pt:8081/zxididp?o=B urn:liberty:ims:2006-08 \
18 * | zxcot -b /var/zxid/idpdimd
19 *
20 * [SOAPAuthn2] "Liberty ID-WSF Authentication, Single Sign-On, and Identity Mapping Services Specification", liberty-idwsf-authn-svc-2.0-errata-v1.0.pdf from http://projectliberty.org/resource_center/specifications/
21 */
22
23 #include "platform.h" /* for dirent.h */
24 #include "errmac.h"
25 #include "zxid.h"
26 #include "zxidpriv.h"
27 #include "zxidutil.h"
28 #include "zxidconf.h"
29 #include "saml2.h"
30 #include "wsf.h"
31 #include "c/zx-const.h"
32 #include "c/zx-ns.h"
33 #include "c/zx-data.h"
34
35 /*() ID-WSF Single Sign-On Service (SSOS): Issue SSO assertion in response to receiving a token.
36 * See also zxid_idp_sso() for similar code. */
37
38 /* Called by: a7n_test, zxid_sp_soap_dispatch */
zxid_ssos_anreq(zxid_conf * cf,zxid_ses * ses,struct zx_sp_AuthnRequest_s * ar)39 struct zx_sp_Response_s* zxid_ssos_anreq(zxid_conf* cf, zxid_ses* ses, struct zx_sp_AuthnRequest_s* ar)
40 {
41 zxid_a7n* outa7n;
42 X509* sign_cert;
43 EVP_PKEY* sign_pkey;
44 struct zxsig_ref refs;
45 zxid_cgi cgi;
46 char logop[8];
47 struct zx_sp_Response_s* resp = zx_NEW_sp_Response(cf->ctx,0);
48 struct zx_str* payload;
49 struct zx_str* ss;
50 zxid_entity* sp_meta;
51 char uid[ZXID_MAX_BUF];
52 strcpy(logop, "xxxANyy");
53 D_INDENT("ssos: ");
54
55 if (!ar || !ZX_GET_CONTENT(ar->Issuer)) {
56 ERR("No Issuer found in AuthnRequest %p", ar);
57 resp->Status = zxid_mk_Status(cf, &resp->gg, "Fail", 0, 0);
58 D_DEDENT("ssos: ");
59 return resp;
60 }
61
62 if (!zxid_idp_map_nid2uid(cf, sizeof(uid), uid, ses->tgtnameid, 0)) {
63 resp->Status = zxid_mk_Status(cf, &resp->gg, "Fail", 0, 0);
64 D_DEDENT("ssos: ");
65 return resp;
66 }
67
68 ZERO(&cgi, sizeof(cgi));
69 ses->an_instant = time(0); /* This will be later used by AuthnStatement constructor. */
70 ses->an_ctx = SAML_AUTHCTX_PREVSESS; /* Is there better one to use for token based auth? */
71 ss = zxid_mk_id(cf, "OSES", ZXID_ID_BITS); /* Onetime Master session. Each pairwise SSO should have its own to avoid correlation. The session can not be used for SLO. */
72 ses->sesix = ss->s;
73 ZX_FREE(cf->ctx, ss);
74 ses->sid = cgi.sid = ses->sesix;
75 cgi.uid = uid;
76 ses->uid = cgi.uid;
77 /*zxid_put_ses(cf, ses);*/
78
79 sp_meta = zxid_get_ent_ss(cf, ZX_GET_CONTENT(ar->Issuer));
80 if (!sp_meta) {
81 ERR("The metadata for Issuer of the AuthnRequest could not be found or fetched %d", 0);
82 resp->Status = zxid_mk_Status(cf, &resp->gg, "Fail", 0, 0);
83 D_DEDENT("ssos: ");
84 return resp;
85 }
86 D("sp_eid(%s)", sp_meta->eid);
87
88 outa7n = zxid_sso_issue_a7n(cf, &cgi, ses, &ses->srcts, sp_meta, 0, 0, logop, ar);
89
90 if (cf->sso_sign & ZXID_SSO_SIGN_A7N) {
91 ZERO(&refs, sizeof(refs));
92 refs.id = &outa7n->ID->g;
93 refs.canon = zx_easy_enc_elem_sig(cf, &outa7n->gg);
94 if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert paos")) {
95 outa7n->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey, cf->xmldsig_sig_meth, cf->xmldsig_digest_algo);
96 zx_add_kid_after_sa_Issuer(&outa7n->gg, &outa7n->Signature->gg);
97 }
98 }
99 resp = zxid_mk_saml_resp(cf, outa7n, cf->post_a7n_enc?sp_meta:0);
100 payload = zxid_anoint_sso_resp(cf, cf->sso_sign & ZXID_SSO_SIGN_RESP, resp, ar);
101 if (!payload) {
102 resp->Status = zxid_mk_Status(cf, &resp->gg, "Fail", 0, 0);
103 D_DEDENT("ssos: ");
104 return resp;
105 }
106 zx_str_free(cf->ctx, payload);
107
108 zxlogwsp(cf, ses, "K", logop, uid, "SSOS");
109
110 /* *** Generate SOAP envelope with ECP header as required by ECP PAOS */
111
112 D_DEDENT("ssos: ");
113 return resp;
114 }
115
116 /*(i) Use Liberty ID-WSF 2.0 Identity Mapping Service to convert
117 * the identity of the session to identity token in the namespace
118 * of the entity at_eid.
119 *
120 * This is the main work horse for WSCs wishing to call WSPs via EPR.
121 *
122 * cf:: ZXID configuration object, also used for memory allocation
123 * ses:: Session object in whose EPR cache the file will be searched
124 * at_eid:: EntityID of the destination namespace
125 * how:: How to make mapping (0 = invocaction identity, 1 = target identity)
126 * return:: 0 on failure, token on success
127 *
128 * This will generate <im:IdentityMappingRequest> in SOAP envelope to the
129 * IM service of the user, as discovered dynamically. For the discovery to work,
130 * the service must have been provisioned to the discovery, with command
131 * similar to
132 *
133 * zxcot -e http://idp.tas3.pt:8081/zxididp?o=S 'IDMap Svc' \
134 * http://idp.tas3.pt:8081/zxididp?o=B urn:liberty:ims:2006-08 \
135 * | zxcot -b /var/zxid/idpdimd
136 *
137 * The received identity token is stored in session. From there it is usually
138 * automatically used in appropriate context (see the how argument). Typically
139 * you would not use the return value for anything else than checking for an error.
140 */
141
142 /* Called by: zxcall_main */
zxid_map_identity_token(zxid_conf * cf,zxid_ses * ses,const char * at_eid,int how)143 zxid_tok* zxid_map_identity_token(zxid_conf* cf, zxid_ses* ses, const char* at_eid, int how)
144 {
145 struct zx_e_Envelope_s* env;
146 struct zx_im_MappingInput_s* inp;
147 struct zx_im_MappingOutput_s* out;
148 zxid_epr* epr;
149 epr = zxid_get_epr(cf, ses, XMLNS_IMS, 0, 0, 0, 1);
150 if (!epr) {
151 ERR("No Identity Mapping Service discovered svc(%s) how=%d", STRNULLCHK(at_eid), how);
152 return 0;
153 }
154
155 INFO("Identity Mapping Svc svc(%s) how=%d...", STRNULLCHK(at_eid), how);
156 env = zx_NEW_e_Envelope(cf->ctx,0);
157 env->Body = zx_NEW_e_Body(cf->ctx, &env->gg);
158 env->Header = zx_NEW_e_Header(cf->ctx, &env->gg);
159 env->Body->IdentityMappingRequest = zx_NEW_im_IdentityMappingRequest(cf->ctx, &env->Body->gg);
160 env->Body->IdentityMappingRequest->MappingInput = inp = zx_NEW_im_MappingInput(cf->ctx, &env->Body->IdentityMappingRequest->gg);
161 //inp->Token = zx_NEW_sec_Token(cf->ctx, &inp->gg);
162 //inp->Token->ref = zx_dup_str(cf->ctx, "#A7N");
163 inp->TokenPolicy = zx_NEW_sec_TokenPolicy(cf->ctx, &inp->gg);
164 inp->TokenPolicy->type = zx_dup_attr(cf->ctx, &inp->TokenPolicy->gg, zx_type_ATTR, TOKNUSG_SEC);
165 #if 0 /* Default is true anyway */
166 inp->TokenPolicy->wantDSEPR = zx_dup_attr(cf->ctx, &inp->TokenPolicy->gg, zx_wantDSEPR_ATTR, "1");
167 #endif
168 inp->TokenPolicy->NameIDPolicy = zx_NEW_sp_NameIDPolicy(cf->ctx, &inp->TokenPolicy->gg);
169 inp->TokenPolicy->NameIDPolicy->Format = zx_ref_attr(cf->ctx, &inp->TokenPolicy->NameIDPolicy->gg, zx_Format_ATTR, zxid_saml2_map_nid_fmt("prstnt"));
170 inp->TokenPolicy->NameIDPolicy->SPNameQualifier = zx_dup_attr(cf->ctx, &inp->TokenPolicy->NameIDPolicy->gg, zx_SPNameQualifier_ATTR, at_eid);
171 inp->TokenPolicy->NameIDPolicy->AllowCreate = zx_ref_attr(cf->ctx, &inp->TokenPolicy->NameIDPolicy->gg, zx_AllowCreate_ATTR, XML_TRUE); /* default false */
172
173 env = zxid_wsc_call(cf, ses, epr, env, 0);
174 if (!env || env == (void*)ZXID_REDIR_OK || !env->Body) {
175 ERR("Identity Mapping call failed envelope=%p", env);
176 return 0;
177 }
178 if (!env->Body->IdentityMappingResponse) {
179 ERR("No Identity Mapping Response at_eid(%s)", STRNULLCHK(at_eid));
180 return 0;
181 }
182
183 for (out = env->Body->IdentityMappingResponse->MappingOutput;
184 out;
185 out = (void*)ZX_NEXT(out)) {
186 if (out->gg.g.tok != zx_im_MappingOutput_ELEM)
187 continue;
188 switch (how) {
189 case 0:
190 D("Invocation token set %p", out->Token);
191 ses->call_invoktok = out->Token;
192 break;
193 case 1:
194 D("Target Identity token set %p", out->Token);
195 ses->call_tgttok = out->Token;
196 break;
197 }
198 return out->Token; /* Not really iterating */
199 }
200 return 0; /* never reached */
201 }
202
203 /*() ID-WSF Identity Mapping Service: Issue token in response to receiving a token */
204
205 /* Called by: zxid_sp_soap_dispatch */
zxid_imreq(zxid_conf * cf,zxid_ses * ses,struct zx_im_IdentityMappingRequest_s * req)206 struct zx_im_IdentityMappingResponse_s* zxid_imreq(zxid_conf* cf, zxid_ses* ses, struct zx_im_IdentityMappingRequest_s* req)
207 {
208 struct zx_im_IdentityMappingResponse_s* resp = zx_NEW_im_IdentityMappingResponse(cf->ctx,0);
209 struct zx_im_MappingInput_s* mapinp;
210 struct zx_im_MappingOutput_s* mapout;
211 zxid_tok* tok;
212 zxid_a7n* ina7n;
213 zxid_a7n* outa7n;
214 struct zx_str* issue_to;
215 char allow_create;
216 char* nid_fmt;
217 zxid_nid* nameid;
218 char* logop;
219 int n_mapped = 0;
220 zxid_entity* sp_meta;
221 char sp_name_buf[1024];
222 char uid[ZXID_MAX_BUF];
223 D_INDENT("imreq: ");
224 ses->uid = uid;
225
226 if (!req || !req->MappingInput) {
227 ERR("No IdentityMappingRequest/MappingInput found (WSC error) %p", req);
228 resp->Status = zxid_mk_lu_Status(cf, &resp->gg, "Fail", 0, 0, 0);
229 D_DEDENT("imreq: ");
230 return resp;
231 }
232
233 for (mapinp = req->MappingInput;
234 mapinp;
235 mapinp = (struct zx_im_MappingInput_s*)mapinp->gg.g.n) {
236 if (mapinp->gg.g.tok != zx_im_MappingInput_ELEM)
237 continue;
238
239 if (tok = mapinp->Token) {
240 if (tok->Assertion || tok->EncryptedAssertion) {
241 ina7n = zxid_dec_a7n(cf, tok->Assertion, tok->EncryptedAssertion);
242 if (!ina7n || !ina7n->Subject) {
243 ERR("Missing or malformed MappingInput/Token/Assertion %p", ina7n);
244 continue;
245 }
246 ses->tgtnameid = zxid_decrypt_nameid(cf, ina7n->Subject->NameID, ina7n->Subject->EncryptedID);
247 } else if (tok->ref && !zx_str_cmp(&tok->ref->g, &ses->a7n->ID->g)) {
248 D("Token->ref(%.*s) matches invocation security token.", tok->ref->g.len, tok->ref->g.s);
249 /* N.B. This is a common optimization as it often happens that invoker (delegatee) needs to
250 * IDMap his own token, while delegator's token can usually be found using discovery. */
251 ina7n = ses->a7n;
252 } else {
253 ERR("*** Missing IdentityMappingRequest/MappingInput/Token/(Encrypted)Assertion (WSC error). Using invocation identity instead. %p", tok);
254 ina7n = ses->a7n;
255 }
256 } else {
257 ERR("*** Missing IdentityMappingRequest/MappingInput/Token (WSC error). Using invocation identity instead. %d", 0);
258 ina7n = ses->a7n;
259 }
260
261 if (!mapinp->TokenPolicy) {
262 ERR("Missing TokenPolicy. %d", 0);
263 resp->Status = zxid_mk_lu_Status(cf, &resp->gg, "Fail", 0, 0, 0);
264 D_DEDENT("imreq: ");
265 return resp;
266 }
267
268 if (!zxid_idp_map_nid2uid(cf, sizeof(uid), uid, ses->tgtnameid, &resp->Status)) {
269 D_DEDENT("imreq: ");
270 return resp;
271 }
272
273 /* Figure out destination */
274
275 if (mapinp->TokenPolicy->NameIDPolicy) {
276 issue_to = &mapinp->TokenPolicy->NameIDPolicy->SPNameQualifier->g;
277 nid_fmt = ZX_STR_EQ(&mapinp->TokenPolicy->NameIDPolicy->Format->g, SAML2_TRANSIENT_NID_FMT) ? "trnsnt" : "prstnt";
278 allow_create = XML_TRUE_TEST(&mapinp->TokenPolicy->NameIDPolicy->AllowCreate->g) ? '1':'0';
279 } else {
280 issue_to = &mapinp->TokenPolicy->issueTo->g;
281 nid_fmt = "prstnt";
282 allow_create = '1';
283 }
284
285 if (!issue_to) {
286 ERR("No NameIDPolicy->SPNameQualifier or issueTo %p", mapinp->TokenPolicy);
287 resp->Status = zxid_mk_lu_Status(cf, &resp->gg, "Fail", 0, 0, 0);
288 D_DEDENT("imreq: ");
289 return resp;
290 }
291 zxid_nice_sha1(cf, sp_name_buf, sizeof(sp_name_buf), issue_to, issue_to, 7);
292
293 /* Check for federation */
294
295 nameid = zxid_check_fed(cf, issue_to, uid, allow_create, 0, 0, 0, sp_name_buf);
296 if (nameid) {
297 if (nid_fmt && !strcmp(nid_fmt, "trnsnt")) {
298 D("Despite old fed, using transient due to nid_fmt(%s)", STRNULLCHKD(nid_fmt));
299 zxid_mk_transient_nid(cf, nameid, sp_name_buf, uid);
300 logop = "ITIM";
301 } else
302 logop = "IFIM";
303 } else {
304 D("No nameid (because of no federation), using transient %d", 0);
305 nameid = zx_NEW_sa_NameID(cf->ctx,0);
306 zxid_mk_transient_nid(cf, nameid, sp_name_buf, uid);
307 logop = "ITIM";
308 }
309
310 /* Issue the assertion and sign it. */
311
312 sp_meta = zxid_get_ent_ss(cf, issue_to);
313 if (!sp_meta) {
314 ERR("The metadata for provider could not be found or fetched. Reject. %d", 0);
315 resp->Status = zxid_mk_lu_Status(cf, &resp->gg, "Fail", 0, 0, 0);
316 D_DEDENT("imreq: ");
317 return resp;
318 }
319
320 outa7n = zxid_mk_usr_a7n_to_sp(cf, ses, nameid, sp_meta, sp_name_buf, 1);
321
322 if (!zxid_anoint_a7n(cf, cf->sso_sign & ZXID_SSO_SIGN_A7N, outa7n, issue_to, "IMA7N", uid,0)) {
323 resp->Status = zxid_mk_lu_Status(cf, &resp->gg, "Fail", 0, 0, 0);
324 D_DEDENT("imreq: ");
325 return resp;
326 }
327
328 /* Formulate mapping output */
329
330 resp->MappingOutput = mapout = zx_NEW_im_MappingOutput(cf->ctx, &resp->gg);
331 if (mapinp->reqID && mapinp->reqID->g.len && mapinp->reqID->g.s)
332 mapout->reqRef = zx_dup_len_attr(cf->ctx, &mapout->gg, zx_reqRef_ATTR, mapinp->reqID->g.len, mapinp->reqID->g.s);
333 mapout->Token = zx_NEW_sec_Token(cf->ctx, &mapout->gg);
334 if (cf->di_a7n_enc) {
335 mapout->Token->EncryptedAssertion = zxid_mk_enc_a7n(cf, &mapout->Token->gg, outa7n, sp_meta);
336 } else {
337 zx_add_kid(&mapout->Token->gg, &outa7n->gg);
338 mapout->Token->Assertion = outa7n;
339 }
340
341 ++n_mapped;
342 zxlogwsp(cf, ses, "K", logop, 0,"n=%d", n_mapped);
343 }
344
345 D("TOTAL Identity Mappings issued %d", n_mapped);
346 zxlogwsp(cf, ses, "K", "IMOK", 0, "n=%d", n_mapped);
347 resp->Status = zxid_mk_lu_Status(cf, &resp->gg, "OK", 0, 0, 0);
348 D_DEDENT("imreq: ");
349 return resp;
350 }
351
352 /*(i) Use SAML 2.0 NameID Mapping Service to convert
353 * the identity of the session to identity token in the namespace
354 * of the entity at_eid.
355 *
356 * cf:: ZXID configuration object, also used for memory allocation
357 * ses:: Session object in whose EPR cache the file will be searched
358 * at_eid:: EntityID of the destination namespace
359 * how:: How to make mapping (0 = invocaction identity, 1 = target identity)
360 * return:: 0 on failure, token on success
361 *
362 * This will generate <im:IdentityMappingRequest> in SOAP envelope to the
363 * IM service of the user, as discovered dynamically. For the discovery to work,
364 * the service must have been provisioned to the discovery, with command
365 * similar to
366 *
367 * zxcot -e http://idp.tas3.pt:8081/zxididp?o=S 'IDMap Svc' \
368 * http://idp.tas3.pt:8081/zxididp?o=B urn:liberty:ims:2006-08 \
369 * | zxcot -b /var/zxid/idpdimd
370 *
371 * The received identity token is stored in session. From there it is usually
372 * automatically used in appropriate context (see the how argument). Typically
373 * you would not use the return value for anything else than checking for an error.
374 */
375
376 /* Called by: zxcall_main */
zxid_nidmap_identity_token(zxid_conf * cf,zxid_ses * ses,const char * at_eid,int how)377 zxid_tok* zxid_nidmap_identity_token(zxid_conf* cf, zxid_ses* ses, const char* at_eid, int how)
378 {
379 struct zx_e_Envelope_s* env;
380 struct zx_sec_Token_s* tok;
381 struct zx_sp_NameIDMappingRequest_s* req;
382 zxid_epr* epr;
383 epr = zxid_get_epr(cf, ses, XMLNS_IMS, 0, 0, 0, 1);
384 if (!epr) {
385 ERR("No Identity Mapping Service discovered svc(%s) how=%d", STRNULLCHK(at_eid), how);
386 return 0;
387 }
388
389 INFO("NID Mapping svc(%s) how=%d...", STRNULLCHK(at_eid), how);
390 env = zx_NEW_e_Envelope(cf->ctx,0);
391 env->Body = zx_NEW_e_Body(cf->ctx, &env->gg);
392 env->Header = zx_NEW_e_Header(cf->ctx, &env->gg);
393 env->Body->NameIDMappingRequest = req = zx_NEW_sp_NameIDMappingRequest(cf->ctx, &env->Body->gg);
394
395 req->NameIDPolicy = zx_NEW_sp_NameIDPolicy(cf->ctx, &req->gg);
396 req->NameIDPolicy->Format = zx_ref_attr(cf->ctx, &req->NameIDPolicy->gg, zx_Format_ATTR, zxid_saml2_map_nid_fmt("prstnt"));
397 req->NameIDPolicy->SPNameQualifier = zx_dup_attr(cf->ctx, &req->NameIDPolicy->gg, zx_SPNameQualifier_ATTR, at_eid);
398 req->NameIDPolicy->AllowCreate = zx_ref_attr(cf->ctx, &req->NameIDPolicy->gg, zx_AllowCreate_ATTR, XML_TRUE); /* default false */
399
400 req->NameID = ses->nameid; /* or tgtnameid? */
401
402 env = zxid_wsc_call(cf, ses, epr, env, 0);
403 if (!env || env == (void*)ZXID_REDIR_OK || !env->Body) {
404 ERR("Identity Mapping call failed envelope=%p", env);
405 return 0;
406 }
407 if (!env->Body->NameIDMappingResponse) {
408 ERR("No Identity Mapping Response at_eid(%s)", STRNULLCHK(at_eid));
409 return 0;
410 }
411
412 tok = zx_NEW_sec_Token(cf->ctx, 0);
413 if (env->Body->NameIDMappingResponse->NameID) {
414 ERR("*** NOT IMPLEMENTED NameIDMappingResponse has NameID %p", tok);
415
416 } else if (env->Body->NameIDMappingResponse->EncryptedID) {
417 ERR("*** NOT IMPLEMENTED NameIDMappingResponse has EncryptedID %p", tok);
418
419 } else {
420 ERR("NameIDMappingResponse did not contain any ID %p", tok);
421 return 0;
422 }
423
424 switch (how) {
425 case 0:
426 D("Invocation token set %p", tok);
427 ses->call_invoktok = tok;
428 break;
429 case 1:
430 D("Target Identity token set %p", tok);
431 ses->call_tgttok = tok;
432 break;
433 }
434 return tok;
435 }
436
437 /*() SAML NameID Mapping Service: Issue token in response to receiving a token */
438
439 /* Called by: zxid_sp_soap_dispatch */
zxid_nidmap_do(zxid_conf * cf,struct zx_sp_NameIDMappingRequest_s * req)440 struct zx_sp_NameIDMappingResponse_s* zxid_nidmap_do(zxid_conf* cf, struct zx_sp_NameIDMappingRequest_s* req)
441 {
442 struct zx_sp_NameIDMappingResponse_s* resp = zx_NEW_sp_NameIDMappingResponse(cf->ctx,0);
443 struct zx_str* issue_to;
444 struct zx_str* affil;
445 char allow_create;
446 char* nid_fmt;
447 zxid_nid* nameid;
448 char* logop;
449 int len, n_mapped = 0;
450 char uid[ZXID_MAX_BUF];
451 char sp_name_buf[1024];
452 D_INDENT("nidmap: ");
453
454 /* *** there should be some strict access control policies here, otherwise
455 * privacy can be lost by consulting nameids directly via this service. */
456
457 nameid = zxid_decrypt_nameid(cf, req->NameID, req->EncryptedID);
458 affil = nameid->SPNameQualifier ? &nameid->SPNameQualifier->g : zxid_my_ent_id(cf);
459
460 zxid_nice_sha1(cf, sp_name_buf, sizeof(sp_name_buf), affil, affil, 7);
461 len = read_all(sizeof(uid)-1, uid, "idp_map_nid2uid", 1, "%s" ZXID_NID_DIR "%s/%.*s", cf->cpath, sp_name_buf, ZX_GET_CONTENT_LEN(nameid), ZX_GET_CONTENT_S(nameid));
462 if (!len) {
463 ERR("Can not find reverse mapping for SP,SHA1(%s) nid(%.*s)", sp_name_buf, ZX_GET_CONTENT_LEN(nameid), ZX_GET_CONTENT_S(nameid));
464 resp->Status = zxid_mk_Status(cf, &resp->gg, "Fail", 0, 0);
465 D_DEDENT("nidmap: ");
466 return resp;
467 }
468
469 /* Figure out destination */
470
471 if (req->NameIDPolicy) {
472 issue_to = &req->NameIDPolicy->SPNameQualifier->g;
473 nid_fmt = ZX_STR_EQ(&req->NameIDPolicy->Format->g, SAML2_TRANSIENT_NID_FMT) ? "trnsnt" : "prstnt";
474 allow_create = XML_TRUE_TEST(&req->NameIDPolicy->AllowCreate->g) ? '1':'0';
475 } else {
476 issue_to = 0;
477 }
478
479 if (!issue_to) {
480 ERR("No NameIDPolicy->SPNameQualifier %p", req->NameIDPolicy);
481 resp->Status = zxid_mk_Status(cf, &resp->gg, "Fail", 0, 0);
482 D_DEDENT("nidmap: ");
483 return resp;
484 }
485 zxid_nice_sha1(cf, sp_name_buf, sizeof(sp_name_buf), issue_to, issue_to, 7);
486
487 /* Check for federation */
488
489 nameid = zxid_check_fed(cf, issue_to, uid, allow_create, 0, 0, 0, sp_name_buf);
490 if (nameid) {
491 if (nid_fmt && !strcmp(nid_fmt, "trnsnt")) {
492 D("Despite old fed, using transient due to nid_fmt(%s)", STRNULLCHKD(nid_fmt));
493 zxid_mk_transient_nid(cf, nameid, sp_name_buf, uid);
494 logop = "ITNIDMAP";
495 } else
496 logop = "IFNIDMAP";
497 } else {
498 D("No nameid (because of no federation), using transient %d", 0);
499 nameid = zx_NEW_sa_NameID(cf->ctx,0);
500 zxid_mk_transient_nid(cf, nameid, sp_name_buf, uid);
501 logop = "ITNIDMAP";
502 }
503
504 zxlog(cf, 0, 0, 0, 0, 0, 0, ZX_GET_CONTENT(nameid), "N", "K", logop, 0, "n=%d", n_mapped);
505 resp->Status = zxid_OK(cf, &resp->gg);
506 D_DEDENT("nidmap: ");
507 return resp;
508 }
509
510 /* EOF -- zxidim.c */
511