Branch data Line data Source code
1 : : /* zxidwsp.c - Handwritten nitty-gritty functions for Liberty ID-WSF Web Services Provider
2 : : * Copyright (c) 2009-2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3 : : * Copyright (c) 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: zxidwsc.c,v 1.16 2009-11-20 20:27:13 sampo Exp $
10 : : *
11 : : * 22.11.2009, created --Sampo
12 : : * 7.1.2010, added WSP signing --Sampo
13 : : * 31.5.2010, reworked PEPs extensively --Sampo
14 : : */
15 : :
16 : : #include "platform.h" /* needed on Win32 for pthread_mutex_lock() et al. */
17 : :
18 : : #include "errmac.h"
19 : : #include "zx.h"
20 : : #include "zxid.h"
21 : : #include "zxidpriv.h"
22 : : #include "zxidutil.h"
23 : : #include "zxidconf.h"
24 : : #include "saml2.h"
25 : : #include "wsf.h"
26 : : #include "c/zx-const.h"
27 : : #include "c/zx-ns.h"
28 : : #include "c/zx-data.h"
29 : :
30 : : #define BOOL_STR_TEST(x) ((x) && (x) != '0')
31 : :
32 : : /*(i) zxid_wsf_decor() implements the main low level ID-WSF web service call logic, including
33 : : * preparation of SOAP headers, use of sec mech (e.g. preparation of wsse:Security
34 : : * header and signing of appropriate compoments of the message), and sequencing
35 : : * of the call. In particular, it is possible that WSP requests user interaction
36 : : * and thus the caller web application will need to perform a redirect and then
37 : : * later call this function again to continue the web service call after interaction.
38 : : *
39 : : * env (rather than Body) is taken as argument so that caller can prepare
40 : : * additional SOAP headers at will before calling this function. This function
41 : : * will add Liberty ID-WSF specific SOAP headers. */
42 : :
43 : : /* Called by: main, zxid_soap_cgi_resp_body, zxid_wsc_prep, zxid_wsp_decorate */
44 : : int zxid_wsf_decor(zxid_conf* cf, zxid_ses* ses, struct zx_e_Envelope_s* env, int is_resp)
45 : 191 : {
46 : : struct zx_wsse_Security_s* sec;
47 : : struct zx_e_Header_s* hdr;
48 : :
49 [ + - - + ]: 191 : if (!env || !env->Body) {
50 : 0 : ERR("NULL SOAP envelope or body %p", env);
51 : 0 : return 0;
52 : : }
53 : :
54 [ - + ]: 191 : if (!env->Header)
55 : 0 : env->Header = zx_NEW_e_Header(cf->ctx, &env->gg);
56 : 191 : hdr = env->Header;
57 : :
58 : : /* Populate SOAP headers. */
59 : :
60 : 191 : hdr->Framework = zx_NEW_sbf_Framework(cf->ctx, &hdr->gg);
61 : 191 : hdr->Framework->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->Framework->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
62 : 191 : hdr->Framework->actor = zx_ref_attr(cf->ctx, &hdr->Framework->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
63 : 191 : hdr->Framework->version = zx_ref_attr(cf->ctx, &hdr->Framework->gg, zx_version_ATTR, "2.0");
64 : :
65 : : #if 1
66 : : /* *** Conor claims Sender is not mandatory */
67 : 191 : hdr->Sender = zx_NEW_b_Sender(cf->ctx, &hdr->gg);
68 : 191 : hdr->Sender->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->Sender->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
69 : 191 : hdr->Sender->actor = zx_ref_attr(cf->ctx, &hdr->Sender->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
70 : 191 : hdr->Sender->providerID = zxid_my_ent_id_attr(cf, &hdr->Sender->gg, zx_providerID_ATTR);
71 [ - + ]: 191 : if (cf->affiliation)
72 : 0 : hdr->Sender->affiliationID = zx_ref_attr(cf->ctx, &hdr->Sender->gg, zx_affiliationID_ATTR, cf->affiliation);
73 : : #endif
74 : :
75 : 191 : hdr->MessageID = zx_NEW_a_MessageID(cf->ctx, &hdr->gg);
76 : 191 : hdr->MessageID->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->MessageID->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
77 : 191 : hdr->MessageID->actor = zx_ref_attr(cf->ctx, &hdr->MessageID->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
78 : :
79 : : #if 0
80 : : hdr->Action = zx_NEW_a_Action(cf->ctx, &hdr->gg);
81 : : zx_add_content(cf->ctx, &hdr->Action->gg, zx_ref_str(cf->ctx, ***));
82 : : hdr->Action->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->Action->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
83 : : hdr->Action->actor = zx_ref_attr(cf->ctx, gghdr->Action->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
84 : : #endif
85 : :
86 : : #if 0
87 : : hdr->From = zx_NEW_a_From(cf->ctx, &hdr->gg);
88 : : hdr->From->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->From->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
89 : : hdr->From->actor = zx_ref_attr(cf->ctx, &hdr->From->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
90 : : hdr->From->Address = zxid_mk_addr(cf, zx_strf(cf->ctx, "%s?o=P", cf->url));
91 : : #endif
92 : :
93 : : #if 0
94 : : hdr->ReferenceParameters = zx_NEW_a_ReferenceParameters(cf->ctx, &hdr->gg);
95 : : hdr->ReferenceParameters->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->ReferenceParameters->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
96 : : hdr->ReferenceParameters->actor = zx_ref_attr(cf->ctx, &hdr->ReferenceParameters->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
97 : : #endif
98 : :
99 : : #if 0
100 : : hdr->Credentials = zx_NEW_tas3_Credentials(cf->ctx, &hdr->gg);
101 : : hdr->Credentials->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->Credentials->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
102 : : hdr->Credentials->actor = zx_ref_attr(cf->ctx, &hdr->Credentials->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
103 : : #endif
104 : :
105 : : #if 0
106 : : /* If you want this header, you should
107 : : * create it prior to calling zxid_wsc_call() */
108 : : hdr->UsageDirective = zx_NEW_b_UsageDirective(cf->ctx, &hdr->gg);
109 : : hdr->UsageDirective->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->UsageDirective->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
110 : : hdr->UsageDirective->actor = zx_ref_attr(cf->ctx, &hdr->UsageDirective->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
111 : : #endif
112 : :
113 : : #if 0
114 : : /* Interaction or redirection. If you want this header, you should
115 : : * create it prior to calling zxid_wsc_call() */
116 : : hdr->UserInteraction = zx_NEW_b_UserInteraction(cf->ctx, &hdr->gg);
117 : : hdr->UserInteraction->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->UserInteraction->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
118 : : hdr->UserInteraction->actor = zx_ref_attr(cf->ctx, &hdr->UserInteraction->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
119 : : #endif
120 : :
121 [ + - - + ]: 191 : if (ses && ses->curstatus) {
122 : 0 : ZX_ADD_KID(hdr, Status, ses->curstatus);
123 : : }
124 : :
125 : 191 : sec = hdr->Security = zx_NEW_wsse_Security(cf->ctx, &hdr->gg);
126 : 191 : sec->actor = zx_ref_attr(cf->ctx, &sec->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
127 : 191 : sec->mustUnderstand = zx_ref_attr(cf->ctx, &sec->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
128 : 191 : sec->Timestamp = zx_NEW_wsu_Timestamp(cf->ctx, &sec->gg);
129 : 191 : sec->Timestamp->Created = zx_NEW_wsu_Created(cf->ctx, &sec->Timestamp->gg);
130 : 191 : zx_reverse_elem_lists(&sec->gg);
131 : :
132 [ + + ]: 191 : if (is_resp) {
133 : 153 : zx_add_content(cf->ctx, &sec->Timestamp->Created->gg, zxid_date_time(cf, time(0)));
134 : 153 : zx_add_content(cf->ctx, &hdr->MessageID->gg, zxid_mk_id(cf, "urn:M", ZXID_ID_BITS));
135 : : /* Clear away any credentials from previous iteration. *** clear kids list, too */
136 : 153 : sec->Signature = 0;
137 : 153 : sec->BinarySecurityToken = 0;
138 : 153 : sec->SecurityTokenReference = 0;
139 : 153 : sec->Assertion = 0;
140 : 153 : sec->sa11_Assertion = 0;
141 : 153 : sec->ff12_Assertion = 0;
142 : :
143 [ + - + + : 153 : if (ses && ses->wsp_msgid && ses->wsp_msgid->len) {
+ - ]
144 [ + - - + ]: 35 : D("wsp_msgid(%.*s) %p %d %p", ses->wsp_msgid->len, ses->wsp_msgid->s, ses->wsp_msgid, ses->wsp_msgid->len, ses->wsp_msgid->s);
145 : 35 : hdr->RelatesTo = zx_NEW_a_RelatesTo(cf->ctx, &hdr->gg);
146 : 35 : zx_add_content(cf->ctx, &hdr->RelatesTo->gg, ses->wsp_msgid);
147 : 35 : hdr->RelatesTo->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->RelatesTo->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
148 : 35 : hdr->RelatesTo->actor = zx_ref_attr(cf->ctx, &hdr->RelatesTo->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
149 : : }
150 : :
151 : 153 : zxid_attach_sol1_usage_directive(cf, ses, env, TAS3_REQUIRE, cf->wsp_localpdp_obl_emit);
152 : 153 : zxid_wsf_sign(cf, cf->wsp_sign, sec, 0, hdr, env->Body);
153 : : }
154 : 191 : return 1;
155 : : }
156 : :
157 : : /* ----------------------------------------
158 : : * Simplify writing WSPs */
159 : :
160 : : /*(i) Add ID-WSF (and TAS3) specific headers and signatures to
161 : : * web service response. Simple and intuitive specification of
162 : : * XML as string: no need to build complex data structures.
163 : : *
164 : : * If the string starts by "<e:Envelope", then string should be
165 : : * a complete SOAP envelope including <e:Header> and <e:Body> parts. This
166 : : * allows caller to specify custom SOAP headers, in addition to the ones
167 : : * that the underlying zxid_wsc_call() will add. Usually the payload service
168 : : * will be passed as the contents of the body. If the string starts by
169 : : * "<e:Body", then the <e:Envelope> and <e:Header> are automatically added. If
170 : : * the string starts by neither of the above (be careful to use the "e:" as
171 : : * namespace prefix), the it is assumed to be the payload content of
172 : : * the <e:Body> and the rest of the SOAP envelope is added.
173 : : *
174 : : * cf:: ZXID configuration object, see zxid_new_conf()
175 : : * ses:: Session object that contains the EPR cache
176 : : * az_cred:: (Optional) Additional authorization credentials or
177 : : * attributes, query string format. These credentials will be populated
178 : : * to the attribute pool in addition to the ones obtained from token and
179 : : * other sources. Then a PDP is called to get an authorization
180 : : * decision (generating obligations). See also PEPMAP_RSOUT configuration
181 : : * option. This implements generalized (application independent)
182 : : * Responder Out PEP. To implement application dependent PEP features
183 : : * you should call zxid_az() directly.
184 : : * env:: XML payload
185 : : * return:: SOAP Envelope of the response, as a string, ready to be
186 : : * sent as HTTP response. */
187 : :
188 : : /* Called by: covimp_test, main x9, zxid_wsp_decoratef, zxidwspcgi_parent */
189 : : struct zx_str* zxid_wsp_decorate(zxid_conf* cf, zxid_ses* ses, const char* az_cred, const char* enve)
190 : 18 : {
191 : : struct zx_str* ss;
192 : : struct zx_e_Envelope_s* env;
193 : 18 : D_INDENT("decor: ");
194 : :
195 : 18 : env = zxid_add_env_if_needed(cf, enve);
196 [ - + ]: 18 : if (!env) {
197 : 0 : D_DEDENT("decor: ");
198 : 0 : return 0;
199 : : }
200 : :
201 : : //*** Needs thought and development
202 : :
203 : : /* Call Rs-Out PDP */
204 : :
205 [ - + ]: 18 : if (!zxid_localpdp(cf, ses)) {
206 : 0 : ERR("RSOUT3 Deny by local PDP %d",0);
207 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_OUT, "e:Server", "Response denied by WSP local policy", TAS3_STATUS_DENY, 0, 0, 0));
208 : : /* Fall through, letting zxid_wsf_decor() pick up the fault and package it as response. */
209 [ + + + - ]: 18 : } else if (cf->pdp_url && *cf->pdp_url) {
210 : : //zxid_add_attr_to_pool(cf, ses, "Action", zx_dup_str(cf->ctx, "access"));
211 [ - + ]: 17 : if (!zxid_pep_az_soap_pepmap(cf, 0, ses, cf->pdp_url, cf->pepmap_rsout)) {
212 : 0 : ERR("RSOUT3 Deny %d", 0);
213 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_OUT, "e:Server", "Response denied by WSP policy at PDP", TAS3_STATUS_DENY, 0, 0, 0));
214 : : /* Fall through, letting zxid_wsf_decor() pick up the fault and package it as response. */
215 : : }
216 : : }
217 : :
218 [ - + ]: 18 : if (ses->curflt) {
219 [ # # # # ]: 0 : D("Detected curflt, abandoning previous Body content. %d", 0);
220 : : /* *** LEAK: Should free previous body content */
221 : 0 : env->Body = (struct zx_e_Body_s*)zx_replace_kid(&env->gg, (struct zx_elem_s*)zx_NEW_e_Body(cf->ctx, 0));
222 : 0 : ZX_ADD_KID(env->Body, Fault, ses->curflt);
223 : : }
224 : :
225 [ - + ]: 18 : if (!zxid_wsf_decor(cf, ses, env, 1)) {
226 : 0 : ERR("Response decoration failed %p", env);
227 : 0 : D_DEDENT("decor: ");
228 : 0 : return 0;
229 : : }
230 : 18 : zx_reverse_elem_lists(&env->Header->gg);
231 : :
232 : 18 : ss = zx_easy_enc_elem_opt(cf, &env->gg);
233 : : DD("DECOR len=%d envelope(%.*s)", ss->len, ss->len, ss->s);
234 : 18 : D_XML_BLOB(cf, "WSP_DECOR", ss->len, ss->s);
235 : 18 : D_DEDENT("decor: ");
236 : 18 : return ss;
237 : : }
238 : :
239 : : /*() Create web service response, printf style. See zxid_wsp_decorate() for more documentation. */
240 : :
241 : : /* Called by: main */
242 : : struct zx_str* zxid_wsp_decoratef(zxid_conf* cf, zxid_ses* ses, const char* az_cred, const char* env_f, ...)
243 : 1 : {
244 : : char* s;
245 : : va_list ap;
246 : 1 : va_start(ap, env_f);
247 : 1 : s = zx_alloc_vasprintf(cf->ctx, 0, env_f, ap);
248 : 1 : va_end(ap);
249 : 1 : return zxid_wsp_decorate(cf, ses, az_cred, s);
250 : : }
251 : :
252 : : /*() Perform necessary validation steps to check either requester or target identity
253 : : * assertion. Also log the assertion and extract from assertion relevant information
254 : : * into the session. The two types of assertion are distinguished by lk == "req" or "tgt".
255 : : * returns 0 on failure and 1 on success.
256 : : * See zxid_sp_sso_finalize() for similar code. *** consider factoring out commonality */
257 : :
258 : : /* Called by: zxid_wsp_validate_env x2 */
259 : : static int zxid_wsf_validate_a7n(zxid_conf* cf, zxid_ses* ses, zxid_a7n* a7n, const char* lk, struct timeval* srcts)
260 : 35 : {
261 : : struct zx_str* logpath;
262 : : struct zx_str* a7nss;
263 : : struct zxsig_ref refs;
264 : : zxid_nid* nameid;
265 : : int fmt;
266 : : struct zx_str* issuer;
267 : : zxid_entity* idp_meta;
268 : : zxid_cgi cgi;
269 : :
270 [ + - - + ]: 35 : if (!a7n || !a7n->Subject) {
271 : 0 : ERR("%s: Assertion lacking or does not have Subject. %p", lk, a7n);
272 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "Assertion does not have Subject.", "IDStarMsgNotUnderstood", 0, lk, 0));
273 : 0 : return 0;
274 : : }
275 : :
276 [ + - + - : 35 : issuer = ZX_GET_CONTENT(a7n->Issuer);
+ - ]
277 : 35 : nameid = zxid_decrypt_nameid(cf, a7n->Subject->NameID, a7n->Subject->EncryptedID);
278 [ + - + - : 35 : if (!ZX_GET_CONTENT(nameid)) {
- + ]
279 : 0 : ERR("%s: Assertion does not have Subject->NameID. %p", lk, ses->nameid);
280 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "Assertion does not have Subject->NameID.", "IDStarMsgNotUnderstood", 0, lk, 0));
281 : 0 : return 0;
282 : : }
283 : :
284 [ + - - + ]: 35 : if (nameid->Format && !memcmp(nameid->Format->g.s, SAML2_TRANSIENT_NID_FMT, nameid->Format->g.len)) {
285 : 0 : fmt = 0;
286 : : } else {
287 : 35 : fmt = 1; /* anything nontransient may be a federation */
288 : : }
289 : :
290 [ + - - + : 35 : D("A7N received. NID(%s) FMT(%d) SESIX(%s)", STRNULLCHKQ(ses->nid), ses->nidfmt, STRNULLCHK(ses->sesix));
- + - + ]
291 [ - + ]: 35 : if (!strcmp(lk, "tgt")) {
292 : 0 : ses->tgtnameid = nameid;
293 [ # # # # : 0 : ses->tgt = zx_str_to_c(cf->ctx, ZX_GET_CONTENT(nameid));
# # ]
294 : 0 : ses->tgtfmt = fmt;
295 : : } else {
296 : 35 : ses->nameid = nameid;
297 [ + - + - : 35 : ses->nid = zx_str_to_c(cf->ctx, ZX_GET_CONTENT(nameid));
+ - ]
298 : 35 : ses->nidfmt = fmt;
299 : : }
300 : :
301 : : /* Validate signature (*** add Issuer trusted check, CA validation, etc.) */
302 : :
303 : 35 : idp_meta = zxid_get_ent_ss(cf, issuer);
304 [ - + ]: 35 : if (!idp_meta) {
305 : 0 : ses->sigres = ZXSIG_NO_SIG;
306 [ # # ]: 0 : if (!cf->nosig_fatal) {
307 : 0 : ERR("%s: Unable to find metadata for Assertion Issuer(%.*s).", lk, issuer->len, issuer->s);
308 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "No unable to find SAML metadata for Assertion Issuer.", "ProviderIDNotValid", 0, lk, 0));
309 : 0 : return 0;
310 : : } else {
311 : 0 : INFO("%s: Unable to find metadata for Assertion Issuer(%.*s), but configured to ignore this problem (NOSIG_FATAL=0).", lk, issuer->len, issuer->s);
312 : : }
313 : : } else {
314 [ + - + - : 70 : if (a7n->Signature && a7n->Signature->SignedInfo && a7n->Signature->SignedInfo->Reference) {
+ - ]
315 : 35 : ZERO(&refs, sizeof(refs));
316 : 35 : refs.sref = a7n->Signature->SignedInfo->Reference;
317 : 35 : refs.blob = (struct zx_elem_s*)a7n;
318 : 35 : ses->sigres = zxsig_validate(cf->ctx, idp_meta->sign_cert, a7n->Signature, 1, &refs);
319 : 35 : zxid_sigres_map(ses->sigres, &cgi.sigval, &cgi.sigmsg);
320 : : } else {
321 [ # # # # ]: 0 : if (cf->msg_sig_ok && !ses->sigres) {
322 : 0 : INFO("Assertion without signature accepted due to message level signature (SimpleSign) %d", 0);
323 : : } else {
324 : 0 : ses->sigres = ZXSIG_NO_SIG;
325 [ # # ]: 0 : if (!cf->nosig_fatal) {
326 [ # # ]: 0 : ERR("Assertion not signed. Sigval(%s) %p", STRNULLCHKNULL(cgi.sigval), a7n->Signature);
327 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "Assertion not signed.", TAS3_STATUS_NOSIG, 0, lk, 0));
328 : 0 : return 0;
329 : : } else {
330 [ # # ]: 0 : INFO("SSO warn: assertion not signed, but configured to ignore this problem (NOSIG_FATAL=0). Sigval(%s) %p", STRNULLCHKNULL(cgi.sigval), a7n->Signature);
331 : : }
332 : : }
333 : : }
334 : : }
335 [ + - - + ]: 35 : if (cf->sig_fatal && ses->sigres) {
336 : 0 : ERR("Fail due to failed assertion signature sigres=%d", ses->sigres);
337 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "Assertion signature did not validate.", TAS3_STATUS_BADSIG, 0, lk, 0));
338 : 0 : return 0;
339 : : }
340 : :
341 [ - + ]: 35 : if (zxid_validate_cond(cf, &cgi, ses, a7n, zxid_my_ent_id(cf), 0, 0)) {
342 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "Conditions did not validate.", TAS3_STATUS_BADCOND, 0, lk, 0));
343 : 0 : return 0;
344 : : }
345 : :
346 [ + - ]: 35 : if (cf->log_rely_a7n) {
347 : : DD("Logging... %d", 0);
348 : 35 : logpath = zxlog_path(cf, issuer, &a7n->ID->g, ZXLOG_RELY_DIR, ZXLOG_A7N_KIND, 1);
349 [ + - ]: 35 : if (logpath) {
350 : 35 : ses->sso_a7n_path = ses->tgt_a7n_path = zx_str_to_c(cf->ctx, logpath);
351 : 35 : a7nss = zx_easy_enc_elem_sig(cf, &a7n->gg);
352 [ + + ]: 35 : if (zxlog_dup_check(cf, logpath, "SSO assertion")) {
353 [ + + ]: 5 : if (cf->dup_a7n_fatal) {
354 : 4 : zxlog_blob(cf, cf->log_rely_a7n, logpath, a7nss, "wsp_validade dup err");
355 : 4 : return 0;
356 : : }
357 : : }
358 : 31 : zxlog_blob(cf, cf->log_rely_a7n, logpath, a7nss, "wsp_validate");
359 [ + - + - : 31 : zxlog(cf, 0, srcts, ses->ipport, issuer, ses->wsp_msgid, &a7n->ID->g, ZX_GET_CONTENT(nameid), "N", "K", "A7N VALID", logpath->s, lk);
+ - ]
360 : 31 : zx_str_free(cf->ctx, a7nss);
361 : : }
362 : : }
363 : 31 : return 1;
364 : : }
365 : :
366 : : /*() Validate SOAP request envelope, specified as data structure
367 : : *
368 : : * cf:: ZXID configuration object, see zxid_new_conf()
369 : : * ses:: Session object that contains the EPR cache
370 : : * az_cred:: (Optional) Additional authorization credentials or
371 : : * attributes, query string format. These credentials will be populated
372 : : * to the attribute pool in addition to the ones obtained from token and
373 : : * other sources. Then a PDP is called to get an authorization
374 : : * decision (matching obligations we support to those in the request,
375 : : * and obligations pleged by caller to those we insist on). See
376 : : * also PEPMAP configuration option. This implements generalized
377 : : * (application independent) Responder In PEP. To implement
378 : : * application dependent PEP features you should call zxid_az() directly.
379 : : * env:: SOAP envelope as data structure
380 : : * return:: idpnid of target identity of the request (rest of the information
381 : : * is populated to the session object, from where it can be retrieved).
382 : : * NULL if the validation fails. The target identity is still retrievable
383 : : * from the session, should there be desire to process the message despite
384 : : * the validation failure.
385 : : *
386 : : * See also: zxid_wsc_validate_resp_env() */
387 : :
388 : : /* Called by: zxid_sp_soap_dispatch, zxid_wsp_validate */
389 : : char* zxid_wsp_validate_env(zxid_conf* cf, zxid_ses* ses, const char* az_cred, struct zx_e_Envelope_s* env)
390 : 37 : {
391 : 37 : int n_refs = 0;
392 : : struct zxsig_ref refs[ZXID_N_WSF_SIGNED_HEADERS];
393 : : struct timeval ourts;
394 : : zxid_entity* wsc_meta;
395 : : struct zx_e_Header_s* hdr;
396 : : struct zx_wsse_Security_s* sec;
397 : : zxid_cgi cgi;
398 : :
399 : 37 : D_INDENT("valid: ");
400 : 37 : GETTIMEOFDAY(&ourts, 0);
401 : 37 : zxid_set_fault(cf, ses, 0);
402 : 37 : zxid_set_tas3_status(cf, ses, 0);
403 : :
404 [ - + ]: 37 : if (!env) {
405 : 0 : ERR("No <e:Envelope> found. %d", 0);
406 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "No SOAP Envelope found.", "IDStarMsgNotUnderstood", 0, 0, 0));
407 : 0 : D_DEDENT("valid: ");
408 : 0 : return 0;
409 : : }
410 : :
411 : 37 : hdr = env->Header;
412 [ + + ]: 37 : if (!hdr) {
413 : 1 : ERR("No <e:Header> found. %d", 0);
414 : 1 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "No SOAP Header found.", "IDStarMsgNotUnderstood", 0, 0, 0));
415 : 1 : D_DEDENT("valid: ");
416 : 1 : return 0;
417 : : }
418 [ + - + - : 36 : if (!ZX_SIMPLE_ELEM_CHK(hdr->MessageID)) {
+ - + - +
- - + ]
419 : 0 : ERR("No <a:MessageID> found. %d", 0);
420 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "No MessageID header found.", "IDStarMsgNotUnderstood", 0, 0, 0));
421 : 0 : D_DEDENT("valid: ");
422 : 0 : return 0;
423 : : }
424 : : /* Remember MessageID for generating RelatesTo in Response */
425 [ + - + - : 36 : ses->wsp_msgid = zx_dup_zx_str(cf->ctx, ZX_GET_CONTENT(hdr->MessageID));
+ - ]
426 : : DD("wsp_msgid(%.*s) %p %d %p", ses->wsp_msgid->len, ses->wsp_msgid->s, ses->wsp_msgid, ses->wsp_msgid->len, ses->wsp_msgid->s);
427 : :
428 [ + - - + : 36 : if (!hdr->Sender || !hdr->Sender->providerID && !hdr->Sender->affiliationID) {
# # ]
429 : 0 : ERR("No <b:Sender> found (or missing providerID or affiliationID). %p", hdr->Sender);
430 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "No b:Sender header found (or missing providerID or affiliationID).", "IDStarMsgNotUnderstood", 0, 0, 0));
431 : 0 : D_DEDENT("valid: ");
432 : 0 : return 0;
433 : : }
434 [ + - ]: 36 : ses->issuer = zx_dup_zx_str(cf->ctx, hdr->Sender->providerID?
435 : : &hdr->Sender->providerID->g : &hdr->Sender->affiliationID->g);
436 : :
437 : : /* Validate message signature (*** add Issuer trusted check, CA validation, etc.) */
438 : :
439 [ - + ]: 36 : if (!(sec = hdr->Security)) {
440 : 0 : ERR("No <wsse:Security> found. %d", 0);
441 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "No wsse:Security header found.", "IDStarMsgNotUnderstood", 0, 0, 0));
442 : 0 : D_DEDENT("valid: ");
443 : 0 : return 0;
444 : : }
445 : :
446 [ + - + - : 36 : if (!sec->Signature || !sec->Signature->SignedInfo || !sec->Signature->SignedInfo->Reference) {
- + ]
447 : 0 : ses->sigres = ZXSIG_NO_SIG;
448 [ # # ]: 0 : if (cf->wsp_nosig_fatal) {
449 : 0 : ERR("No Security/Signature found. %p", sec->Signature);
450 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "No wsse:Security/ds:Signature found.", TAS3_STATUS_NOSIG, 0, 0, 0));
451 : 0 : D_DEDENT("valid: ");
452 : 0 : return 0;
453 : : } else {
454 : 0 : INFO("No Security/Signature found, but configured to ignore this problem (NOSIG_FATAL=0). %p", sec->Signature);
455 : : }
456 : : }
457 : :
458 : 36 : wsc_meta = zxid_get_ent_ss(cf, ses->issuer);
459 [ + - ]: 36 : if (wsc_meta) {
460 : 36 : ZERO(refs, sizeof(refs));
461 : 36 : n_refs = zxid_hunt_sig_parts(cf, n_refs, refs, sec->Signature->SignedInfo->Reference, hdr, env->Body);
462 : : /* *** Consider adding BDY and STR */
463 : 36 : ses->sigres = zxsig_validate(cf->ctx, wsc_meta->sign_cert, sec->Signature, n_refs, refs);
464 : 36 : zxid_sigres_map(ses->sigres, &cgi.sigval, &cgi.sigmsg);
465 [ + - + + ]: 36 : if (cf->sig_fatal && ses->sigres) {
466 : 1 : ERR("Fail due to failed message signature sigres=%d", ses->sigres);
467 : 1 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "Message signature did not validate.", TAS3_STATUS_BADSIG, 0, 0, 0));
468 : 1 : D_DEDENT("valid: ");
469 : 1 : return 0;
470 : : }
471 : : } else {
472 : 0 : ses->sigres = ZXSIG_NO_SIG;
473 [ # # ]: 0 : if (cf->nosig_fatal) {
474 : 0 : INFO("Unable to find SAML metadata for Sender(%.*s), but configured to ignore this problem (NOSIG_FATAL=0).", ses->issuer->len, ses->issuer->s);
475 : : } else {
476 : 0 : ERR("Unable to find SAML metadata for Sender(%.*s).", ses->issuer->len, ses->issuer->s);
477 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "No unable to find SAML metadata for sender.", "ProviderIDNotValid", 0, 0, 0));
478 : 0 : D_DEDENT("valid: ");
479 : 0 : return 0;
480 : : }
481 : : }
482 : :
483 [ - + ]: 35 : if (!zxid_timestamp_chk(cf, ses, sec->Timestamp, &ourts, &ses->srcts, TAS3_PEP_RQ_IN,"e:Client"))
484 : 0 : return 0;
485 : :
486 : : /* Check Requester Identity */
487 : :
488 : 35 : ses->a7n = zxid_dec_a7n(cf, sec->Assertion, sec->EncryptedAssertion);
489 [ + - + - ]: 35 : if (ses->a7n && ses->a7n->Subject) {
490 [ + + ]: 35 : if (!zxid_wsf_validate_a7n(cf, ses, ses->a7n, "req", &ses->srcts)) {
491 : 4 : D_DEDENT("valid: ");
492 : 4 : return 0;
493 : : }
494 : : } else {
495 : : /* *** should there be absolute requirement for a requester assertion to exist? */
496 : 0 : ERR("No Requester <sa:Assertion> found. %p", ses->a7n);
497 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "No assertion found.", TAS3_STATUS_BADCOND, 0, 0, 0));
498 : 0 : D_DEDENT("valid: ");
499 : 0 : return 0;
500 : : }
501 : :
502 : : /* Check Target Identity */
503 : :
504 [ - + ]: 31 : if (hdr->TargetIdentity) {
505 : 0 : ses->tgta7n = zxid_dec_a7n(cf, hdr->TargetIdentity->Assertion, hdr->TargetIdentity->EncryptedAssertion);
506 [ # # # # ]: 0 : if (ses->tgta7n && ses->tgta7n->Subject) {
507 [ # # ]: 0 : if (!zxid_wsf_validate_a7n(cf, ses, ses->a7n, "tgt", &ses->srcts)) {
508 : 0 : D_DEDENT("valid: ");
509 : 0 : return 0;
510 : : }
511 : : } else {
512 : 0 : ERR("No TargetIdentity <sa:Assertion> found. %p", ses->tgta7n);
513 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "No TargetIdentity Assertion found.", TAS3_STATUS_BADCOND, 0, 0, 0));
514 : 0 : D_DEDENT("valid: ");
515 : 0 : return 0;
516 : : }
517 : :
518 : : } else {
519 : 31 : INFO("No explicit TargetIdentity, using requester identity as target identity. %d", 0);
520 : 31 : ses->tgta7n = ses->a7n;
521 : 31 : ses->tgtnameid = ses->nameid;
522 : 31 : ses->tgt = ses->nid;
523 : 31 : ses->tgtfmt = ses->nidfmt;
524 : 31 : ses->tgt_a7n_path = ses->sso_a7n_path;
525 : : }
526 : :
527 [ + - ]: 31 : if (hdr->UsageDirective) {
528 [ + - + - : 62 : if (hdr->UsageDirective->Obligation && ZX_GET_CONTENT(hdr->UsageDirective->Obligation->AttributeAssignment)) {
+ - + - ]
529 [ + - + - : 31 : ses->rcvd_usagedir = zx_str_to_c(cf->ctx, ZX_GET_CONTENT(hdr->UsageDirective->Obligation->AttributeAssignment));
+ - ]
530 [ + - - + ]: 31 : D("Found TAS3 UsageDirective with obligation(%s)", ses->rcvd_usagedir);
531 [ # # # # : 0 : } else if (ZX_GET_CONTENT(hdr->UsageDirective)) {
# # ]
532 [ # # # # : 0 : ses->rcvd_usagedir = zx_str_to_c(cf->ctx, ZX_GET_CONTENT(hdr->UsageDirective));
# # ]
533 [ # # # # ]: 0 : D("Found unknown UsageDirective(%s)", ses->rcvd_usagedir);
534 : : } else {
535 : 0 : ERR("UsageDirective empty or not understood. %p", hdr->UsageDirective->Dict);
536 : : }
537 : : }
538 : :
539 [ + - + - : 31 : if (hdr->UsageDirective && hdr->UsageDirective->Obligation
+ - + - ]
540 : : && ZX_STR_EQ(&hdr->UsageDirective->Obligation->ObligationId->g, TAS3_SOL1_ENGINE)) {
541 : : /* *** extract usage directive */
542 : : }
543 : :
544 : 31 : zxid_put_ses(cf, ses);
545 : 31 : zxid_ses_to_pool(cf, ses);
546 : 31 : zxid_snarf_eprs_from_ses(cf, ses); /* Harvest attributes and bootstrap(s) */
547 [ + - + - : 31 : zxid_put_user(cf, &ses->nameid->Format->g, &ses->nameid->NameQualifier->g, &ses->nameid->SPNameQualifier->g, ZX_GET_CONTENT(ses->nameid), 0);
+ - ]
548 : 31 : zxlogwsp(cf, ses, "K", "PNEWSES", ses->sid, 0);
549 : :
550 : : /* Call Rq-In PDP */
551 : :
552 [ - + ]: 31 : if (!zxid_localpdp(cf, ses)) {
553 : 0 : ERR("RQIN2 Deny by local PDP %d",0);
554 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_OUT, "e:Server", "Request denied by WSP local policy", TAS3_STATUS_DENY, 0, 0, 0));
555 : : /* Fall through, letting zxid_wsf_decor() pick up the fault and package it as response. */
556 [ + - + + ]: 31 : } else if (cf->pdp_url && *cf->pdp_url) {
557 : : //zxid_add_attr_to_pool(cf, ses, "Action", zx_dup_str(cf->ctx, "access"));
558 [ - + ]: 13 : if (!zxid_pep_az_soap_pepmap(cf, 0, ses, cf->pdp_url, cf->pepmap_rqin)) {
559 : 0 : ERR("RQIN2 Deny %d", 0);
560 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Server", "Request denied by WSP policy", TAS3_STATUS_DENY, 0, 0, 0));
561 : 0 : D_DEDENT("valid: ");
562 : 0 : return 0;
563 : : }
564 : : }
565 : :
566 : 31 : D_DEDENT("valid: ");
567 : 31 : return ses->tgt;
568 : : }
569 : :
570 : : /*(i) Validate SOAP request (envelope), specified by the string.
571 : : *
572 : : * If the string starts by "<e:Envelope", then string
573 : : * should be a complete SOAP envelope including <e:Header> (and <e:Body>)
574 : : * parts.
575 : : *
576 : : * cf:: ZXID configuration object, see zxid_new_conf()
577 : : * ses:: Session object that contains the EPR cache
578 : : * az_cred:: (Optional) Additional authorization credentials or
579 : : * attributes, query string format. These credentials will be populated
580 : : * to the attribute pool in addition to the ones obtained from token and
581 : : * other sources. Then a PDP is called to get an authorization
582 : : * decision (matching obligations we support to those in the request,
583 : : * and obligations pleged by caller to those we insist on). See
584 : : * also PEPMAP configuration option. This implements generalized
585 : : * (application independent) Responder In PEP. To implement
586 : : * application dependent PEP features you should call zxid_az() directly.
587 : : * env:: Entire SOAP envelope as a string
588 : : * return:: idpnid of target identity of the request (rest of the information
589 : : * is populated to the session object, from where it can be retrieved).
590 : : * NULL if the validation fails. The target identity is still retrievable
591 : : * from the session, should there be desire to process the message despite
592 : : * the validation failure.
593 : : *
594 : : * See also: zxid_wsc_validate_resp_env() */
595 : :
596 : : /* Called by: main, zxidwspcgi_main */
597 : : char* zxid_wsp_validate(zxid_conf* cf, zxid_ses* ses, const char* az_cred, const char* enve)
598 : 17 : {
599 : : struct zx_str ss;
600 : : char* p;
601 : : char msg[256];
602 : : struct zx_str* logpath;
603 : : struct zx_root_s* r;
604 : :
605 : 17 : ss.s = (char*)enve;
606 : 17 : ss.len = strlen(enve);
607 : 17 : D_XML_BLOB(cf, "WSP_VALIDATE", ss.len, ss.s);
608 : 17 : r = zx_dec_zx_root(cf->ctx, ss.len, enve, "valid");
609 [ - + ]: 17 : if (!r) {
610 : 0 : zx_format_parse_error(cf->ctx, msg, sizeof(msg), "valid");
611 : 0 : ERR("Malformed XML: %s", msg);
612 : : /* Squash " to ' because the message will appear in XML attribute value delimited by " */
613 [ # # ]: 0 : for (p = msg; *p; ++p)
614 [ # # ]: 0 : if (*p == '"')
615 : 0 : *p = '\'';
616 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RQ_IN, "e:Client", "Malformed XML", "IDStarMsgNotUnderstood", 0, msg, 0));
617 : 0 : return 0;
618 : : }
619 : 17 : p = zxid_wsp_validate_env(cf, ses, az_cred, r->Envelope);
620 : 17 : ZX_FREE(cf->ctx, r);
621 : :
622 : 17 : logpath = zxlog_path(cf, ses->issuer, ses->wsp_msgid, ZXLOG_RELY_DIR, ZXLOG_MSG_KIND, 1);
623 [ - + ]: 17 : if (zxlog_dup_check(cf, logpath, "validate request")) {
624 [ # # ]: 0 : if (cf->dup_msg_fatal) {
625 : 0 : zxlog_blob(cf, cf->log_rely_msg, logpath, &ss, "validate request dup err");
626 : 0 : zxid_set_fault(cf, ses, zxid_mk_fault(cf, 0, TAS3_PEP_RS_IN, "e:Client", "Duplicate Message.", "DuplicateMsg", 0, 0, 0));
627 : 0 : D_DEDENT("valid: ");
628 : 0 : return 0;
629 : : } else {
630 : 0 : INFO("Duplicate message detected, but configured to ignore this (DUP_MSG_FATAL=0). %d",0);
631 : : }
632 : : }
633 : 17 : zxlog_blob(cf, cf->log_rely_msg, logpath, &ss, "validate request");
634 : 17 : zxlogwsp(cf, ses, "K", "VALID", logpath->s, 0);
635 : 17 : return p;
636 : : }
637 : :
638 : : /* EOF -- zxidwsp.c */
|