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