1 /* zxidspx.c  -  Handwritten functions for SP dispatch
2  * Copyright (c) 2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3  * Copyright (c) 2006-2009 Symlabs (symlabs@symlabs.com), 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: zxidspx.c,v 1.14 2010-01-08 02:10:09 sampo Exp $
10  *
11  * 12.8.2006,  created --Sampo
12  * 12.10.2007, tweaked for signing SLO and MNI --Sampo
13  * 14.4.2008,  added SimpleSign --Sampo
14  * 7.10.2008,  added documentation --Sampo
15  * 22.8.2009,  added XACML dummy PDP support --Sampo
16  * 15.11.2009, added discovery service Query --Sampo
17  * 12.2.2010,  added locking to lazy loading --Sampo
18  *
19  * See also zxid/sg/wsf-soap11.sg and zxid/c/zx-e-data.h, which is generated.
20  */
21 
22 #include "platform.h"  /* needed on Win32 for pthread_mutex_lock() et al. */
23 
24 #include "errmac.h"
25 #include "zxid.h"
26 #include "zxidutil.h"
27 #include "zxidpriv.h"
28 #include "zxidconf.h"
29 #include "saml2.h"
30 #include "c/zx-const.h"
31 #include "c/zx-ns.h"
32 #include "c/zx-data.h"
33 
34 /*() Extract an assertion, decrypting EncryptedAssertion if needed. */
35 
36 /* Called by:  sig_validate x2, zxid_imreq, zxid_sp_dig_oauth_sso_a7n, zxid_sp_dig_sso_a7n, zxid_wsp_validate_env x2 */
zxid_dec_a7n(zxid_conf * cf,zxid_a7n * a7n,struct zx_sa_EncryptedAssertion_s * enca7n)37 zxid_a7n* zxid_dec_a7n(zxid_conf* cf, zxid_a7n* a7n, struct zx_sa_EncryptedAssertion_s* enca7n)
38 {
39   struct zx_str* ss;
40   struct zx_root_s* r;
41 
42   if (!a7n && enca7n) {
43     ss = zxenc_privkey_dec(cf, enca7n->EncryptedData, enca7n->EncryptedKey);
44     if (!ss || !ss->s || !ss->len) {
45       return 0;
46     }
47     r = zx_dec_zx_root(cf->ctx, ss->len, ss->s, "dec a7n");
48     if (!r) {
49       ERR("Failed to parse EncryptedAssertion buf(%.*s)", ss->len, ss->s);
50       zxlog(cf, 0, 0, 0, 0, 0, 0, 0, "N", "C", "BADXML", 0, "bad EncryptedAssertion");
51       return 0;
52     }
53     a7n = r->Assertion;
54   }
55   return a7n;
56 }
57 
58 /*() Extract an assertion from Request, decrypting EncryptedAssertion if needed, and perform SSO */
59 
60 /* Called by:  zxid_idp_soap_dispatch, zxid_sp_dispatch, zxid_sp_soap_dispatch x3 */
zxid_sp_dig_sso_a7n(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses,struct zx_sp_Response_s * resp)61 static int zxid_sp_dig_sso_a7n(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, struct zx_sp_Response_s* resp)
62 {
63   zxid_a7n* a7n;
64   struct zx_ns_s* pop_seen = 0;
65 
66   if (!zxid_chk_sig(cf, cgi, ses, &resp->gg, resp->Signature, resp->Issuer, 0, "Response"))
67     return 0;
68 
69   a7n = zxid_dec_a7n(cf, resp->Assertion, resp->EncryptedAssertion);
70   if (a7n) {
71     zx_see_elem_ns(cf->ctx, &pop_seen, &resp->gg);
72     return zxid_sp_sso_finalize(cf, cgi, ses, a7n, pop_seen);
73   }
74   if (cf->anon_ok && cgi->rs && zx_match(cf->anon_ok, cgi->rs))
75     return zxid_sp_anon_finalize(cf, cgi, ses);
76   ERR("No Assertion found in SAML Response and anon_ok does not match %p", cf->anon_ok);
77   zxlog(cf, 0, 0, 0, 0, 0, 0, ZX_GET_CONTENT(ses->nameid), "N", "C", "ERR", 0, "sid(%s) No assertion", ses->sid?ses->sid:"");
78   return 0;
79 }
80 
81 /*() Dispatch redirct or post binding requests (and sometimes responses).
82  *
83  * return:: a string (such as Location: header) and let the caller output it.
84  *     Sometimes a dummy string is just output to indicate status, e.g.
85  *     "O" for SSO OK, "K" for normal OK no further action needed,
86  *     "M" show management screen, "I" forward to IdP dispatch, or
87  *     "* ERR" for error situations. These special strings
88  *     are allocated from static storage and MUST NOT be freed. Other
89  *     strings such as "Location: ..." should be freed by caller. */
90 
91 /* Called by:  main x3, zxid_mgmt, zxid_simple_no_ses_cf, zxid_simple_ses_active_cf */
zxid_sp_dispatch(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses)92 struct zx_str* zxid_sp_dispatch(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses)
93 {
94   struct zx_sp_LogoutRequest_s* req;
95   zxid_entity* idp_meta;
96   struct zx_str* loc;
97   struct zx_str* ss;
98   struct zx_str* ss2;
99   struct zx_root_s* r;
100   int ret;
101 
102   ses->sigres = ZXSIG_NO_SIG;
103   r = zxid_decode_redir_or_post(cf, cgi, ses, 1);
104   if (!r)
105     return zx_dup_str(cf->ctx, "* ERR");
106 
107   if (r->Response) {
108     if (!zxid_saml_ok(cf, cgi, r->Response->Status, "SAMLresp"))
109       return zx_dup_str(cf->ctx, "* ERR");
110     ret = zxid_sp_dig_sso_a7n(cf, cgi, ses, r->Response);
111     D("ret=%d ses=%p", ret, ses);
112     switch (ret) {
113     case ZXID_OK:      return zx_dup_str(cf->ctx, "K");
114     case ZXID_SSO_OK:  return zx_dup_str(cf->ctx, "O");
115     case ZXID_IDP_REQ: /* (PXY) Middle IdP of IdP Proxy flow */
116       return zx_dup_str(cf->ctx, zxid_simple_ses_active_cf(cf, cgi, ses, 0, 0x1fff));
117     case ZXID_FAIL:
118       D("*** FAIL, should send back to IdP select %d", 0);
119       return zx_dup_str(cf->ctx, "* ERR");
120     }
121     return zx_dup_str(cf->ctx, "M");  /* Management screen, please. */
122   }
123 
124   if (req = r->LogoutRequest) {
125     if (cf->idp_ena) {  /* *** Kludgy check */
126       D("IdP SLO %d", 0);
127       if (!zxid_idp_slo_do(cf, cgi, ses, req))
128 	return zx_dup_str(cf->ctx, "* ERR");
129     } else {
130       if (!zxid_sp_slo_do(cf, cgi, ses, req))
131 	return zx_dup_str(cf->ctx, "* ERR");
132     }
133     return zxid_slo_resp_redir(cf, cgi, req);
134   }
135 
136   if (r->LogoutResponse) {
137     if (!zxid_saml_ok(cf, cgi, r->LogoutResponse->Status, "SLO resp"))
138       return zx_dup_str(cf->ctx, "* ERR");
139     cgi->msg = "Logout Response OK. Logged out.";
140     zxid_del_ses(cf, ses);
141     return zx_dup_str(cf->ctx, "K"); /* Prevent mgmt screen from displaying, show login screen. */
142   }
143 
144   if (r->ManageNameIDRequest) {
145     idp_meta = zxid_get_ent_ss(cf, ZX_GET_CONTENT(r->ManageNameIDRequest->Issuer));
146     loc = zxid_idp_loc_raw(cf, cgi, idp_meta, ZXID_MNI_SVC, SAML2_REDIR, 0);
147     if (!loc)
148       return zx_dup_str(cf->ctx, "* ERR");  /* *** consider sending error page */
149     ss = zxid_mni_do_ss(cf, cgi, ses, r->ManageNameIDRequest, loc);
150     ss2 = zxid_saml2_resp_redir(cf, loc, ss, cgi->rs);
151     zx_str_free(cf->ctx, loc);
152     zx_str_free(cf->ctx, ss);
153     return ss2;
154   }
155 
156   if (r->ManageNameIDResponse) {
157     if (!zxid_saml_ok(cf, cgi, r->ManageNameIDResponse->Status, "MNI resp")) {
158       ERR("MNI Response indicates failure. %d", 0);
159       return zx_dup_str(cf->ctx, "* ERR");
160     }
161     cgi->msg = "Manage NameID Response OK.";
162     return zx_dup_str(cf->ctx, "M"); /* Defederation doesn't have to mean SLO, show mgmt screen. */
163   }
164 
165   if (r->AuthnRequest) {
166     D("AuthnRequest %d", 0);
167     return zx_dup_str(cf->ctx, "I");
168   }
169 
170   if (cf->log_level > 0)
171     zxlog(cf, 0, 0, 0, 0, 0, 0, ZX_GET_CONTENT(ses->nameid), "N", "C", "SPDISP", 0, "sid(%s) unknown req or resp", STRNULLCHK(ses->sid));
172   ERR("Unknown request or response %p", r);
173   return zx_dup_str(cf->ctx, "* ERR");
174 }
175 
176 /*() Create Authorization Decision */
177 
178 /* Called by:  zxid_xacml_az_do x2 */
zxid_ins_xacml_az_stmt(zxid_conf * cf,zxid_a7n * a7n,char * deci)179 static void zxid_ins_xacml_az_stmt(zxid_conf* cf, zxid_a7n* a7n, char* deci)
180 {
181   /* Two ways of doing assertion with XACMLAuthzDecisionStatement:
182    * 1. Explicitly include such statement in assertion
183    * 2. Use sa:Statement, but brandit with xsi:type
184    * The former is more logical, but the latter is what Jericho does
185    * and in effect the XACML interop events have done (de-facto standard?). */
186 
187 #if 1
188   a7n->XACMLAuthzDecisionStatement = zx_NEW_xasa_XACMLAuthzDecisionStatement(cf->ctx,0);
189   ZX_ADD_KID(a7n->XACMLAuthzDecisionStatement, Response, zxid_mk_xacml_resp(cf, deci));
190   /* *** Add xaspcd1 and xasacd1 variants */
191   zx_add_kid_before(&a7n->gg, zx_xasa_XACMLPolicyStatement_ELEM, &a7n->XACMLAuthzDecisionStatement->gg);
192 #else
193   a7n->Statement = zx_NEW_sa_Statement(cf->ctx,0);
194   a7n->Statement->type = zx_ref_str(cf->ctx, "xasa:XACMLAuthzDecisionStatementType");
195   a7n->Statement->Response = zxid_mk_xacml_resp(cf, deci);
196   zx_add_kid_before(&a7n->gg, zx_sa_AuthnStatement_ELEM, a7n->Statement);
197 #endif
198 }
199 
200 /* Called by:  zxid_xacml_az_cd1_do x2 */
zxid_ins_xacml_az_cd1_stmt(zxid_conf * cf,zxid_a7n * a7n,char * deci)201 static void zxid_ins_xacml_az_cd1_stmt(zxid_conf* cf, zxid_a7n* a7n, char* deci)
202 {
203   /* Two ways of doing assertion with XACMLAuthzDecisionStatement:
204    * 1. Explicitly include such statement in assertion
205    * 2. Use sa:Statement, but brandit with xsi:type
206    * The former is more logical, but the latter is what Jericho does
207    * and in effect the XACML interop events have done (de-facto standard?). */
208 
209 #if 1
210   a7n->xasacd1_XACMLAuthzDecisionStatement = zx_NEW_xasacd1_XACMLAuthzDecisionStatement(cf->ctx,0);
211   ZX_ADD_KID(a7n->xasacd1_XACMLAuthzDecisionStatement, Response, zxid_mk_xacml_resp(cf, deci));
212   /* *** Add xaspcd1 and xasacd1 variants */
213   zx_add_kid_before(&a7n->gg, zx_xasacd1_XACMLPolicyStatement_ELEM, &a7n->xasacd1_XACMLAuthzDecisionStatement->gg);
214 #else
215   a7n->Statement = zx_NEW_sa_Statement(cf->ctx,0);
216   a7n->Statement->type = zx_ref_str(cf->ctx, "xasacd1:XACMLAuthzDecisionStatementType");
217   a7n->Statement->Response = zxid_mk_xacml_resp(cf, deci);
218   zx_add_kid_before(&a7n->gg, zx_sa_AuthnStatement_ELEM, a7n->Statement);
219 #endif
220 }
221 
222 /*() Process <XACMLAuthzDecisionQuery>. The response will have
223  * SAML assertion containing Authorization Decision Statement. */
224 
225 /* Called by:  zxid_sp_soap_dispatch */
zxid_xacml_az_do(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses,struct zx_xasp_XACMLAuthzDecisionQuery_s * azq)226 static struct zx_sp_Response_s* zxid_xacml_az_do(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, struct zx_xasp_XACMLAuthzDecisionQuery_s* azq)
227 {
228   zxid_a7n* a7n;
229   struct zx_str* affil;
230   struct zx_str* subj;
231   struct zx_str* ss;
232   struct zx_xac_Attribute_s* xac_at;
233 
234   if (!zxid_chk_sig(cf, cgi, ses, &azq->gg, azq->Signature, azq->Issuer, 0, "XACMLAuthzDecisionQuery"))
235     return 0;
236 
237   affil = subj = 0;
238 #if 0
239   affil = ar->NameIDPolicy && ar->NameIDPolicy->SPNameQualifier
240     ? ar->NameIDPolicy->SPNameQualifier
241     : ZX_GET_CONTENT(ar->Issuer);
242   subj = zxid_mk_subj(cf, ses, affil, sp_meta);
243 #endif
244   //a7n = zxid_mk_a7n(cf, affil, subj, 0, 0);
245   a7n = zxid_mk_a7n(cf, affil, 0, 0, 0);
246 
247   if (azq->Request && azq->Request->Subject) {
248     for (xac_at = azq->Request->Subject->Attribute;
249 	 xac_at;
250 	 xac_at = (struct zx_xac_Attribute_s*)ZX_NEXT(xac_at)) {
251       if (xac_at->gg.g.tok != zx_xac_Attribute_ELEM)
252 	continue;
253       if (xac_at->AttributeId->g.len == sizeof("role")-1
254 	  && !memcmp(xac_at->AttributeId->g.s, "role", sizeof("role")-1)) {
255 	ss = ZX_GET_CONTENT(xac_at->AttributeValue);
256 	if (ss?ss->len:0 == sizeof("deny")-1 && !memcmp(ss->s, "deny", sizeof("deny")-1)) {
257 	  D("PDP: DENY due to role=deny %d",0);
258 	  zxid_ins_xacml_az_stmt(cf, a7n, "Deny");
259 	  return zxid_mk_saml_resp(cf, a7n, 0);
260 	}
261       }
262     }
263   }
264   D("PDP: PERMIT by default %d",0);
265   zxid_ins_xacml_az_stmt(cf, a7n, "Permit");
266   return zxid_mk_saml_resp(cf, a7n, 0);
267 }
268 
269 /* Called by:  zxid_sp_soap_dispatch */
zxid_xacml_az_cd1_do(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses,struct zx_xaspcd1_XACMLAuthzDecisionQuery_s * azq)270 static struct zx_sp_Response_s* zxid_xacml_az_cd1_do(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, struct zx_xaspcd1_XACMLAuthzDecisionQuery_s* azq)
271 {
272   zxid_a7n* a7n;
273   struct zx_str* affil;
274   struct zx_str* subj;
275   struct zx_str* ss;
276   struct zx_xac_Attribute_s* xac_at;
277 
278   if (!zxid_chk_sig(cf, cgi, ses, &azq->gg, azq->Signature, azq->Issuer, 0, "XACMLAuthzDecisionQuery"))
279     return 0;
280 
281   affil = subj = 0;
282 #if 0
283   affil = ar->NameIDPolicy && ar->NameIDPolicy->SPNameQualifier
284     ? ar->NameIDPolicy->SPNameQualifier
285     : ZX_GET_CONTENT(ar->Issuer);
286   subj = zxid_mk_subj(cf, ses, affil, sp_meta);
287 #endif
288   //a7n = zxid_mk_a7n(cf, affil, subj, 0, 0);
289   a7n = zxid_mk_a7n(cf, affil, 0, 0, 0);
290 
291   if (azq->Request && azq->Request->Subject) {
292     for (xac_at = azq->Request->Subject->Attribute;
293 	 xac_at;
294 	 xac_at = (struct zx_xac_Attribute_s*)ZX_NEXT(xac_at)) {
295       if (xac_at->gg.g.tok == zx_xac_Attribute_ELEM)
296 	continue;
297       if (xac_at->AttributeId->g.len == sizeof("role")-1
298 	  && !memcmp(xac_at->AttributeId->g.s, "role", sizeof("role")-1)) {
299 	ss = ZX_GET_CONTENT(xac_at->AttributeValue);
300 	if (ss?ss->len:0 == sizeof("deny")-1 && !memcmp(ss->s, "deny", sizeof("deny")-1)) {
301 	  D("PDP: Deny due to role=deny %d",0);
302 	  zxid_ins_xacml_az_cd1_stmt(cf, a7n, "Deny");
303 	  return zxid_mk_saml_resp(cf, a7n, 0);
304 	}
305       }
306     }
307   }
308   D("PDP: Permit by default %d",0);
309   zxid_ins_xacml_az_cd1_stmt(cf, a7n, "Permit");
310   return zxid_mk_saml_resp(cf, a7n, 0);
311 }
312 
313 /*() SOAP dispatch can also handle requests and responses received via artifact
314  * resolution. However only some combinations make sense.
315  * See zxid/sg/wsf-soap11.sg for the master SOAP dispatch from parsing perspective.
316  * Despite being called zxid_sp_soap_dispatch(), this actually dispatches
317  * the IdP functions, such as ManageNameIDRequest, XACMLAuthzDecisionQuery,
318  * SASLRequest (AnSvc), Query (Discovery), and People Service requests.
319  *
320  * Return 0 for failure, otherwise some success code such as ZXID_SSO_OK */
321 
322 /* Called by:  zxid_idp_soap_parse, zxid_sp_deref_art, zxid_sp_soap_parse */
zxid_sp_soap_dispatch(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses,struct zx_root_s * r)323 int zxid_sp_soap_dispatch(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, struct zx_root_s* r)
324 {
325   X509* sign_cert;
326   EVP_PKEY* sign_pkey;
327   struct zxsig_ref refs;
328   struct zx_e_Header_s* hdr;  /* Request headers */
329   struct zx_e_Body_s* bdy;    /* Request Body */
330   struct zx_e_Body_s* body;   /* Response Body */
331   ses->sigres = ZXSIG_NO_SIG;
332 
333   if (!r) goto bad;
334   if (!r->Envelope) goto bad;
335   hdr = r->Envelope->Header;
336   bdy = r->Envelope->Body;
337 
338   if (cf->log_level > 1)
339     zxlog(cf, 0, 0, 0, 0, 0, 0, ZX_GET_CONTENT(ses->nameid), "N", "W", "SPDISP", 0, "sid(%s) soap", STRNULLCHK(ses->sid));
340 
341   if (bdy->ArtifactResponse) {
342     if (!zxid_saml_ok(cf, cgi, bdy->ArtifactResponse->Status, "ArtResp"))
343       return 0;
344     return zxid_sp_dig_sso_a7n(cf, cgi, ses, bdy->ArtifactResponse->Response);
345   }
346 
347   if (bdy->Response) {    /* PAOS/ECP response */
348     if (!zxid_saml_ok(cf, cgi, bdy->Response->Status, "PAOS Resp"))
349       return 0;
350     return zxid_sp_dig_sso_a7n(cf, cgi, ses, bdy->Response);
351   }
352 
353   body = zx_NEW_e_Body(cf->ctx,0);
354 
355   if (bdy->LogoutRequest) {
356     ses->issuer = ZX_GET_CONTENT(bdy->LogoutRequest->Issuer);
357     if (!zxid_sp_slo_do(cf, cgi, ses, bdy->LogoutRequest))
358       return 0;
359     ZX_ADD_KID(body, LogoutResponse, zxid_mk_logout_resp(cf, zxid_OK(cf, 0), &bdy->LogoutRequest->ID->g));
360     if (cf->sso_soap_resp_sign) {
361       ZERO(&refs, sizeof(refs));
362       refs.id = &body->LogoutResponse->ID->g;
363       refs.canon = zx_easy_enc_elem_sig(cf, &body->LogoutResponse->gg);
364       if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert slor")) {
365 	body->LogoutResponse->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey, cf->xmldsig_sig_meth, cf->xmldsig_digest_algo);
366 	zx_add_kid_after_sa_Issuer(&body->LogoutResponse->gg,&body->LogoutResponse->Signature->gg);
367       }
368       zx_str_free(cf->ctx, refs.canon);
369     }
370     return zxid_soap_cgi_resp_body(cf, ses, body);
371   }
372 
373   if (bdy->ManageNameIDRequest) {
374     ses->issuer = ZX_GET_CONTENT(bdy->ManageNameIDRequest->Issuer);
375     ZX_ADD_KID(body, ManageNameIDResponse, zxid_mni_do(cf, cgi, ses, bdy->ManageNameIDRequest));
376     if (cf->sso_soap_resp_sign) {
377       ZERO(&refs, sizeof(refs));
378       refs.id = &body->ManageNameIDResponse->ID->g;
379       refs.canon = zx_easy_enc_elem_sig(cf, &body->ManageNameIDResponse->gg);
380       if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert mnir")) {
381 	body->ManageNameIDResponse->Signature = zxsig_sign(cf->ctx, 1, &refs,sign_cert, sign_pkey, cf->xmldsig_sig_meth, cf->xmldsig_digest_algo);
382 	zx_add_kid_after_sa_Issuer(&body->ManageNameIDResponse->gg, &body->ManageNameIDResponse->Signature->gg);
383       }
384       zx_str_free(cf->ctx, refs.canon);
385     }
386     return zxid_soap_cgi_resp_body(cf, ses, body);
387   }
388 
389   DD("as_ena=%d %p", cf->as_ena, bdy->SASLRequest);
390   if (cf->as_ena) {
391     if (bdy->SASLRequest) {
392       if (hdr && hdr->Sender && hdr->Sender->providerID)
393 	ses->issuer = &hdr->Sender->providerID->g;
394       else
395 	ses->issuer = 0;
396       //ses->issuer = ZX_GET_CONTENT(bdy->SASLRequest->Issuer);
397       ZX_ADD_KID(body, SASLResponse, zxid_idp_as_do(cf, bdy->SASLRequest));
398 #if 0
399       if (cf->sso_soap_resp_sign) {
400 	ZERO(&refs, sizeof(refs));
401 	refs.id = res->ID;
402 	refs.canon = zx_EASY_ENC_SO_as_SASLResponse(cf->ctx, res);
403 	if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert asr")) {
404 	  res->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey, cf->xmldsig_sig_meth, cf->xmldsig_digest_algo);
405 	  zx_add_kid(&res->gg, &res->gg);
406 	}
407 	zx_str_free(cf->ctx, refs.canon);
408       }
409 #endif
410       return zxid_soap_cgi_resp_body(cf, ses, body);
411     }
412   }
413 
414   if (cf->pdp_ena) {
415     if (bdy->XACMLAuthzDecisionQuery) {
416       ses->issuer = ZX_GET_CONTENT(bdy->XACMLAuthzDecisionQuery->Issuer);
417       D("XACMLAuthzDecisionQuery %d",0);
418       ZX_ADD_KID(body, Response, zxid_xacml_az_do(cf, cgi, ses, bdy->XACMLAuthzDecisionQuery));
419       if (cf->sso_soap_resp_sign) {
420 	ZERO(&refs, sizeof(refs));
421 	refs.id = &body->Response->ID->g;
422 	refs.canon = zx_easy_enc_elem_sig(cf, &body->Response->gg);
423 	if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert azr")) {
424 	  body->Response->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey, cf->xmldsig_sig_meth, cf->xmldsig_digest_algo);
425 	  zx_add_kid_after_sa_Issuer(&body->Response->gg, &body->Response->Signature->gg);
426 	}
427 	zx_str_free(cf->ctx, refs.canon);
428       }
429       return zxid_soap_cgi_resp_body(cf, ses, body);
430     }
431     if (bdy->xaspcd1_XACMLAuthzDecisionQuery) {
432       ses->issuer = ZX_GET_CONTENT(bdy->XACMLAuthzDecisionQuery->Issuer);
433       D("xaspcd1:XACMLAuthzDecisionQuery %d",0);
434       ZX_ADD_KID(body, Response, zxid_xacml_az_cd1_do(cf, cgi, ses, bdy->xaspcd1_XACMLAuthzDecisionQuery));
435       if (cf->sso_soap_resp_sign) {
436 	ZERO(&refs, sizeof(refs));
437 	refs.id = &body->Response->ID->g;
438 	refs.canon = zx_easy_enc_elem_sig(cf, &body->Response->gg);
439 	if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert azr")) {
440 	  body->Response->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey, cf->xmldsig_sig_meth, cf->xmldsig_digest_algo);
441 	  zx_add_kid_after_sa_Issuer(&body->Response->gg, &body->Response->Signature->gg);
442 	}
443 	zx_str_free(cf->ctx, refs.canon);
444       }
445       return zxid_soap_cgi_resp_body(cf, ses, body);
446     }
447   }
448 
449   if (cf->idp_ena) {
450     if (bdy->ArtifactResolve) {
451       D("*** ArtifactResolve not implemented yet %d",0);
452       //if (!zxid_saml_ok(cf, cgi, bdy->ArtifactResponse->Status, "ArtResp"))
453       //  return 0;
454       //return zxid_sp_dig_sso_a7n(cf, cgi, ses, bdy->ArtifactResponse->Response);
455     }
456 
457     if (bdy->NameIDMappingRequest && cf->imps_ena) {
458       ses->issuer = ZX_GET_CONTENT(bdy->NameIDMappingRequest->Issuer);
459       ZX_ADD_KID(body, NameIDMappingResponse, zxid_nidmap_do(cf, bdy->NameIDMappingRequest));
460       if (cf->sso_soap_resp_sign) {
461 	ZERO(&refs, sizeof(refs));
462 	refs.id = &body->NameIDMappingResponse->ID->g;
463 	refs.canon = zx_easy_enc_elem_sig(cf, &body->NameIDMappingResponse->gg);
464 	if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert mnir")) {
465 	  body->NameIDMappingResponse->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey, cf->xmldsig_sig_meth, cf->xmldsig_digest_algo);
466 	  zx_add_kid_after_sa_Issuer(&body->NameIDMappingResponse->gg, &body->NameIDMappingResponse->Signature->gg);
467 	}
468 	zx_str_free(cf->ctx, refs.canon);
469       }
470       return zxid_soap_cgi_resp_body(cf, ses, body);
471     }
472 
473     if (!zxid_wsp_validate_env(cf, ses, "Resource=Discovery", r->Envelope)) {
474       return zxid_soap_cgi_resp_body(cf, ses, body); /* will include the fault */
475     }
476 
477     if (bdy->Query) { /* Discovery 2.0 Query */
478       ZX_ADD_KID(body, QueryResponse, zxid_di_query(cf, ses, bdy->Query));
479     idwsf_resp:
480 #if 0
481       // *** should really sign the Body, putting sig in wsse:Security header
482       if (cf->sso_soap_resp_sign) {
483 	ZERO(&refs, sizeof(refs));
484 	refs.id = di_resp->ID;
485 	refs.canon = zx_EASY_ENC_SO_e_Body(cf->ctx, body);
486 	if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert dir")) {
487 	  res->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey, cf->xmldsig_sig_meth, cf->xmldsig_digest_algo);
488 	  zx_add_kid_after_sa_Issuer(&res->gg, &res->Signature->gg);
489 	}
490 	zx_str_free(cf->ctx, refs.canon);
491       }
492 #endif
493 
494       return zxid_soap_cgi_resp_body(cf, ses, body);
495     }
496 
497     if (cf->imps_ena) {
498       if (bdy->AddEntityRequest) {
499 	ZX_ADD_KID(body, AddEntityResponse, zxid_ps_addent_invite(cf, ses, bdy->AddEntityRequest));
500 	goto idwsf_resp;
501       }
502       if (bdy->ResolveIdentifierRequest) {
503 	ZX_ADD_KID(body, ResolveIdentifierResponse, zxid_ps_resolv_id(cf, ses, bdy->ResolveIdentifierRequest));
504 	goto idwsf_resp;
505       }
506       if (bdy->IdentityMappingRequest) {
507 	ZX_ADD_KID(body, IdentityMappingResponse, zxid_imreq(cf,ses, bdy->IdentityMappingRequest));
508 	goto idwsf_resp;
509       }
510     }
511     if (bdy->AuthnRequest && cf->as_ena) {
512       ZX_ADD_KID(body, Response, zxid_ssos_anreq(cf, ses, bdy->AuthnRequest));
513       goto idwsf_resp;
514     }
515   }
516 
517  bad:
518   ERR("Unknown SOAP request %p", r);
519   if (cf->log_level > 0)
520     zxlog(cf, 0, 0, 0, 0, 0, 0, ZX_GET_CONTENT(ses->nameid), "N", "C", "SPDISP", 0, "sid(%s) unknown soap req", STRNULLCHK(ses->sid));
521   return 0;
522 }
523 
524 /*() Return 0 for failure, otherwise some success code such as ZXID_SSO_OK */
525 
526 /* Called by:  chkuid, main x6, zxid_mini_httpd_sso, zxid_simple_cf_ses */
zxid_sp_soap_parse(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses,int len,char * buf)527 int zxid_sp_soap_parse(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, int len, char* buf)
528 {
529   struct zx_root_s* r;
530   r = zx_dec_zx_root(cf->ctx, len, buf, "sp soap parse");
531   if (!r || !r->Envelope || !r->Envelope->Body) {
532     ERR("Failed to parse SOAP request buf(%.*s)", len, buf);
533     zxlog(cf, 0, 0, 0, 0, 0, 0, ZX_GET_CONTENT(ses->nameid), "N", "C", "BADXML", 0, "sid(%s) bad soap req", STRNULLCHK(ses->sid));
534     return 0;
535   }
536   return zxid_sp_soap_dispatch(cf, cgi, ses, r);
537 }
538 
539 /* EOF  --  zxidspx.c */
540