Branch data Line data Source code
1 : : /* zxidecp.c - Handwritten functions for implementing Enhanced Client Proxy and SP
2 : : * Copyright (c) 2010 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3 : : * Copyright (c) 2006-2008 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: zxidecp.c,v 1.10 2008-10-08 03:56:55 sampo Exp $
10 : : *
11 : : * 12.8.2006, created --Sampo
12 : : * 16.1.2007, split from zxidlib.c --Sampo
13 : : * 7.10.2008, added documentation --Sampo
14 : : * 14.3.2010, reformed eid presentation --Sampo
15 : : *
16 : : * See: zxid_sp_soap_dispatch() in zxidslo.c for handling PAOS response
17 : : *
18 : : * If you do not know what PAOS, ECP or LECP means, you should read SAML2 Profiles specification.
19 : : */
20 : :
21 : : #include <stdio.h>
22 : : #include <stdlib.h>
23 : :
24 : : #include "errmac.h"
25 : : #include "zxid.h"
26 : : #include "zxidpriv.h"
27 : : #include "zxidconf.h"
28 : : #include "saml2.h"
29 : : #include "c/zx-const.h"
30 : : #include "c/zx-paos-data.h"
31 : :
32 : : extern char **environ;
33 : :
34 : : /*() Generate SOAP headers for use with PAOS carried SAML2 ECP profile AuthnRequest.
35 : : *
36 : : * If you do not know what PAOS, ECP or LECP means, you should read [SAML2bind] specification. */
37 : :
38 : : /* Called by: zxid_lecp_check */
39 : : static struct zx_paos_Request_s* zxid_mk_paos_Request_hdr(zxid_conf* cf)
40 : 1 : {
41 : 1 : struct zx_paos_Request_s* hdr= zx_NEW_paos_Request(cf->ctx,0);
42 : 1 : hdr->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
43 : 1 : hdr->actor = zx_ref_attr(cf->ctx, &hdr->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
44 : 1 : hdr->service = zx_ref_attr(cf->ctx, &hdr->gg, zx_service_ATTR, SAML2_SSO_ECP);
45 : 1 : hdr->responseConsumerURL = zx_attrf(cf->ctx, &hdr->gg, zx_responseConsumerURL_ATTR, "%s?o=P", cf->url);
46 : : /*hdr->messageID = zx_ref_str(cf->ctx, "1"); OPTIONAL */
47 : 1 : return hdr;
48 : : }
49 : :
50 : : /*() Build IDPList of IDPEntry(s) from the IdPs know to us at the moment (our CoT).
51 : : * Can be used for ECP and IdP proxying.
52 : : *
53 : : * cf:: ZXID configuration object, used to locate the CoT directory (PATH
54 : : * configuration option) and for memory allocation
55 : : * binding:: The SSO protocol binding the qualifying IdPs MUST support, or 0 if anything goes
56 : : * return:: IdP list data structure or 0 on failure */
57 : :
58 : : /* Called by: zxid_mk_ecp_Request_hdr */
59 : : static struct zx_sp_IDPList_s* zxid_mk_idp_list(zxid_conf* cf, char* binding)
60 : 1 : {
61 : : zxid_entity* idp;
62 : : struct zx_md_SingleSignOnService_s* sso_svc;
63 : : struct zx_sp_IDPList_s* idp_list;
64 : : struct zx_sp_IDPEntry_s* idp_entry;
65 : :
66 : 1 : idp = zxid_load_cot_cache(cf);
67 [ - + ]: 1 : if (!idp)
68 : 0 : return 0;
69 : :
70 : 1 : idp_list = zx_NEW_sp_IDPList(cf->ctx,0);
71 [ + + ]: 20 : for (; idp; idp = idp->n) {
72 [ - + # # ]: 19 : D("IDPList consider idp(%s)", idp->eid);
73 [ + + ]: 19 : if (!idp->ed->IDPSSODescriptor)
74 : 6 : continue;
75 : 13 : for (sso_svc = idp->ed->IDPSSODescriptor->SingleSignOnService;
76 [ + + + + ]: 43 : sso_svc && sso_svc->gg.g.tok == zx_md_SingleSignOnService_ELEM;
77 : 17 : sso_svc = (struct zx_md_SingleSignOnService_s*)sso_svc->gg.g.n)
78 [ + - + + ]: 19 : if (sso_svc->Binding && !memcmp(binding, sso_svc->Binding->g.s, sso_svc->Binding->g.len))
79 : 2 : break;
80 [ + + ]: 13 : if (!sso_svc) {
81 [ - + # # ]: 7 : D("Entity(%s) does not have any IdP SSO Service with binding(%s)", idp->eid, binding);
82 : 7 : continue; /* Not eligible IdP, next one please. */
83 : : }
84 : :
85 : 6 : idp_list->IDPEntry = idp_entry = zx_NEW_sp_IDPEntry(cf->ctx, &idp_list->gg);
86 : 6 : idp_entry->ProviderID = zx_ref_attr(cf->ctx, &idp_entry->gg, zx_ProviderID_ATTR, idp->eid);
87 : 6 : idp_entry->Name = zx_ref_attr(cf->ctx, &idp_entry->gg, zx_Name_ATTR, idp->dpy_name);
88 : 6 : idp_entry->Loc = sso_svc->Location;
89 : : }
90 : 1 : return idp_list;
91 : : }
92 : :
93 : : /*() Generate headers for use with Liberty ID-FF 1.2 LECP carried AuthnRequest.
94 : : *
95 : : * If you do not know what PAOS, ECP or LECP means, you should read [SAML2bind] specification. */
96 : :
97 : : /* Called by: zxid_lecp_check */
98 : : static struct zx_ecp_Request_s* zxid_mk_ecp_Request_hdr(zxid_conf* cf)
99 : 1 : {
100 : 1 : struct zx_ecp_Request_s* hdr= zx_NEW_ecp_Request(cf->ctx,0);
101 : 1 : hdr->mustUnderstand = zx_ref_attr(cf->ctx, &hdr->gg, zx_e_mustUnderstand_ATTR, XML_TRUE);
102 : 1 : hdr->actor = zx_ref_attr(cf->ctx, &hdr->gg, zx_e_actor_ATTR, SOAP_ACTOR_NEXT);
103 : : /*hdr->IsPassive = zx_ref_attr(cf->ctx, &hdr->gg, zx_IsPassive_ATTR, XML_TRUE); OPTIONAL, default=? */
104 : 1 : hdr->ProviderName = zxid_my_ent_id_attr(cf, &hdr->gg, zx_ProviderName_ATTR); /* *** Friendly name? */
105 : 1 : hdr->Issuer = zxid_my_issuer(cf, &hdr->gg);
106 : 1 : hdr->IDPList = zxid_mk_idp_list(cf, SAML2_SOAP);
107 : 1 : return hdr;
108 : : }
109 : :
110 : : /* ============== LECP or ECP ============== */
111 : :
112 : : /*() Check for ECP indications in HTTP request headers and initiate
113 : : * PAOS based Single Sign On, i.e AuthnRequest. This is part of the
114 : : * SAML2 Enhanced Client Proxy profile.
115 : : *
116 : : * Limitation:: Current (2008) code only works in CGI environment due to
117 : : * reliance on environment variables. (*** fixme)
118 : : *
119 : : * If you do not know what PAOS, ECP or LECP means, you should read [SAML2bind] specification. */
120 : :
121 : : /* Called by: main x4, zxid_simple_no_ses_cf x2 */
122 : : struct zx_str* zxid_lecp_check(zxid_conf* cf, zxid_cgi* cgi)
123 : 8 : {
124 : : struct zx_e_Envelope_s* se;
125 : : struct zx_str* env;
126 : : struct zx_str* req;
127 : : char* le;
128 : : #if 0
129 : : char** pp;
130 : : for (pp = environ; *pp; ++pp) /* Debug envirnment problems, e.g. mini_httpd does not pass HTTP_PAOS, unless patched. */
131 : : D("ENV(%s)", *pp);
132 : : #endif
133 : :
134 : 8 : le = getenv("HTTP_PAOS");
135 [ + + ]: 8 : if (!le) {
136 : 7 : le = getenv("HTTP_LIBERTY_ENABLED");
137 [ + - ]: 7 : if (!le) {
138 [ + - - + ]: 7 : D("Neither ECP nor LECP request %d", 0);
139 : 7 : return 0; /* No ECP/LECP detected, return to normal processing. */
140 : : }
141 [ # # # # ]: 0 : D("LECP detected HTTP_LIBERTY_ENABLED(%s) (*** NOT IMPLEMENTED)", le);
142 : : /* *** start ID-FF 1.2 LECP processing */
143 : 0 : return 0; /* ars = ...; */
144 : : }
145 [ - + # # ]: 1 : D("ECP detected HTTP_PAOS(%s)", le);
146 [ - + ]: 1 : if (!strstr(le, SAML2_SSO_ECP))
147 : 0 : return 0;
148 : :
149 : : /* SAML 2.0 ECP: Create PAOS request to be sent in HTTP response. */
150 : :
151 : 1 : se = zx_NEW_e_Envelope(cf->ctx,0);
152 : 1 : se->Body = zx_NEW_e_Body(cf->ctx, &se->gg);
153 : 1 : se->Body->AuthnRequest = zxid_mk_authn_req(cf, cgi);
154 : 1 : se->Header = zx_NEW_e_Header(cf->ctx, &se->gg);
155 : 1 : se->Header->Request = zxid_mk_paos_Request_hdr(cf);
156 : 1 : se->Header->ecp_Request = zxid_mk_ecp_Request_hdr(cf);
157 : 1 : env = zx_easy_enc_elem_opt(cf, &se->gg);
158 : 1 : req = zx_strf(cf->ctx,
159 : : "Cache-Control: no-cache, no-store, must-revalidate, private" CRLF
160 : : "Pragma: no-cache" CRLF
161 : : "Content-Type: " PAOS_CONTENT CRLF /* content type only specified for ECP */
162 : : "Content-Length: %d" CRLF2
163 : : "%.*s", env->len, env->len, env->s);
164 : 1 : zx_str_free(cf->ctx, env);
165 : 1 : return req;
166 : : }
167 : :
168 : : /* EOF -- zxidecp.c */
|