Branch data Line data Source code
1 : : /* zxidloc.c - Handwritten functions implementing service locator (based on metadata)
2 : : * Copyright (c) 2006-2008 Symlabs (symlabs@symlabs.com), All Rights Reserved.
3 : : * Author: Sampo Kellomaki (sampo@iki.fi)
4 : : * This is confidential unpublished proprietary source code of the author.
5 : : * NO WARRANTY, not even implied warranties. Contains trade secrets.
6 : : * Distribution prohibited unless authorized in writing.
7 : : * Licensed under Apache License 2.0, see file COPYING.
8 : : * $Id: zxidloc.c,v 1.13 2010-01-08 02:10:09 sampo Exp $
9 : : *
10 : : * 12.8.2006, created --Sampo
11 : : * 16.1.2007, split from zxidlib.c --Sampo
12 : : * 7.10.2008, added documentation --Sampo
13 : : */
14 : :
15 : : #include <string.h>
16 : : #include <stdio.h>
17 : : #include <stdlib.h>
18 : :
19 : : #include "errmac.h"
20 : : #include "zxid.h"
21 : : #include "zxidutil.h"
22 : : #include "zxidconf.h"
23 : : #include "saml2.h"
24 : : #include "c/zx-data.h"
25 : :
26 : : /* err_res = "ERR-metadata-does-not-have-url-for-binding";*/
27 : :
28 : : /* ============== IdP Service Locator ============= */
29 : :
30 : : /* *** figure out a way to leverage commonality. */
31 : :
32 : : /*() Raw computation of IdP URL given service type, binding, and whether operation is a
33 : : * request. See zxid_idp_loc() for full description. */
34 : :
35 : : /* Called by: zxid_idp_loc x3, zxid_slo_resp_redir, zxid_sp_dispatch */
36 : : struct zx_str* zxid_idp_loc_raw(zxid_conf* cf, zxid_cgi* cgi,
37 : : zxid_entity* idp_meta, int svc_type, char* binding, int req)
38 : 4 : {
39 : : struct zx_str* loc;
40 : : struct zx_md_SingleLogoutService_s* slo_svc;
41 : : struct zx_md_ManageNameIDService_s* mni_svc;
42 : :
43 [ + - + - : 4 : if (!idp_meta || !idp_meta->eid || !idp_meta->ed->IDPSSODescriptor) {
+ + ]
44 [ + - + - ]: 2 : ERR("Entity(%s) does not have IdP SSO Descriptor (metadata problem)", idp_meta?STRNULLCHKQ(idp_meta->eid):"-");
45 : 2 : return 0;
46 : : }
47 : :
48 [ + - - ]: 2 : switch (svc_type) {
49 : : case ZXID_SLO_SVC:
50 : 2 : for (slo_svc = idp_meta->ed->IDPSSODescriptor->SingleLogoutService;
51 [ + - + - ]: 4 : slo_svc && slo_svc->gg.g.tok == zx_md_SingleLogoutService_ELEM;
52 : 0 : slo_svc = (struct zx_md_SingleLogoutService_s*)slo_svc->gg.g.n)
53 [ + - + - : 2 : if (slo_svc->Binding && !memcmp(binding, slo_svc->Binding->g.s, slo_svc->Binding->g.len)
+ - ]
54 : : /*&& svc->index && !memcmp(end_pt_ix, svc->index->s, svc->index->len)*/
55 : : && slo_svc->Location)
56 : 2 : break;
57 [ + - ]: 2 : if (!slo_svc)
58 : 0 : break;
59 [ + - # # ]: 2 : loc = req ? &slo_svc->Location->g : (slo_svc->ResponseLocation ? &slo_svc->ResponseLocation->g : &slo_svc->Location->g);
60 [ - + ]: 2 : if (!loc)
61 : 0 : break;
62 : 2 : return loc;
63 : : case ZXID_MNI_SVC:
64 : 0 : for (mni_svc = idp_meta->ed->IDPSSODescriptor->ManageNameIDService;
65 [ # # # # ]: 0 : mni_svc && mni_svc->gg.g.tok == zx_md_ManageNameIDService_ELEM;
66 : 0 : mni_svc = (struct zx_md_ManageNameIDService_s*)mni_svc->gg.g.n)
67 [ # # # # : 0 : if (mni_svc->Binding && !memcmp(binding, mni_svc->Binding->g.s, mni_svc->Binding->g.len)
# # ]
68 : : /*&& svc->index && !memcmp(end_pt_ix, svc->index->s, svc->index->len)*/
69 : : && mni_svc->Location)
70 : 0 : break;
71 [ # # ]: 0 : if (!mni_svc)
72 : 0 : break;
73 [ # # # # ]: 0 : loc = req ? &mni_svc->Location->g : (mni_svc->ResponseLocation ? &mni_svc->ResponseLocation->g : &mni_svc->Location->g);
74 [ # # ]: 0 : if (!loc)
75 : 0 : break;
76 : 0 : return loc;
77 : : }
78 : :
79 : 0 : ERR("IdP Entity(%s) does not have any %d service with binding(%s) (metadata problem)", idp_meta->eid, svc_type, binding);
80 : 0 : return 0;
81 : : }
82 : :
83 : : /*() SAML2 service locator. Given desired service, like SLO or MNI, and possibly binding,
84 : : * locate the appropriate service descriptor from the IdP metadata.
85 : : *
86 : : * cf:: ZXID configuration object, used for preferences and for memory allocation
87 : : * cgi:: May contain CGI variables that further indicate preference. Often specified
88 : : * as 0 (no preference).
89 : : * ses:: Session object, which may be used to remember historical events, such as
90 : : * binding of SSO transaction, that may act as preferences for binding. The
91 : : * session MUST have assertion.
92 : : * idp_meta:: Metadata for the IdP
93 : : * svc_type:: The desired service, indicated as URN
94 : : * binding:: preferred binding URN, or 0 if no preference. In that case the built in
95 : : * preference is used, or if that is indifferent, then first applicable metadata
96 : : * item is picked. If IdP only supports one binding 0 will match that. If nonzero,
97 : : * then the IdP metadata MUST have exactly matching entry or else 0 is returned.
98 : : * return:: URL for accessing the service or 0 upon failure
99 : : *
100 : : * *Limitation:* If binding is not specified, it may be ambiguous what binding the returned
101 : : * URL relates to. Generally the decision will have been taken prior to calling
102 : : * this function. */
103 : :
104 : : /* Called by: zxid_idp_soap, zxid_sp_mni_redir, zxid_sp_slo_redir */
105 : : struct zx_str* zxid_idp_loc(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses,
106 : : zxid_entity* idp_meta, int svc_type, char* binding)
107 : 2 : {
108 : 2 : zxid_get_ses_sso_a7n(cf, ses);
109 : :
110 [ + - ]: 2 : if (ses->a7n) {
111 : 2 : return zxid_idp_loc_raw(cf, cgi, idp_meta, svc_type, binding, 1);
112 : : }
113 [ # # ]: 0 : if (ses->a7n11) {
114 : 0 : ERR("Not implemented: obtaining location from SAML 1.1 assetion %d", 0);
115 : : //return zxid_idp_loc_raw(cf, cgi, ses->a7n->Issuer, svc_type, binding, 1);
116 : : }
117 [ # # ]: 0 : if (ses->a7n12) {
118 : 0 : ERR("Not implemented: obtaining location from ID-FF 1.2 type SAML 1.1 assetion %d", 0);
119 : : //return zxid_idp_loc_raw(cf, cgi, ses->a7n->Issuer, svc_type, binding, 1);
120 : : }
121 : :
122 : 0 : ERR("Session sid(%s) appears to lack SSO assertion.", ses->sid);
123 : 0 : return 0;
124 : : }
125 : :
126 : : /*() Deternine URL for SOAP binding to given service and perform a SOAP call.
127 : : *
128 : : * cf:: ZXID configuration object
129 : : * cgi:: CGI variables that may influence determination of end point. Or 0 if no preference.
130 : : * ses:: Session information that may influence the choice of the end point. The
131 : : * session MUST have asserion.
132 : : * idp_meta:: Metadata for the IdP
133 : : * svc_type:: The desired service, indicated as URN
134 : : * body:: XML data structure for the SOAP call <Body> element payload
135 : : * return:: XML data structure for Body element of the SOAP call response. */
136 : :
137 : : /* Called by: zxid_az_soap, zxid_sp_mni_soap, zxid_sp_slo_soap */
138 : : struct zx_root_s* zxid_idp_soap(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses,
139 : : zxid_entity* idp_meta, int svc_type, struct zx_e_Body_s* body)
140 : 0 : {
141 : : struct zx_root_s* r;
142 : 0 : struct zx_str* loc = zxid_idp_loc(cf, cgi, ses, idp_meta, svc_type, SAML2_SOAP);
143 [ # # ]: 0 : if (!loc)
144 : 0 : return 0;
145 : 0 : r = zxid_soap_call_hdr_body(cf, loc, 0, body);
146 : 0 : zx_str_free(cf->ctx, loc);
147 : 0 : return r;
148 : : }
149 : :
150 : : /* ============== SP Service Locator ============= */
151 : :
152 : : /* *** figure out a way to leverage commonality. */
153 : :
154 : : /* Called by: zxid_idp_sso */
155 : : struct zx_str* zxid_sp_loc_by_index_raw(zxid_conf* cf, zxid_cgi* cgi,
156 : : zxid_entity* sp_meta, int svc_type,
157 : : struct zx_str* ix, int* binding)
158 : 0 : {
159 : : struct zx_str* loc;
160 : : struct zx_md_AssertionConsumerService_s* acs_svc;
161 : :
162 [ # # # # : 0 : if (!sp_meta || !sp_meta->eid || !sp_meta->ed->SPSSODescriptor) {
# # ]
163 [ # # # # ]: 0 : ERR("Entity(%s) does not have SP SSO Descriptor (metadata problem)", sp_meta?STRNULLCHKQ(sp_meta->eid):"-");
164 : 0 : return 0;
165 : : }
166 : :
167 [ # # ]: 0 : switch (svc_type) {
168 : : case ZXID_ACS_SVC:
169 : 0 : for (acs_svc = sp_meta->ed->SPSSODescriptor->AssertionConsumerService;
170 [ # # # # ]: 0 : acs_svc && acs_svc->gg.g.tok == zx_md_AssertionConsumerService_ELEM;
171 : 0 : acs_svc = (struct zx_md_AssertionConsumerService_s*)acs_svc->gg.g.n)
172 [ # # # # : 0 : if (acs_svc->index && ix->len == acs_svc->index->g.len
# # # # ]
173 : : && !memcmp(ix->s, acs_svc->index->g.s, ix->len)
174 : : && acs_svc->Location)
175 : 0 : break;
176 [ # # ]: 0 : if (!acs_svc)
177 : 0 : break;
178 : 0 : loc = &acs_svc->Location->g;
179 [ # # ]: 0 : if (!loc)
180 : 0 : break;
181 : 0 : *binding = zxid_protocol_binding_map_saml2(&acs_svc->Binding->g);
182 : 0 : return loc;
183 : : }
184 : :
185 : 0 : ERR("SP Entity(%s) does not have any %d service with index(%.*s) (metadata problem)", sp_meta->eid, svc_type, ix->len, ix->s);
186 : 0 : *binding = 0;
187 : 0 : return 0;
188 : : }
189 : :
190 : :
191 : : /*() Raw computation of SP URL given service type, binding, and whether operation is a
192 : : * request. See zxid_sp_loc() for full description.
193 : : *
194 : : * return:: URL for the protocol end point, or 0 on failure */
195 : :
196 : : /* Called by: zxid_idp_dispatch, zxid_idp_sso x2, zxid_slo_resp_redir, zxid_sp_loc x3 */
197 : : struct zx_str* zxid_sp_loc_raw(zxid_conf* cf, zxid_cgi* cgi, zxid_entity* sp_meta, int svc_type, char* binding, int req)
198 : 7 : {
199 : : struct zx_str* loc;
200 : : struct zx_md_SingleLogoutService_s* slo_svc;
201 : : struct zx_md_ManageNameIDService_s* mni_svc;
202 : : struct zx_md_AssertionConsumerService_s* acs_svc;
203 : :
204 [ + - + - : 7 : if (!sp_meta || !sp_meta->eid || !sp_meta->ed->SPSSODescriptor) {
- + ]
205 [ # # # # ]: 0 : ERR("Entity(%s) does not have SP SSO Descriptor (metadata problem)", sp_meta?STRNULLCHKQ(sp_meta->eid):"-");
206 : 0 : return 0;
207 : : }
208 : :
209 [ + - + - ]: 7 : switch (svc_type) {
210 : : case ZXID_SLO_SVC:
211 : 2 : for (slo_svc = sp_meta->ed->SPSSODescriptor->SingleLogoutService;
212 [ + - + - ]: 4 : slo_svc && slo_svc->gg.g.tok == zx_md_SingleLogoutService_ELEM;
213 : 0 : slo_svc = (struct zx_md_SingleLogoutService_s*)slo_svc->gg.g.n)
214 [ + - + - : 2 : if (slo_svc->Binding && !memcmp(binding, slo_svc->Binding->g.s, slo_svc->Binding->g.len)
+ - ]
215 : : /*&& svc->index && !memcmp(end_pt_ix, svc->index->s, svc->index->len)*/
216 : : && slo_svc->Location)
217 : 2 : break;
218 [ + - ]: 2 : if (!slo_svc)
219 : 0 : break;
220 [ - + + - ]: 2 : loc = req ? &slo_svc->Location->g : (slo_svc->ResponseLocation ? &slo_svc->ResponseLocation->g : &slo_svc->Location->g);
221 [ - + ]: 2 : if (!loc)
222 : 0 : break;
223 : 2 : return loc;
224 : : case ZXID_MNI_SVC:
225 : 0 : for (mni_svc = sp_meta->ed->SPSSODescriptor->ManageNameIDService;
226 [ # # # # ]: 0 : mni_svc && mni_svc->gg.g.tok == zx_md_ManageNameIDService_ELEM;
227 : 0 : mni_svc = (struct zx_md_ManageNameIDService_s*)mni_svc->gg.g.n)
228 [ # # # # : 0 : if (mni_svc->Binding && !memcmp(binding, mni_svc->Binding->g.s, mni_svc->Binding->g.len)
# # ]
229 : : /*&& svc->index && !memcmp(end_pt_ix, svc->index->s, svc->index->len)*/
230 : : && mni_svc->Location)
231 : 0 : break;
232 [ # # ]: 0 : if (!mni_svc)
233 : 0 : break;
234 [ # # # # ]: 0 : loc = req ? &mni_svc->Location->g : (mni_svc->ResponseLocation ? &mni_svc->ResponseLocation->g : &mni_svc->Location->g);
235 [ # # ]: 0 : if (!loc)
236 : 0 : break;
237 : 0 : return loc;
238 : : case ZXID_ACS_SVC:
239 : 5 : for (acs_svc = sp_meta->ed->SPSSODescriptor->AssertionConsumerService;
240 [ + - + - ]: 25 : acs_svc && acs_svc->gg.g.tok == zx_md_AssertionConsumerService_ELEM;
241 : 15 : acs_svc = (struct zx_md_AssertionConsumerService_s*)acs_svc->gg.g.n)
242 [ + - + + : 20 : if (acs_svc->Binding && !memcmp(binding, acs_svc->Binding->g.s, acs_svc->Binding->g.len)
+ - ]
243 : : /*&& svc->index && !memcmp(end_pt_ix, svc->index->s, svc->index->len)*/
244 : : && acs_svc->Location)
245 : 5 : break;
246 [ - + ]: 5 : if (!acs_svc)
247 : 0 : break;
248 : 5 : loc = &acs_svc->Location->g;
249 [ - + ]: 5 : if (!loc)
250 : 0 : break;
251 : 5 : return loc;
252 : : }
253 : :
254 : 0 : ERR("SP Entity(%s) does not have any %d service with binding(%s) (metadata problem)", sp_meta->eid, svc_type, binding);
255 : 0 : return 0;
256 : : }
257 : :
258 : : /*() SAML2 service locator for SP. Given desired service, like SLO or MNI, and possibly binding,
259 : : * locate the appropriate service descriptor from the Sp metadata.
260 : : *
261 : : * cf:: ZXID configuration object, used for preferences and for memory allocation
262 : : * cgi:: May contain CGI variables that further indicate preference. Often specified
263 : : * as 0 (no preference).
264 : : * ses:: Session object, which may be used to remember historical events, such as
265 : : * binding of SSO transaction, that may act as preferences for binding. The
266 : : * session MUST have assertion.
267 : : * sp_meta:: Metadata for the Sp
268 : : * svc_type:: The desired service, indicated as URN
269 : : * binding:: preferred binding URN, or 0 if no preference. In that case the built in
270 : : * preference is used, or if that is indifferent, then first applicable metadata
271 : : * item is picked. If Sp only supports one binding 0 will match that. If nonzero,
272 : : * then the Sp metadata MUST have exactly matching entry or else 0 is returned.
273 : : * return:: URL for accessing the service or 0 upon failure
274 : : *
275 : : * *Limitation:* If binding is not specified, it may be ambiguous what binding the returned
276 : : * URL relates to. Generally the decision will have been taken prior to calling
277 : : * this function. */
278 : :
279 : : /* Called by: zxid_sp_soap */
280 : : struct zx_str* zxid_sp_loc(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, zxid_entity* sp_meta, int svc_type, char* binding)
281 : 0 : {
282 : 0 : zxid_get_ses_sso_a7n(cf, ses);
283 : :
284 [ # # ]: 0 : if (ses->a7n) {
285 : 0 : return zxid_sp_loc_raw(cf, cgi, sp_meta, svc_type, binding, 1);
286 : : }
287 [ # # ]: 0 : if (ses->a7n11) {
288 : 0 : ERR("Not implemented: obtaining location from SAML 1.1 assetion %d", 0);
289 : : //return zxid_sp_loc_raw(cf, cgi, ses->a7n->Issuer, svc_type, binding, 1);
290 : : }
291 [ # # ]: 0 : if (ses->a7n12) {
292 : 0 : ERR("Not implemented: obtaining location from ID-FF 1.2 type SAML 1.1 assetion %d", 0);
293 : : //return zxid_sp_loc_raw(cf, cgi, ses->a7n->Issuer, svc_type, binding, 1);
294 : : }
295 : :
296 : 0 : ERR("Session sid(%s) appears to lack SSO assertion.", ses->sid);
297 : 0 : return 0;
298 : : }
299 : :
300 : : /*() Deternine URL for SOAP binding to given service on SP and perform a SOAP call.
301 : : *
302 : : * cf:: ZXID configuration object
303 : : * cgi:: CGI variables that may influence determination of end point. Or 0 if no preference.
304 : : * ses:: Session information that may influence the choice of the end point. The
305 : : * session MUST have asserion.
306 : : * sp_meta:: Metadata for the Sp
307 : : * svc_type:: The desired service, indicated as URN
308 : : * body:: XML data structure for the SOAP call <Body> element payload
309 : : * return:: XML data structure for Body element of the SOAP call response. */
310 : :
311 : : /* Called by: */
312 : : struct zx_root_s* zxid_sp_soap(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, zxid_entity* sp_meta, int svc_type, struct zx_e_Body_s* body)
313 : 0 : {
314 : : struct zx_root_s* r;
315 : 0 : struct zx_str* loc = zxid_sp_loc(cf, cgi, ses, sp_meta, svc_type, SAML2_SOAP);
316 [ # # ]: 0 : if (!loc)
317 : 0 : return 0;
318 : 0 : r = zxid_soap_call_hdr_body(cf, loc, 0, body);
319 : 0 : zx_str_free(cf->ctx, loc);
320 : 0 : return r;
321 : : }
322 : :
323 : : /* EOF -- zxidloc.c */
|