1 /* zxididpx.c - Handwritten functions for IdP dispatch
2 * Copyright (c) 2008-2011 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3 * This is confidential unpublished proprietary source code of the author.
4 * NO WARRANTY, not even implied warranties. Contains trade secrets.
5 * Distribution prohibited unless authorized in writing.
6 * Licensed under Apache License 2.0, see file COPYING.
7 * $Id: zxididpx.c,v 1.10 2010-01-08 02:10:09 sampo Exp $
8 *
9 * 14.11.2008, created --Sampo
10 * 12.2.2010, added locking to lazy loading --Sampo
11 * 11.12.2011, added OAUTH2 and OpenID-Connect support --Sampo
12 *
13 * TODO: *** Review of all of IdP SLO and MNI code
14 */
15
16 #include "platform.h"
17 #include "errmac.h"
18 #include "zxid.h"
19 #include "zxidpriv.h"
20 #include "zxidconf.h"
21 #include "saml2.h"
22 #include "c/zx-const.h"
23 #include "c/zx-ns.h"
24 #include "c/zx-data.h"
25
26 /* ============== Dispatch incoming requests and responses ============== */
27
28 /*() Dispatch redirect and post binding requests.
29 *
30 * return:: a string (such as Location: header) and let the caller output it. */
31
32 /* Called by: zxid_simple_ses_active_cf x2 */
zxid_idp_dispatch(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses,int chk_dup)33 struct zx_str* zxid_idp_dispatch(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, int chk_dup)
34 {
35 struct zx_sp_LogoutRequest_s* req;
36 zxid_entity* sp_meta;
37 struct zx_str* loc;
38 struct zx_str* ss;
39 struct zx_str* ss2;
40 struct zx_root_s* r;
41 ses->sigres = ZXSIG_NO_SIG;
42
43 if (cgi->response_type) /* OAUTH2 / OpenID-Connect */
44 return zxid_oauth2_az_server_sso(cf, cgi, ses);
45
46 r = zxid_decode_redir_or_post(cf, cgi, ses, chk_dup);
47 if (!r)
48 return zx_dup_str(cf->ctx, "* ERR");
49
50 if (r->AuthnRequest)
51 return zxid_idp_sso(cf, cgi, ses, r->AuthnRequest);
52
53 if (req = r->LogoutRequest) {
54 D("IdP SLO %d", 0);
55 if (cf->idp_ena) { /* *** Kludgy check */
56 if (!zxid_idp_slo_do(cf, cgi, ses, req))
57 return zx_dup_str(cf->ctx, "* ERR");
58 } else {
59 if (!zxid_sp_slo_do(cf, cgi, ses, req))
60 return zx_dup_str(cf->ctx, "* ERR");
61 }
62 /* *** Need to do much more to log out all other SPs of the session. */
63 return zxid_slo_resp_redir(cf, cgi, req);
64 }
65
66 if (r->LogoutResponse) {
67 if (!zxid_saml_ok(cf, cgi, r->LogoutResponse->Status, "SLO resp"))
68 return zx_dup_str(cf->ctx, "* ERR");
69 cgi->msg = "Logout Response OK. Logged out.";
70 zxid_del_ses(cf, ses);
71 return zx_dup_str(cf->ctx, "K"); /* Prevent mgmt screen from displaying, show login screen. */
72 }
73
74 if (r->ManageNameIDRequest) {
75 sp_meta = zxid_get_ent_ss(cf, ZX_GET_CONTENT(r->ManageNameIDRequest->Issuer));
76 loc = zxid_sp_loc_raw(cf, cgi, sp_meta, ZXID_MNI_SVC, SAML2_REDIR, 0);
77 if (!loc)
78 return 0; /* *** consider sending error page */
79 ss = zxid_mni_do_ss(cf, cgi, ses, r->ManageNameIDRequest, loc);
80 ss2 = zxid_saml2_resp_redir(cf, loc, ss, cgi->rs);
81 zx_str_free(cf->ctx, loc);
82 zx_str_free(cf->ctx, ss);
83 return ss2;
84 }
85
86 if (r->ManageNameIDResponse) {
87 if (!zxid_saml_ok(cf, cgi, r->ManageNameIDResponse->Status, "MNI resp")) {
88 ERR("MNI Response indicates failure. %d", 0);
89 return zx_dup_str(cf->ctx, "* ERR");
90 }
91 cgi->msg = "Manage NameID Response OK.";
92 return zx_dup_str(cf->ctx, "M"); /* Defederation doesn't have to mean SLO, show mgmt screen. */
93 }
94
95 if (cf->log_level > 0)
96 zxlog(cf, 0, 0, 0, 0, 0, 0, ZX_GET_CONTENT(ses->nameid), "N", "C", "IDPDISP", 0, "sid(%s) unknown req or resp (loc)", ses->sid);
97 ERR("Unknown request or response %p", r);
98 return zx_dup_str(cf->ctx, "* ERR");
99 }
100
101 #if 0
102 /*(-) SOAP dispatch can also handle requests and responses received via artifact
103 * resolution. However only some combinations make sense.
104 * Return 0 for failure, otherwise some success code such as ZXID_SSO_OK
105 * *** NOT CALLED FROM ANYWHERE. See zxid_sp_soap_dispatch() for real action */
106
107 /* Called by: */
108 int zxid_idp_soap_dispatch(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, struct zx_root_s* r)
109 {
110 X509* sign_cert;
111 RSA* sign_pkey;
112 struct zxsig_ref refs;
113 struct zx_e_Body_s* body;
114 struct zx_sp_LogoutRequest_s* req;
115 ses->sigres = ZXSIG_NO_SIG;
116
117 if (!r) goto bad;
118 if (!r->Envelope) goto bad;
119
120 if (cf->log_level > 1)
121 zxlog(cf, 0, 0, 0, 0, 0, 0, ZX_GET_CONTENT(ses->nameid), "N", "W", "IDPDISP", 0, "sid(%s) soap", ses->sid);
122
123 if (r->Envelope->Body->ArtifactResolve) {
124 D("ArtifactResolve not implemented yet %d",0);
125 //if (!zxid_saml_ok(cf, cgi, r->Envelope->Body->ArtifactResponse->Status, "ArtResp"))
126 // return 0;
127 //return zxid_sp_dig_sso_a7n(cf, cgi, ses, r->Envelope->Body->ArtifactResponse->Response);
128 }
129
130 if (req = r->Envelope->Body->LogoutRequest) {
131 if (!zxid_idp_slo_do(cf, cgi, ses, req))
132 return 0;
133
134 body = zx_NEW_e_Body(cf->ctx,0);
135 body->LogoutResponse = zxid_mk_logout_resp(cf, zxid_OK(cf), req->ID);
136 if (cf->sso_soap_resp_sign) {
137 ZERO(&refs, sizeof(refs));
138 refs.id = body->LogoutResponse->ID;
139 refs.canon = zx_EASY_ENC_SO_sp_LogoutResponse(cf->ctx, body->LogoutResponse);
140 if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert idp slo")) {
141 body->LogoutResponse->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey, cf->xmldsig_sig_meth, cf->xmldsig_digest_algo);
142 zx_add_kid_after_sa_Issuer(&body->LogoutResponse->gg, &body->LogoutResponse->Signature->gg);
143 }
144 zx_str_free(cf->ctx, refs.canon);
145 }
146 return zxid_soap_cgi_resp_body(cf, ses, body);
147 }
148
149 if (r->Envelope->Body->ManageNameIDRequest) {
150 struct zx_sp_ManageNameIDResponse_s* res = zxid_mni_do(cf, cgi, ses, r->Envelope->Body->ManageNameIDRequest);
151 body = zx_NEW_e_Body(cf->ctx,0);
152 body->ManageNameIDResponse = res;
153 if (cf->sso_soap_resp_sign) {
154 ZERO(&refs, sizeof(refs));
155 refs.id = res->ID;
156 refs.canon = zx_EASY_ENC_SO_sp_ManageNameIDResponse(cf->ctx, res);
157 if (zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "use sign cert idp mni")) {
158 res->Signature = zxsig_sign(cf->ctx, 1, &refs, sign_cert, sign_pkey, cf->xmldsig_sig_meth, cf->xmldsig_digest_algo);
159 zx_add_kid_after_sa_Issuer(&res->gg, &res->Signature->gg);
160 }
161 zx_str_free(cf->ctx, refs.canon);
162 }
163 return zxid_soap_cgi_resp_body(cf, body, ZX_GET_CONTENT(r->Envelope->Body->ManageNameIDRequest->Issuer));
164 }
165
166 bad:
167 ERR("Unknown soap request %p", r);
168 if (cf->log_level > 0)
169 zxlog(cf, 0, 0, 0, 0, 0, 0, ZX_GET_CONTENT(ses->nameid), "N", "C", "IDPDISP", 0, "sid(%s) unknown soap req", ses->sid);
170 return 0;
171 }
172
173 /*() Return 0 for failure, otherwise some success code such as ZXID_SSO_OK */
174
175 /* Called by: */
176 int zxid_idp_soap_parse(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses, int len, char* buf)
177 {
178 struct zx_root_s* r;
179 r = zx_dec_zx_root(cf->ctx, len, buf, "idp soap parse");
180 if (!r || !r->Envelope || !r->Envelope->Body) {
181 ERR("Failed to parse SOAP request buf(%.*s)", len, buf);
182 zxlog(cf, 0, 0, 0, 0, 0, 0, ZX_GET_CONTENT(ses->nameid), "N", "C", "BADXML", 0, "sid(%s) bad soap req", ses->sid);
183 return 0;
184 }
185 return zxid_sp_soap_dispatch(cf, cgi, ses, r);
186 }
187 #endif
188
189 /* EOF -- zxididpx.c */
190