1 /* $Id$
2 *
3 * Lasso - A free implementation of the Liberty Alliance specifications.
4 *
5 * Copyright (C) 2004-2007 Entr'ouvert
6 * http://lasso.entrouvert.org
7 *
8 * Authors: See AUTHORS file in top-level directory.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "../xml/private.h"
25 #include <libxml/xpath.h>
26 #include <libxml/xpathInternals.h>
27
28 #include "providerprivate.h"
29 #include "loginprivate.h"
30 #include "profileprivate.h"
31 #include "federationprivate.h"
32 #include "saml2_helper.h"
33
34 #include "../id-ff/providerprivate.h"
35 #include "../id-ff/serverprivate.h"
36 #include "../id-ff/login.h"
37 #include "../id-ff/identityprivate.h"
38 #include "../id-ff/sessionprivate.h"
39 #include "../id-ff/loginprivate.h"
40
41 #include "../xml/ecp/ecp_relaystate.h"
42 #include "../xml/paos_response.h"
43
44 #include "../xml/xml_enc.h"
45
46 #include "../xml/saml-2.0/samlp2_authn_request.h"
47 #include "../xml/saml-2.0/samlp2_response.h"
48 #include "../xml/saml-2.0/saml2_assertion.h"
49 #include "../xml/saml-2.0/saml2_audience_restriction.h"
50 #include "../xml/saml-2.0/saml2_authn_statement.h"
51 #include "../xml/saml-2.0/saml2_encrypted_element.h"
52 #include "../xml/saml-2.0/saml2_attribute.h"
53 #include "../xml/saml-2.0/saml2_attribute_statement.h"
54 #include "../xml/saml-2.0/saml2_attribute_value.h"
55 #include "../xml/saml-2.0/saml2_name_id.h"
56 #include "../xml/saml-2.0/saml2_xsd.h"
57 #include "../xml/saml-2.0/samlp2_artifact_response.h"
58
59 #include "../utils.h"
60
61 static int lasso_saml20_login_process_federation(LassoLogin *login, gboolean is_consent_obtained);
62 static gboolean lasso_saml20_login_must_ask_for_consent_private(LassoLogin *login);
63 static gint lasso_saml20_login_process_response_status_and_assertion(LassoLogin *login);
64 static char* lasso_saml20_login_get_assertion_consumer_service_url(LassoLogin *login,
65 LassoProvider *remote_provider);
66 static gboolean _lasso_login_must_verify_signature(LassoProfile *profile) G_GNUC_UNUSED;
67 static gboolean _lasso_login_must_verify_authn_request_signature(LassoProfile *profile);
68
69 /* No need to check type of arguments, it has been done in lasso_login_* methods */
70
71 gint
lasso_saml20_login_init_authn_request(LassoLogin * login,LassoHttpMethod http_method)72 lasso_saml20_login_init_authn_request(LassoLogin *login, LassoHttpMethod http_method)
73 {
74 LassoProfile *profile = NULL;
75 LassoSamlp2RequestAbstract *request = NULL;
76 gchar *default_name_id_format = NULL;
77 int rc = 0;
78
79 profile = &login->parent;
80
81 /* new */
82 request = (LassoSamlp2RequestAbstract*)lasso_samlp2_authn_request_new();
83 lasso_check_good_rc(lasso_saml20_profile_init_request(profile, profile->remote_providerID, FALSE,
84 request, http_method, LASSO_MD_PROTOCOL_TYPE_SINGLE_SIGN_ON));
85
86 /* FIXME: keep old behaviour */
87 login->http_method = login->parent.http_request_method;
88
89 /* save request ID, for later check */
90 lasso_assign_string(login->private_data->request_id, request->ID);
91 /* set name id policy */
92 lasso_assign_new_gobject(LASSO_SAMLP2_AUTHN_REQUEST(request)->NameIDPolicy,
93 lasso_samlp2_name_id_policy_new());
94 /* set name id policy format */
95 /* no need to check server, done in init_request */
96 default_name_id_format = lasso_provider_get_metadata_one_for_role(&profile->server->parent,
97 LASSO_PROVIDER_ROLE_SP, "NameIDFormat");
98 if (default_name_id_format) {
99 /* steal the string */
100 lasso_assign_new_string(LASSO_SAMLP2_AUTHN_REQUEST(request)->NameIDPolicy->Format,
101 default_name_id_format);
102 } else {
103 lasso_assign_string(LASSO_SAMLP2_AUTHN_REQUEST(request)->NameIDPolicy->Format,
104 LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT);
105 }
106
107 cleanup:
108 lasso_release_gobject(request);
109 return rc;
110 }
111
want_authn_request_signed(LassoProvider * provider)112 static gboolean want_authn_request_signed(LassoProvider *provider) {
113 char *s;
114 gboolean rc = FALSE;
115
116 s = lasso_provider_get_metadata_one_for_role(provider, LASSO_PROVIDER_ROLE_IDP,
117 LASSO_SAML2_METADATA_ATTRIBUTE_WANT_AUTHN_REQUEST_SIGNED);
118 if (lasso_strisequal(s, "true")) {
119 rc = TRUE;
120 }
121 lasso_release_string(s);
122 return rc;
123 }
124
authn_request_signed(LassoProvider * provider)125 static gboolean authn_request_signed(LassoProvider *provider) {
126 char *s;
127 gboolean rc = FALSE;
128
129 s = lasso_provider_get_metadata_one_for_role(provider, LASSO_PROVIDER_ROLE_SP,
130 LASSO_SAML2_METADATA_ATTRIBUTE_AUTHN_REQUEST_SIGNED);
131 if (lasso_strisequal(s,"true")) {
132 rc = TRUE;
133 }
134 lasso_release_string(s);
135 return rc;
136 }
137
138 static gboolean
_lasso_login_must_sign_non_authn_request(LassoLogin * profile)139 _lasso_login_must_sign_non_authn_request(LassoLogin *profile)
140 {
141 switch (lasso_profile_get_signature_hint(&profile->parent)) {
142 case LASSO_PROFILE_SIGNATURE_HINT_MAYBE:
143 return lasso_flag_add_signature;
144 case LASSO_PROFILE_SIGNATURE_HINT_FORCE:
145 return TRUE;
146 case LASSO_PROFILE_SIGNATURE_HINT_FORBID:
147 return FALSE;
148 default:
149 return TRUE;
150 }
151 }
152
153 static gboolean
_lasso_login_must_sign(LassoProfile * profile)154 _lasso_login_must_sign(LassoProfile *profile)
155 {
156 gboolean ret;
157 LassoProvider *remote_provider;
158
159 remote_provider = lasso_server_get_provider(profile->server,
160 profile->remote_providerID);
161
162 switch (lasso_profile_get_signature_hint(profile)) {
163 case LASSO_PROFILE_SIGNATURE_HINT_MAYBE:
164 /* If our metadatas say that we sign, then we sign,
165 * If the IdP says that he wants our signature, then we sign
166 * Otherwise we do not.
167 */
168 ret = authn_request_signed(&profile->server->parent)
169 || want_authn_request_signed(remote_provider);
170 return ret;
171 case LASSO_PROFILE_SIGNATURE_HINT_FORCE:
172 return TRUE;
173 case LASSO_PROFILE_SIGNATURE_HINT_FORBID:
174 return FALSE;
175 }
176 g_assert(0);
177 return TRUE;
178 }
179
180 static gboolean
_lasso_login_must_verify_authn_request_signature(LassoProfile * profile)181 _lasso_login_must_verify_authn_request_signature(LassoProfile *profile) {
182 LassoProvider *remote_provider;
183
184 remote_provider = lasso_server_get_provider(profile->server,
185 profile->remote_providerID);
186
187 switch (lasso_profile_get_signature_verify_hint(profile)) {
188 /* If our metadatas say that we want signature, then we verify,
189 * If the SP says that he signs, then we verify
190 * Otherwise we do not.
191 */
192 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
193 return want_authn_request_signed(&profile->server->parent) ||
194 authn_request_signed(remote_provider);
195 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
196 return FALSE;
197 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
198 return TRUE;
199 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_LAST:
200 break;
201 }
202 g_assert(0);
203 return TRUE;
204 }
205
206 static gboolean
_lasso_login_must_verify_signature(LassoProfile * profile)207 _lasso_login_must_verify_signature(LassoProfile *profile) {
208 switch (lasso_profile_get_signature_verify_hint(profile)) {
209 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
210 return lasso_flag_verify_signature;
211 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
212 return FALSE;
213 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
214 return TRUE;
215 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_LAST:
216 break;
217 }
218 g_assert(0);
219 return TRUE;
220 }
221
222 gint
lasso_saml20_login_build_authn_request_msg(LassoLogin * login)223 lasso_saml20_login_build_authn_request_msg(LassoLogin *login)
224 {
225 char *assertionConsumerServiceURL = NULL;
226 gboolean must_sign = TRUE;
227 LassoProfile *profile;
228 LassoSamlp2AuthnRequest *authn_request;
229 int rc = 0;
230
231 profile = &login->parent;
232
233 lasso_extract_node_or_fail(authn_request, profile->request, SAMLP2_AUTHN_REQUEST,
234 LASSO_PROFILE_ERROR_INVALID_REQUEST);
235
236 /* default is to sign ! */
237 must_sign = _lasso_login_must_sign(profile);
238
239 if (! must_sign) {
240 lasso_node_remove_signature(profile->request);
241 }
242
243 /* support old way of doing PAOS */
244 if (login->http_method == LASSO_HTTP_METHOD_SOAP
245 && lasso_strisequal(authn_request->ProtocolBinding,LASSO_SAML2_METADATA_BINDING_PAOS)) {
246 login->http_method = LASSO_HTTP_METHOD_PAOS;
247 }
248
249 if (login->http_method == LASSO_HTTP_METHOD_PAOS) {
250 /*
251 * PAOS is special, the url passed to build_request is the
252 * AssertionConsumerServiceURL of this SP, not the
253 * destination IdP URL. This is done to fill paos:responseConsumerURL
254 * appropriately down the line in build_request_msg.
255 * See https://dev.entrouvert.org/issues/34409 for more information.
256 */
257 if (authn_request->AssertionConsumerServiceURL) {
258 assertionConsumerServiceURL = authn_request->AssertionConsumerServiceURL;
259 if (!lasso_saml20_provider_check_assertion_consumer_service_url(
260 LASSO_PROVIDER(profile->server), assertionConsumerServiceURL, LASSO_SAML2_METADATA_BINDING_PAOS)) {
261 rc = LASSO_PROFILE_ERROR_INVALID_REQUEST;
262 goto cleanup;
263 }
264 } else {
265 assertionConsumerServiceURL = lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(
266 LASSO_PROVIDER(profile->server), LASSO_SAML2_METADATA_BINDING_PAOS);
267 lasso_assign_new_string(authn_request->AssertionConsumerServiceURL, assertionConsumerServiceURL);
268 }
269 }
270
271 lasso_check_good_rc(lasso_saml20_profile_build_request_msg(profile, "SingleSignOnService",
272 login->http_method, assertionConsumerServiceURL));
273
274 cleanup:
275 return rc;
276 }
277
278 int
lasso_saml20_login_process_authn_request_msg(LassoLogin * login,const char * authn_request_msg)279 lasso_saml20_login_process_authn_request_msg(LassoLogin *login, const char *authn_request_msg)
280 {
281 LassoNode *request = NULL;
282 LassoProfile *profile = LASSO_PROFILE(login);
283 LassoSamlp2StatusResponse *response = NULL;
284 LassoSamlp2AuthnRequest *authn_request = NULL;
285 LassoProvider *remote_provider = NULL;
286 LassoServer *server = NULL;
287 const gchar *protocol_binding = NULL;
288 const char *status1 = LASSO_SAML2_STATUS_CODE_RESPONDER;
289 const char *status2 = NULL;
290 int rc = 0;
291
292 if (authn_request_msg == NULL) {
293 if (profile->request == NULL) {
294 return critical_error(LASSO_PROFILE_ERROR_MISSING_REQUEST);
295 }
296
297 /* AuthnRequest already set by .._init_idp_initiated_authn_request, or from a
298 * previously failed call to process_authn_request that we retry. */
299 request = lasso_ref(profile->request);
300 } else {
301 request = lasso_samlp2_authn_request_new();
302 lasso_check_good_rc(lasso_saml20_profile_process_any_request(profile, request, authn_request_msg));
303 }
304 if (! LASSO_IS_SAMLP2_AUTHN_REQUEST(request)) {
305 return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
306 }
307 authn_request = LASSO_SAMLP2_AUTHN_REQUEST(request);
308 /* intialize the response */
309 response = (LassoSamlp2StatusResponse*) lasso_samlp2_response_new();
310 lasso_assign_string(response->InResponseTo,
311 LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->ID);
312 /* reset response binding */
313 login->protocolProfile = 0;
314
315 /* find the remote provider */
316 if (! authn_request->parent.Issuer || ! authn_request->parent.Issuer->content) {
317 rc = LASSO_PROFILE_ERROR_INVALID_REQUEST;
318 goto cleanup;
319 }
320 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
321 if (remote_provider == NULL) {
322 rc = LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER;
323 goto cleanup;
324 }
325 lasso_extract_node_or_fail(server, lasso_profile_get_server(&login->parent), SERVER,
326 LASSO_PROFILE_ERROR_MISSING_SERVER);
327 remote_provider->role = LASSO_PROVIDER_ROLE_SP;
328 server->parent.role = LASSO_PROVIDER_ROLE_IDP;
329
330 if (((authn_request->ProtocolBinding != NULL) ||
331 (authn_request->AssertionConsumerServiceURL != NULL)) &&
332 (authn_request->AssertionConsumerServiceIndex != -1))
333 {
334 rc = LASSO_PROFILE_ERROR_INVALID_REQUEST;
335 goto cleanup;
336 }
337
338 /* try to find a protocol profile for sending the response */
339 protocol_binding = authn_request->ProtocolBinding;
340 if (protocol_binding || authn_request->AssertionConsumerServiceURL)
341 {
342 if (authn_request->AssertionConsumerServiceURL) {
343 if (protocol_binding) {
344 if (! lasso_saml20_provider_check_assertion_consumer_service_url(
345 remote_provider,
346 authn_request->AssertionConsumerServiceURL,
347 authn_request->ProtocolBinding)) {
348 // Sent ACS URL is unknown
349 rc = LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE;
350 goto cleanup;
351 }
352 } else {
353 // Only ACS URL sent, choose the first associated binding
354 protocol_binding = lasso_saml20_provider_get_assertion_consumer_service_binding_by_url(
355 remote_provider, authn_request->AssertionConsumerServiceURL);
356 if (! protocol_binding) {
357 rc = LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE;
358 goto cleanup;
359 }
360 lasso_assign_string(authn_request->ProtocolBinding,
361 protocol_binding);
362 }
363 }
364
365 if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_ARTIFACT)) {
366 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
367 } else if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_POST)) {
368 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST;
369 } else if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_SOAP)) {
370 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
371 } else if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_REDIRECT)) {
372 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT;
373 goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE);
374 } else if (lasso_strisequal(protocol_binding,LASSO_SAML2_METADATA_BINDING_PAOS)) {
375 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
376 } else {
377 rc = LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE;
378 goto cleanup;
379 }
380 } else {
381 /* protocol binding not set; so it will look into
382 * AssertionConsumerServiceIndex
383 * Also, if AssertionConsumerServiceIndex is not set in request,
384 * its value will be -1, which is just the right value to get
385 * default assertion consumer... (convenient)
386 */
387 gchar *binding;
388 int service_index = authn_request->AssertionConsumerServiceIndex;
389
390 binding = lasso_saml20_provider_get_assertion_consumer_service_binding(
391 remote_provider, service_index);
392 if (binding == NULL) {
393 if (service_index == -1) {
394 goto_cleanup_with_rc(LASSO_LOGIN_ERROR_NO_DEFAULT_ENDPOINT);
395 } else {
396 goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE);
397 }
398 } else if (lasso_strisequal(binding,"HTTP-Artifact")) {
399 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
400 } else if (lasso_strisequal(binding,"HTTP-POST")) {
401 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST;
402 } else if (lasso_strisequal(binding,"HTTP-Redirect")) {
403 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT;
404 } else if (lasso_strisequal(binding,"SOAP")) {
405 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
406 } else if (lasso_strisequal(binding,"PAOS")) {
407 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
408 }
409 lasso_release_string(binding);
410 }
411
412
413 if (_lasso_login_must_verify_authn_request_signature(profile) && profile->signature_status)
414 {
415 status1 = LASSO_SAML2_STATUS_CODE_REQUESTER;
416 status2 = LASSO_LIB_STATUS_CODE_INVALID_SIGNATURE;
417 rc = profile->signature_status;
418 } else {
419 status1 = LASSO_SAML2_STATUS_CODE_SUCCESS;
420 status2 = NULL;
421 }
422 lasso_saml20_profile_init_response(profile, response,
423 status1, status2);
424 cleanup:
425 lasso_release_gobject(request);
426 lasso_release_gobject(response);
427 return rc;
428 }
429
430
431 gboolean
lasso_saml20_login_must_authenticate(LassoLogin * login)432 lasso_saml20_login_must_authenticate(LassoLogin *login)
433 {
434 LassoSamlp2AuthnRequest *request;
435 gboolean matched = TRUE;
436 GList *assertions = NULL;
437 LassoProfile *profile = &login->parent;
438
439 if (! LASSO_IS_SAMLP2_AUTHN_REQUEST(profile->request))
440 return FALSE;
441
442 request = LASSO_SAMLP2_AUTHN_REQUEST(profile->request);
443 if (request->ForceAuthn == TRUE && request->IsPassive == FALSE)
444 return TRUE;
445
446 if (request->RequestedAuthnContext) {
447 char *comparison = request->RequestedAuthnContext->Comparison;
448 GList *class_refs = request->RequestedAuthnContext->AuthnContextClassRef;
449 char *class_ref;
450 GList *t1, *t2;
451 int compa = -1;
452
453 if (comparison == NULL || lasso_strisequal(comparison,"exact")) {
454 compa = 0;
455 } else if (lasso_strisequal(comparison,"minimum")) {
456 message(G_LOG_LEVEL_CRITICAL, "'minimum' comparison is not implemented");
457 compa = 1;
458 } else if (lasso_strisequal(comparison,"better")) {
459 message(G_LOG_LEVEL_CRITICAL, "'better' comparison is not implemented");
460 compa = 2;
461 } else if (lasso_strisequal(comparison,"maximum")) {
462 message(G_LOG_LEVEL_CRITICAL, "'maximum' comparison is not implemented");
463 compa = 3;
464 }
465
466 if (class_refs) {
467 matched = FALSE;
468 }
469
470 assertions = lasso_session_get_assertions(profile->session, NULL);
471 for (t1 = class_refs; t1 && !matched; t1 = g_list_next(t1)) {
472 class_ref = t1->data;
473 for (t2 = assertions; t2 && !matched; t2 = g_list_next(t2)) {
474 LassoSaml2Assertion *assertion;
475 LassoSaml2AuthnStatement *as = NULL;
476 char *method;
477 GList *t3;
478
479 if (LASSO_IS_SAML2_ASSERTION(t2->data) == FALSE) {
480 continue;
481 }
482
483 assertion = t2->data;
484
485 for (t3 = assertion->AuthnStatement; t3; t3 = g_list_next(t3)) {
486 if (LASSO_IS_SAML2_AUTHN_STATEMENT(t3->data)) {
487 as = t3->data;
488 break;
489 }
490 }
491
492 if (as == NULL)
493 continue;
494
495 if (as->AuthnContext == NULL)
496 continue;
497
498 method = as->AuthnContext->AuthnContextClassRef;
499
500 switch (compa) {
501 case 1: /* minimum */
502 /* XXX: implement 'minimum' comparison */
503 case 2: /* better */
504 /* XXX: implement 'better' comparison */
505 case 3: /* maximum */
506 /* XXX: implement 'maximum' comparison */
507 case 0: /* exact */
508 if (lasso_strisequal(method,class_ref)) {
509 matched = TRUE;
510 }
511 break;
512 default: /* never reached */
513 break;
514 }
515 if (matched == TRUE) {
516 break;
517 }
518 }
519 }
520 } else {
521 /* if nothing specific was asked; don't look for any
522 * particular assertions, one is enough
523 */
524 matched = (profile->session != NULL && \
525 lasso_session_count_assertions(profile->session) > 0);
526 }
527 if (assertions) {
528 lasso_release_list(assertions);
529 }
530 if (matched == FALSE && request->IsPassive == FALSE)
531 return TRUE;
532 if (profile->identity == NULL && request->IsPassive) {
533 lasso_saml20_profile_set_response_status_responder(LASSO_PROFILE(login),
534 LASSO_SAML2_STATUS_CODE_NO_PASSIVE);
535 return FALSE;
536 }
537 return FALSE;
538 }
539
540 static gboolean
lasso_saml20_login_must_ask_for_consent_private(LassoLogin * login)541 lasso_saml20_login_must_ask_for_consent_private(LassoLogin *login)
542 {
543 LassoProfile *profile = LASSO_PROFILE(login);
544 LassoSamlp2NameIDPolicy *name_id_policy;
545 char *consent;
546 LassoFederation *federation;
547 const char *name_id_sp_name_qualifier = NULL;
548 LassoProvider *remote_provider;
549 gboolean rc = TRUE;
550
551 name_id_policy = LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->NameIDPolicy;
552
553 if (name_id_policy) {
554 char *format = name_id_policy->Format;
555 if (lasso_strisequal(format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT)) {
556 goto_cleanup_with_rc (FALSE)
557 }
558 if (name_id_policy->AllowCreate == FALSE) {
559 goto_cleanup_with_rc (FALSE)
560 }
561 }
562
563 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
564 name_id_sp_name_qualifier = lasso_provider_get_sp_name_qualifier(remote_provider);
565
566 /* if something goes wrong better to ask thant to let go */
567 if (name_id_sp_name_qualifier == NULL)
568 goto_cleanup_with_rc (TRUE)
569
570 if (profile->identity && profile->identity->federations) {
571 federation = g_hash_table_lookup(profile->identity->federations,
572 name_id_sp_name_qualifier);
573 if (federation) {
574 goto_cleanup_with_rc (FALSE)
575 }
576 }
577
578 consent = LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->Consent;
579 if (consent == NULL)
580 goto_cleanup_with_rc (FALSE)
581
582 if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_OBTAINED))
583 goto_cleanup_with_rc (FALSE)
584
585 if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_PRIOR))
586 goto_cleanup_with_rc (FALSE)
587
588 if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_IMPLICIT))
589 goto_cleanup_with_rc (FALSE)
590
591 if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_EXPLICIT))
592 goto_cleanup_with_rc (FALSE)
593
594 if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_UNAVAILABLE))
595 goto_cleanup_with_rc (TRUE)
596
597 if (lasso_strisequal(consent,LASSO_SAML2_CONSENT_INAPPLICABLE))
598 goto_cleanup_with_rc (TRUE)
599
600 cleanup:
601 return rc;
602 }
603
604 gboolean
lasso_saml20_login_must_ask_for_consent(LassoLogin * login)605 lasso_saml20_login_must_ask_for_consent(LassoLogin *login)
606 {
607 LassoProfile *profile = LASSO_PROFILE(login);
608
609 if (LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->IsPassive)
610 return FALSE;
611
612 return lasso_saml20_login_must_ask_for_consent_private(login);
613 }
614
615 int
lasso_saml20_login_validate_request_msg(LassoLogin * login,gboolean authentication_result,gboolean is_consent_obtained)616 lasso_saml20_login_validate_request_msg(LassoLogin *login, gboolean authentication_result,
617 gboolean is_consent_obtained)
618 {
619 LassoProfile *profile;
620 int rc = 0;
621
622 profile = LASSO_PROFILE(login);
623
624 if (authentication_result == FALSE) {
625 lasso_saml20_profile_set_response_status_responder(profile,
626 LASSO_SAML2_STATUS_CODE_REQUEST_DENIED);
627 goto_cleanup_with_rc(LASSO_LOGIN_ERROR_REQUEST_DENIED);
628 }
629
630 if (_lasso_login_must_verify_authn_request_signature(profile) && profile->signature_status)
631 {
632 lasso_saml20_profile_set_response_status_requester(profile,
633 LASSO_LIB_STATUS_CODE_INVALID_SIGNATURE);
634
635 if (profile->signature_status == LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) {
636 goto_cleanup_with_rc(LASSO_LOGIN_ERROR_UNSIGNED_AUTHN_REQUEST);
637 }
638 goto_cleanup_with_rc(LASSO_LOGIN_ERROR_INVALID_SIGNATURE);
639 }
640
641 rc = lasso_saml20_login_process_federation(login, is_consent_obtained);
642 if (rc == LASSO_LOGIN_ERROR_FEDERATION_NOT_FOUND) {
643 lasso_saml20_profile_set_response_status_requester(profile,
644 LASSO_LIB_STATUS_CODE_FEDERATION_DOES_NOT_EXIST);
645 goto cleanup;
646 }
647 /* UNKNOWN_PROVIDER, CONSENT_NOT_OBTAINED */
648 if (rc) {
649 lasso_saml20_profile_set_response_status_responder(profile,
650 LASSO_SAML2_STATUS_CODE_REQUEST_DENIED);
651 goto cleanup;
652 }
653
654 lasso_saml20_profile_set_response_status_success(profile, NULL);
655 cleanup:
656
657 return rc;
658 }
659
660 static int
lasso_saml20_login_process_federation(LassoLogin * login,gboolean is_consent_obtained)661 lasso_saml20_login_process_federation(LassoLogin *login, gboolean is_consent_obtained)
662 {
663 LassoProfile *profile = LASSO_PROFILE(login);
664 LassoSamlp2NameIDPolicy *name_id_policy;
665 char *name_id_policy_format = NULL;
666 LassoFederation *federation;
667 const char *name_id_sp_name_qualifier = NULL;
668 LassoProvider *remote_provider;
669 int rc = 0;
670
671 /* verify if identity already exists else create it */
672 if (profile->identity == NULL) {
673 profile->identity = lasso_identity_new();
674 }
675
676 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
677 if (! LASSO_IS_PROVIDER(remote_provider)) {
678 goto_cleanup_with_rc (LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER);
679 }
680
681 if (! LASSO_IS_SAMLP2_AUTHN_REQUEST(profile->request)) {
682 goto_cleanup_with_rc(critical_error(LASSO_PROFILE_ERROR_INVALID_REQUEST));
683 }
684
685 name_id_policy = ((LassoSamlp2AuthnRequest*)profile->request)->NameIDPolicy;
686
687 if (name_id_policy) {
688 name_id_policy_format = name_id_policy->Format;
689 }
690
691 if (! name_id_policy_format) {
692 name_id_policy_format = lasso_provider_get_default_name_id_format(remote_provider);
693 }
694
695 lasso_assign_string(login->nameIDPolicy, name_id_policy_format);
696
697 if (lasso_saml20_login_must_ask_for_consent_private(login) && !is_consent_obtained) {
698 goto_cleanup_with_rc (LASSO_LOGIN_ERROR_CONSENT_NOT_OBTAINED)
699 }
700 if (lasso_strisnotequal(name_id_policy_format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT)) {
701 /* non persistent case, TRANSIENT is handled by lasso_login_build_assertion() and
702 * other format are the sole responsibility of the caller */
703 goto_cleanup_with_rc (0)
704 }
705
706 /* PERSISTENT case, try to federation or find an existing federation */
707 name_id_sp_name_qualifier = lasso_provider_get_sp_name_qualifier(remote_provider);
708 if (name_id_sp_name_qualifier == NULL) {
709 goto_cleanup_with_rc (LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER);
710 }
711
712 /* search a federation in the identity */
713 federation = lasso_identity_get_federation(profile->identity, name_id_sp_name_qualifier);
714 if (! federation && ( ! name_id_policy || name_id_policy->AllowCreate == FALSE)) {
715 goto_cleanup_with_rc (LASSO_LOGIN_ERROR_FEDERATION_NOT_FOUND)
716 }
717 if (! federation && name_id_policy && name_id_policy->AllowCreate) {
718 federation = lasso_federation_new(name_id_sp_name_qualifier);
719 lasso_saml20_federation_build_local_name_identifier(federation,
720 LASSO_PROVIDER(profile->server)->ProviderID,
721 LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT,
722 NULL);
723 lasso_assign_string(LASSO_SAML2_NAME_ID(federation->local_nameIdentifier)->SPNameQualifier,
724 name_id_sp_name_qualifier);
725 lasso_identity_add_federation(profile->identity, federation);
726 }
727
728 lasso_assign_gobject(profile->nameIdentifier, federation->local_nameIdentifier);
729
730 cleanup:
731 return rc;
732 }
733
734 static LassoFederation*
_lasso_login_saml20_get_federation(LassoLogin * login)735 _lasso_login_saml20_get_federation(LassoLogin *login) {
736 LassoFederation *federation = NULL;
737 const char *name_id_sp_name_qualifier = NULL;
738
739
740 name_id_sp_name_qualifier = lasso_provider_get_sp_name_qualifier(
741 lasso_server_get_provider(login->parent.server, login->parent.remote_providerID));
742 federation = lasso_identity_get_federation(login->parent.identity, name_id_sp_name_qualifier);
743 return federation;
744 }
745
746 int
lasso_saml20_login_build_assertion(LassoLogin * login,const char * authenticationMethod,const char * authenticationInstant,const char * notBefore,const char * notOnOrAfter)747 lasso_saml20_login_build_assertion(LassoLogin *login,
748 const char *authenticationMethod,
749 const char *authenticationInstant,
750 const char *notBefore,
751 const char *notOnOrAfter)
752 {
753 LassoProfile *profile = &login->parent;
754 LassoSaml2Assertion *assertion = NULL;
755 LassoSaml2AudienceRestriction *audience_restriction = NULL;
756 LassoSamlp2NameIDPolicy *name_id_policy = NULL;
757 LassoSaml2NameID *name_id = NULL;
758 LassoSaml2AuthnStatement *authentication_statement;
759 LassoProvider *provider = NULL;
760 LassoSamlp2Response *response = NULL;
761 LassoSamlp2RequestAbstract *request_abstract = NULL;
762 LassoSamlp2AuthnRequest *authn_request = NULL;
763 gboolean do_encrypt_nameid = FALSE;
764 gboolean do_encrypt_assertion = FALSE;
765 int rc = 0;
766
767 provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
768
769 if (provider) {
770 do_encrypt_nameid = lasso_provider_get_encryption_mode(provider) &
771 LASSO_ENCRYPTION_MODE_NAMEID;
772 do_encrypt_assertion = lasso_provider_get_encryption_mode(provider) &
773 LASSO_ENCRYPTION_MODE_ASSERTION;
774 }
775
776 if (LASSO_IS_SAMLP2_AUTHN_REQUEST(profile->request)) {
777 authn_request = (LassoSamlp2AuthnRequest*)profile->request;
778 request_abstract = &authn_request->parent;
779 }
780 goto_cleanup_if_fail_with_rc(LASSO_IS_SAMLP2_RESPONSE(profile->response),
781 LASSO_PROFILE_ERROR_MISSING_RESPONSE);
782
783 assertion = LASSO_SAML2_ASSERTION(lasso_saml2_assertion_new());
784 assertion->ID = lasso_build_unique_id(32);
785 lasso_assign_string(assertion->Version, "2.0");
786 assertion->IssueInstant = lasso_get_current_time();
787 assertion->Issuer = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
788 LASSO_PROVIDER(profile->server)->ProviderID));
789 assertion->Conditions = LASSO_SAML2_CONDITIONS(lasso_saml2_conditions_new());
790 lasso_assign_string(assertion->Conditions->NotBefore, notBefore);
791 lasso_assign_string(assertion->Conditions->NotOnOrAfter, notOnOrAfter);
792
793 audience_restriction = LASSO_SAML2_AUDIENCE_RESTRICTION(
794 lasso_saml2_audience_restriction_new());
795 lasso_assign_string(audience_restriction->Audience, profile->remote_providerID);
796 lasso_list_add_new_gobject(assertion->Conditions->AudienceRestriction, audience_restriction);
797
798 assertion->Subject = LASSO_SAML2_SUBJECT(lasso_saml2_subject_new());
799 assertion->Subject->SubjectConfirmation = LASSO_SAML2_SUBJECT_CONFIRMATION(
800 lasso_saml2_subject_confirmation_new());
801 assertion->Subject->SubjectConfirmation->Method = g_strdup(
802 LASSO_SAML2_CONFIRMATION_METHOD_BEARER);
803 assertion->Subject->SubjectConfirmation->SubjectConfirmationData =
804 LASSO_SAML2_SUBJECT_CONFIRMATION_DATA(
805 lasso_saml2_subject_confirmation_data_new());
806 lasso_assign_string(
807 assertion->Subject->SubjectConfirmation->SubjectConfirmationData->NotOnOrAfter,
808 notOnOrAfter);
809
810 /* If request is present, refer to it in the response */
811 if (authn_request) {
812 if (request_abstract->ID) {
813 lasso_assign_string(assertion->Subject->SubjectConfirmation->SubjectConfirmationData->InResponseTo,
814 request_abstract->ID);
815 /*
816 * It MUST NOT contain a NotBefore attribute. If
817 * the containing message is in response to an <AuthnRequest>,
818 * then the InResponseTo attribute MUST match the request's ID.
819 */
820 lasso_release_string(assertion->Subject->SubjectConfirmation->SubjectConfirmationData->NotBefore);
821 }
822 name_id_policy = authn_request->NameIDPolicy;
823 }
824 /* TRANSIENT */
825 if (!name_id_policy || name_id_policy->Format == NULL ||
826 lasso_strisequal(name_id_policy->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED) ||
827 lasso_strisequal(name_id_policy->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT)) {
828 char *id = lasso_build_unique_id(32);
829
830 name_id = (LassoSaml2NameID*)lasso_saml2_name_id_new_with_string(id);
831 lasso_release_string(id);
832 lasso_assign_string(name_id->NameQualifier,
833 lasso_provider_get_sp_name_qualifier(&profile->server->parent));
834 lasso_assign_string(name_id->Format, LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT);
835 assertion->Subject->NameID = name_id;
836 /* FEDERATED */
837 } else if (lasso_strisequal(name_id_policy->Format,
838 LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT) ||
839 lasso_strisequal(name_id_policy->Format,
840 LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENCRYPTED))
841 {
842 LassoFederation *federation;
843
844 federation = _lasso_login_saml20_get_federation(login);
845 goto_cleanup_if_fail_with_rc(federation != NULL,
846 LASSO_PROFILE_ERROR_FEDERATION_NOT_FOUND);
847
848 if (lasso_strisequal(name_id_policy->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENCRYPTED)) {
849 do_encrypt_nameid = TRUE;
850 }
851 lasso_assign_gobject(assertion->Subject->NameID,
852 federation->local_nameIdentifier);
853 /* ALL OTHER KIND OF NAME ID FORMATS */
854 } else {
855 /* caller must set the name identifier content afterwards */
856 name_id = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new());
857 lasso_assign_string(name_id->NameQualifier,
858 LASSO_PROVIDER(profile->server)->ProviderID);
859 lasso_assign_string(name_id->Format, name_id_policy->Format);
860 assertion->Subject->NameID = name_id;
861 if (do_encrypt_nameid) {
862 message(G_LOG_LEVEL_WARNING, "NameID encryption is currently not "
863 "supported with non transient or persisent NameID format");
864 do_encrypt_nameid = FALSE;
865 }
866 }
867
868 authentication_statement = LASSO_SAML2_AUTHN_STATEMENT(lasso_saml2_authn_statement_new());
869 authentication_statement->AuthnInstant = g_strdup(authenticationInstant);
870 authentication_statement->AuthnContext = LASSO_SAML2_AUTHN_CONTEXT(
871 lasso_saml2_authn_context_new());
872 authentication_statement->AuthnContext->AuthnContextClassRef = g_strdup(
873 authenticationMethod);
874
875 /* if remote provider supports logout profile, add a session index == ID of the assertion */
876 if (lasso_provider_get_first_http_method(&login->parent.server->parent,
877 provider, LASSO_MD_PROTOCOL_TYPE_SINGLE_LOGOUT) != LASSO_HTTP_METHOD_NONE) {
878 lasso_assign_string(authentication_statement->SessionIndex, assertion->ID);
879 }
880 lasso_list_add_new_gobject(assertion->AuthnStatement, authentication_statement);
881
882 /* Save signing material in assertion private datas to be able to sign later */
883 lasso_check_good_rc(lasso_server_saml2_assertion_setup_signature(profile->server,
884 assertion));
885
886 /* Encrypt NameID */
887 if (do_encrypt_nameid) {
888 /* store assertion in session object */
889 if (profile->session == NULL) {
890 profile->session = lasso_session_new();
891 }
892
893 lasso_session_add_assertion(profile->session, profile->remote_providerID,
894 LASSO_NODE(assertion));
895
896 /* FIXME: as with assertions, it should be possible to setup encryption of NameID for later */
897 goto_cleanup_if_fail_with_rc(provider != NULL, LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
898
899 assertion->Subject->EncryptedID = (LassoSaml2EncryptedElement*)lasso_node_encrypt(
900 (LassoNode*)assertion->Subject->NameID,
901 lasso_provider_get_encryption_public_key(provider),
902 lasso_provider_get_encryption_sym_key_type(provider),
903 provider->ProviderID);
904 goto_cleanup_if_fail_with_rc(assertion->Subject->EncryptedID != NULL,
905 LASSO_DS_ERROR_ENCRYPTION_FAILED);
906 lasso_release_gobject(assertion->Subject->NameID);
907 }
908
909 /* Save encryption material in assertion private datas to be able to encrypt later */
910 if (do_encrypt_assertion) {
911 lasso_node_set_encryption((LassoNode*)assertion,
912 lasso_provider_get_encryption_public_key(provider),
913 lasso_provider_get_encryption_sym_key_type(provider));
914 }
915
916 response = LASSO_SAMLP2_RESPONSE(profile->response);
917 lasso_list_add_gobject(response->Assertion, assertion);
918 lasso_assign_gobject(login->private_data->saml2_assertion, assertion);
919 cleanup:
920 lasso_release_gobject(assertion);
921 return rc;
922 }
923
924 gint
lasso_saml20_login_build_artifact_msg(LassoLogin * login,LassoHttpMethod http_method)925 lasso_saml20_login_build_artifact_msg(LassoLogin *login, LassoHttpMethod http_method)
926 {
927 LassoProfile *profile;
928 LassoProvider *remote_provider;
929 char *url;
930 LassoSaml2Assertion *assertion;
931 LassoSamlp2StatusResponse *response;
932 int rc = 0;
933
934 profile = &login->parent;
935
936 if (profile->remote_providerID == NULL)
937 return critical_error(LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID);
938
939 if (http_method != LASSO_HTTP_METHOD_ARTIFACT_GET && http_method != LASSO_HTTP_METHOD_ARTIFACT_POST) {
940 return critical_error(LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD);
941 }
942
943 if (! LASSO_IS_SAMLP2_RESPONSE(profile->response)) {
944 return critical_error(LASSO_PROFILE_ERROR_MISSING_RESPONSE);
945 }
946 response = (LassoSamlp2StatusResponse*)profile->response;
947 /* XXX: why checking now ? */
948 if (response->Status == NULL || response->Status->StatusCode == NULL
949 || response->Status->StatusCode->Value == NULL) {
950 return critical_error(LASSO_PROFILE_ERROR_MISSING_STATUS_CODE);
951 }
952
953 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
954 if (LASSO_IS_PROVIDER(remote_provider) == FALSE)
955 return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
956
957 url = lasso_saml20_login_get_assertion_consumer_service_url(login, remote_provider);
958 assertion = login->private_data->saml2_assertion;
959 if (LASSO_IS_SAML2_ASSERTION(assertion) && url) {
960 LassoSaml2SubjectConfirmationData *subject_confirmation_data;
961
962 subject_confirmation_data =
963 lasso_saml2_assertion_get_subject_confirmation_data(assertion, TRUE);
964 lasso_assign_string(subject_confirmation_data->Recipient, url);
965 }
966
967 /* If there is a non-encrypted NameID, fix the assertion in the session */
968 if (assertion && assertion->Subject && assertion->Subject->NameID) {
969 /* store assertion in session object */
970 if (profile->session == NULL) {
971 profile->session = lasso_session_new();
972 }
973 lasso_session_add_assertion(profile->session, profile->remote_providerID,
974 LASSO_NODE(assertion));
975 }
976
977
978 lasso_check_good_rc(lasso_saml20_profile_build_response_msg(profile, NULL, http_method,
979 url));
980
981 cleanup:
982 lasso_release_string(url);
983 return rc;
984 }
985
986
987 gint
lasso_saml20_login_init_request(LassoLogin * login,gchar * response_msg,LassoHttpMethod response_http_method)988 lasso_saml20_login_init_request(LassoLogin *login, gchar *response_msg,
989 LassoHttpMethod response_http_method)
990 {
991 return lasso_saml20_profile_init_artifact_resolve(LASSO_PROFILE(login),
992 LASSO_PROVIDER_ROLE_IDP, response_msg, response_http_method);
993 }
994
995
996 gint
lasso_saml20_login_build_request_msg(LassoLogin * login)997 lasso_saml20_login_build_request_msg(LassoLogin *login)
998 {
999 LassoProfile *profile;
1000 lasso_error_t rc = 0;
1001
1002 profile = &login->parent;
1003 if (_lasso_login_must_sign_non_authn_request(login)) {
1004 rc = lasso_profile_saml20_setup_message_signature(profile, profile->request);
1005 if (rc != 0) {
1006 return rc;
1007 }
1008 } else {
1009 lasso_node_remove_signature(profile->request);
1010 }
1011 return lasso_saml20_profile_build_request_msg(profile, "ArtifactResolutionService",
1012 LASSO_HTTP_METHOD_SOAP, profile->msg_url);
1013 }
1014
1015 gint
lasso_saml20_login_process_request_msg(LassoLogin * login,gchar * request_msg)1016 lasso_saml20_login_process_request_msg(LassoLogin *login, gchar *request_msg)
1017 {
1018 LassoProfile *profile = LASSO_PROFILE(login);
1019 int rc = 0;
1020
1021 rc = lasso_saml20_profile_process_artifact_resolve(profile, request_msg);
1022 if (rc != 0) {
1023 return rc;
1024 }
1025 /* compat with liberty id-ff code */
1026 lasso_assign_new_string(login->assertionArtifact, lasso_profile_get_artifact(profile));
1027 return 0;
1028 }
1029
1030 gint
lasso_saml20_login_build_response_msg(LassoLogin * login)1031 lasso_saml20_login_build_response_msg(LassoLogin *login)
1032 {
1033 LassoProfile *profile = LASSO_PROFILE(login);
1034 LassoProvider *remote_provider;
1035 LassoSaml2Assertion *assertion;
1036 int rc = 0;
1037
1038 if (login->protocolProfile == LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP) {
1039 char *assertionConsumerURL;
1040
1041 lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile,
1042 profile->response));
1043 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
1044 if (LASSO_IS_PROVIDER(remote_provider) == FALSE)
1045 return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
1046
1047 assertionConsumerURL = lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(
1048 remote_provider, LASSO_SAML2_METADATA_BINDING_PAOS);
1049
1050 assertion = login->private_data->saml2_assertion;
1051 if (LASSO_IS_SAML2_ASSERTION(assertion) == TRUE) {
1052 assertion->Subject->SubjectConfirmation->SubjectConfirmationData->Recipient
1053 = g_strdup(assertionConsumerURL);
1054 }
1055
1056 /* If response is signed it MUST have Destination attribute, optional otherwise */
1057 lasso_assign_string(((LassoSamlp2StatusResponse*)profile->response)->Destination,
1058 assertionConsumerURL);
1059
1060 /* build an ECP SOAP Response */
1061 lasso_assign_new_string(profile->msg_body, lasso_node_export_to_ecp_soap_response(
1062 LASSO_NODE(profile->response), assertionConsumerURL));
1063 lasso_release_string(assertionConsumerURL);
1064 return rc;
1065 }
1066
1067 return lasso_saml20_profile_build_artifact_response(LASSO_PROFILE(login));
1068
1069 cleanup:
1070 return rc;
1071 }
1072
1073 /**
1074 * lasso_saml20_login_process_paos_response_msg:
1075 * @login: a #LassoLogin profile object
1076 * @msg: ECP to SP PAOS message
1077 *
1078 * Process an ECP to SP PAOS response message.
1079 *
1080 * SAML2 Profile for ECP (Section 4.2) defines these steps for an ECP
1081 * transaction
1082 *
1083 * 1. ECP issues HTTP Request to SP
1084 * 2. SP issues <AuthnRequest> to ECP using PAOS
1085 * 3. ECP determines IdP
1086 * 4. ECP conveys <AuthnRequest> to IdP using SOAP
1087 * 5. IdP identifies principal
1088 * 6. IdP issues <Response> to ECP, targeted at SP using SOAP
1089 * 7. ECP conveys <Response> to SP using PAOS
1090 * 8. SP grants or denies access to principal
1091 *
1092 * This function is used in the implemention of Step 8 in an SP. The
1093 * ECP response from Step 7 has been received from the ECP client, the
1094 * SP must now parse the response and act upon the result of the Authn
1095 * request the SP issued in Step 2. If the SOAP body contains a
1096 * samlp:Response with a saml:Assertion the assertion is processed in
1097 * the context of the @login parameter.
1098 *
1099 * The response may contain in the SOAP header a paos:Response or
1100 * ecp:RelayState elment, both are optional. If the ecp:RelayState is
1101 * present it is assigned to the #LassoProfile.msg_relayState
1102 * field. If the paos:Response is present it's refToMessageID
1103 * attribute is assigned to the #LassoProfile.msg_messageID field.
1104 */
1105 gint
lasso_saml20_login_process_paos_response_msg(LassoLogin * login,gchar * msg)1106 lasso_saml20_login_process_paos_response_msg(LassoLogin *login, gchar *msg)
1107 {
1108 LassoSoapHeader *header = NULL;
1109 LassoProfile *profile;
1110 int rc;
1111
1112 lasso_null_param(msg);
1113
1114 profile = LASSO_PROFILE(login);
1115
1116 /*
1117 * lasso_saml20_profile_process_soap_response_with_headers()
1118 * performs a signature check on the SAML message. A signature
1119 * can also appear on the assertion which is checked by
1120 * lasso_saml20_login_process_response_status_and_assertion()
1121 * (below). Therefore if the error is SIGNATURE_NOT_FOUND we
1122 * proceed because
1123 * lasso_saml20_login_process_response_status_and_assertion()
1124 * will test the signature on the assertion.
1125 */
1126 rc = lasso_saml20_profile_process_soap_response_with_headers(profile, msg, &header);
1127 if (rc != 0 && rc != LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) {
1128 return rc;
1129 }
1130
1131 /*
1132 * If the SOAP message contained a header check for the optional
1133 * paos:Response and ecp:RelayState elements, if they exist extract their
1134 * values into the profile.
1135 */
1136 if (header) {
1137 GList *i = NULL;
1138 LassoEcpRelayState *ecp_relaystate = NULL;
1139 LassoPaosResponse *paos_response = NULL;
1140
1141 lasso_foreach(i, header->Other) {
1142 if (!ecp_relaystate && LASSO_IS_ECP_RELAYSTATE(i->data)) {
1143 ecp_relaystate = (LassoEcpRelayState *)i->data;
1144 } else if (!paos_response && LASSO_IS_PAOS_RESPONSE(i->data)) {
1145 paos_response = (LassoPaosResponse *)i->data;
1146 }
1147 if (ecp_relaystate && paos_response) break;
1148 }
1149 if (ecp_relaystate) {
1150 lasso_assign_string(profile->msg_relayState, ecp_relaystate->RelayState);
1151 }
1152 if (paos_response) {
1153 lasso_profile_set_message_id(profile, paos_response->refToMessageID);
1154 }
1155 lasso_release_gobject(header);
1156 }
1157
1158 rc = lasso_saml20_login_process_response_status_and_assertion(login);
1159 return rc;
1160 }
1161
1162 /**
1163 * lasso_saml20_login_process_authn_response_msg:
1164 * @login: a #LassoLogin profile object
1165 * @authn_response_msg: a string containg a response msg to an #LassoSaml2AuthnRequest
1166 *
1167 * Parse a response made using binding HTTP-Redirect, HTTP-Post or HTTP-SOAP. Any signature
1168 * validation error is reported.
1169 *
1170 * Return value: 0 if succesfull, an error code otherwise.
1171 */
1172 gint
lasso_saml20_login_process_authn_response_msg(LassoLogin * login,gchar * authn_response_msg)1173 lasso_saml20_login_process_authn_response_msg(LassoLogin *login, gchar *authn_response_msg)
1174 {
1175 LassoProfile *profile = NULL;
1176 LassoSamlp2Response *samlp2_response = NULL;
1177 LassoHttpMethod response_method = LASSO_HTTP_METHOD_NONE;
1178 int rc = 0;
1179
1180 lasso_null_param(authn_response_msg);
1181
1182 /* parse the message */
1183 profile = LASSO_PROFILE(login);
1184 samlp2_response = (LassoSamlp2Response*)lasso_samlp2_response_new();
1185 rc = lasso_saml20_profile_process_any_response(profile,
1186 (LassoSamlp2StatusResponse*)samlp2_response, &response_method,
1187 authn_response_msg);
1188
1189 if (response_method != LASSO_HTTP_METHOD_POST) {
1190 /* Only HTTP-Post binding is possible through this method */
1191 goto_cleanup_with_rc(LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE);
1192 }
1193
1194 /* Skip signature errors, let lasso_saml20_login_process_response_status_and_assertion
1195 * handle them */
1196 goto_cleanup_if_fail (rc == 0 || rc == LASSO_LOGIN_ERROR_STATUS_NOT_SUCCESS || rc ==
1197 LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE);
1198
1199 rc = lasso_saml20_login_process_response_status_and_assertion(login);
1200 cleanup:
1201 lasso_release_gobject(samlp2_response);
1202 return rc;
1203 }
1204
1205 gint
lasso_saml20_login_process_response_msg(LassoLogin * login,gchar * response_msg)1206 lasso_saml20_login_process_response_msg(LassoLogin *login, gchar *response_msg)
1207 {
1208 LassoProfile *profile = LASSO_PROFILE(login);
1209 int rc = 0;
1210
1211 rc = lasso_saml20_profile_process_artifact_response(profile, response_msg);
1212 if (rc) {
1213 return rc;
1214 }
1215 if (LASSO_IS_SAMLP2_ARTIFACT_RESPONSE(login->parent.response)) {
1216 return lasso_saml20_login_process_authn_request_msg(login, NULL);
1217 } else {
1218 return lasso_saml20_login_process_response_status_and_assertion(login);
1219 }
1220 }
1221
1222 static gint
lasso_saml20_login_check_assertion_signature(LassoLogin * login,LassoSaml2Assertion * assertion)1223 lasso_saml20_login_check_assertion_signature(LassoLogin *login,
1224 LassoSaml2Assertion *assertion)
1225 {
1226 xmlNode *original_node = NULL;
1227 LassoSaml2NameID *Issuer = NULL;
1228 LassoServer *server = NULL;
1229 LassoProfile *profile = NULL;
1230 char *remote_provider_id = NULL;
1231 LassoProvider *remote_provider;
1232 int rc = 0;
1233
1234 lasso_bad_param(SAML2_ASSERTION, assertion);
1235
1236 profile = (LassoProfile*)login;
1237 lasso_extract_node_or_fail(server, lasso_profile_get_server(profile),
1238 SERVER, LASSO_PROFILE_ERROR_MISSING_SERVER);
1239
1240 /* Get an issuer */
1241 Issuer = assertion->Issuer;
1242 if (! Issuer || /* No issuer */
1243 ! Issuer->content || /* No issuer content */
1244 (Issuer->Format &&
1245 lasso_strisnotequal(Issuer->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENTITY)))
1246 /* Issuer format is not entity */
1247 {
1248 rc = LASSO_PROFILE_ERROR_MISSING_ISSUER;
1249 goto cleanup;
1250 } else {
1251 remote_provider_id = Issuer->content;
1252 }
1253 remote_provider = lasso_server_get_provider(server, remote_provider_id);
1254 goto_cleanup_if_fail_with_rc(remote_provider, LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
1255
1256 /* Get the original node */
1257 original_node = lasso_node_get_original_xmlnode(LASSO_NODE(assertion));
1258 goto_cleanup_if_fail_with_rc(original_node, LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE);
1259
1260 /* Shouldn't set the profile->signature_status here as we're only
1261 * checking the assertion signature.
1262 * Instead, we'll set the status after all the assertions are iterated.
1263 */
1264 rc = lasso_provider_verify_saml_signature(remote_provider, original_node, NULL);
1265
1266 #define log_verify_assertion_signature_error(msg) \
1267 message(G_LOG_LEVEL_WARNING, "Could not verify signature of assertion" \
1268 "ID:%s, " msg ".", assertion->ID);
1269 cleanup:
1270 switch (rc) {
1271 case LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND:
1272 log_verify_assertion_signature_error("Issuer is unknown");
1273 break;
1274 case LASSO_PROFILE_ERROR_MISSING_ISSUER:
1275 log_verify_assertion_signature_error(
1276 "no Issuer found or Issuer has bad format");
1277 break;
1278 case LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE:
1279 log_verify_assertion_signature_error(
1280 " the original xmlNode is certainly not accessible anymore");
1281
1282 default:
1283 break;
1284 }
1285 #undef log_verify_assertion_signature_error
1286 return rc;
1287 }
1288
1289 static gint
_lasso_saml20_login_decrypt_assertion(LassoLogin * login,LassoSamlp2Response * samlp2_response)1290 _lasso_saml20_login_decrypt_assertion(LassoLogin *login, LassoSamlp2Response *samlp2_response)
1291 {
1292 GList *encryption_private_keys = NULL;
1293 GList *it = NULL;
1294 gboolean at_least_one_decryption_failture = FALSE;
1295 gboolean at_least_one_malformed_element = FALSE;
1296
1297 if (! samlp2_response->EncryptedAssertion)
1298 return 0; /* nothing to do */
1299
1300 encryption_private_keys = lasso_server_get_encryption_private_keys(login->parent.server);
1301 if (! encryption_private_keys) {
1302 message(G_LOG_LEVEL_WARNING, "Missing private encryption key, cannot decrypt assertions.");
1303 return LASSO_DS_ERROR_DECRYPTION_FAILED_MISSING_PRIVATE_KEY;
1304 }
1305
1306 lasso_foreach (it, samlp2_response->EncryptedAssertion) {
1307 LassoSaml2EncryptedElement *encrypted_assertion;
1308 LassoSaml2Assertion * assertion = NULL;
1309 int rc1 = 0;
1310
1311 if (! LASSO_IS_SAML2_ENCRYPTED_ELEMENT(it->data)) {
1312 message(G_LOG_LEVEL_WARNING, "EncryptedAssertion contains a non EncryptedElement object");
1313 at_least_one_malformed_element |= TRUE;
1314 continue;
1315 }
1316 encrypted_assertion = (LassoSaml2EncryptedElement*)it->data;
1317 lasso_foreach_full_begin(xmlSecKey*, encryption_private_key, it,
1318 encryption_private_keys)
1319 {
1320 rc1 = lasso_saml2_encrypted_element_decrypt(encrypted_assertion, encryption_private_key, (LassoNode**)&assertion);
1321 if (rc1 == 0)
1322 break;
1323 }
1324 lasso_foreach_full_end();
1325 if (rc1 == LASSO_DS_ERROR_DECRYPTION_FAILED) {
1326 message(G_LOG_LEVEL_WARNING, "Could not decrypt the EncryptedKey");
1327 at_least_one_decryption_failture |= TRUE;
1328 continue;
1329 } else if (rc1) {
1330 message(G_LOG_LEVEL_WARNING, "Could not decrypt an assertion: %s", lasso_strerror(rc1));
1331 at_least_one_decryption_failture |= TRUE;
1332 continue;
1333 }
1334
1335 if (! LASSO_IS_SAML2_ASSERTION(assertion)) {
1336 message(G_LOG_LEVEL_WARNING, "EncryptedAssertion contains something that is not an assertion");
1337 lasso_release_gobject(assertion);
1338 continue;
1339 }
1340 /* copy the assertion to the clear assertion list */
1341 lasso_list_add_new_gobject(samlp2_response->Assertion, assertion);
1342 }
1343
1344 if (at_least_one_decryption_failture) {
1345 return LASSO_DS_ERROR_DECRYPTION_FAILED;
1346 }
1347 if (at_least_one_malformed_element) {
1348 return LASSO_XML_ERROR_SCHEMA_INVALID_FRAGMENT;
1349 }
1350 return 0;
1351 }
1352
1353 /* Verify that an assertion comes from a designated Issuer */
1354 static gboolean
_lasso_check_assertion_issuer(LassoSaml2Assertion * assertion,const gchar * provider_id)1355 _lasso_check_assertion_issuer(LassoSaml2Assertion *assertion, const gchar *provider_id)
1356 {
1357 if (! LASSO_SAML2_ASSERTION(assertion) || ! provider_id)
1358 return FALSE;
1359 if (! assertion->Issuer || ! assertion->Issuer->content)
1360 return FALSE;
1361 return lasso_strisequal(assertion->Issuer->content,provider_id);
1362 }
1363
1364 static gint
lasso_saml20_login_process_response_status_and_assertion(LassoLogin * login)1365 lasso_saml20_login_process_response_status_and_assertion(LassoLogin *login)
1366 {
1367 LassoSamlp2StatusResponse *response;
1368 LassoSamlp2Response *samlp2_response = NULL;
1369 LassoSaml2Assertion *last_assertion = NULL;
1370 LassoProfile *profile;
1371 char *status_value;
1372 lasso_error_t rc = 0;
1373 lasso_error_t assertion_signature_status = 0;
1374 LassoProfileSignatureVerifyHint verify_hint;
1375
1376 profile = &login->parent;
1377 lasso_extract_node_or_fail(response, profile->response, SAMLP2_STATUS_RESPONSE,
1378 LASSO_PROFILE_ERROR_INVALID_MSG);
1379 lasso_extract_node_or_fail(samlp2_response, response, SAMLP2_RESPONSE,
1380 LASSO_PROFILE_ERROR_INVALID_MSG);
1381
1382 if (response->Status == NULL || ! LASSO_IS_SAMLP2_STATUS(response->Status) ||
1383 response->Status->StatusCode == NULL ||
1384 response->Status->StatusCode->Value == NULL) {
1385 return LASSO_PROFILE_ERROR_MISSING_STATUS_CODE;
1386 }
1387
1388 status_value = response->Status->StatusCode->Value;
1389 if (status_value && lasso_strisnotequal(status_value,LASSO_SAML2_STATUS_CODE_SUCCESS)) {
1390 if (lasso_strisequal(status_value,LASSO_SAML2_STATUS_CODE_REQUEST_DENIED))
1391 return LASSO_LOGIN_ERROR_REQUEST_DENIED;
1392 if (lasso_strisequal(status_value,LASSO_SAML2_STATUS_CODE_RESPONDER) ||
1393 lasso_strisequal(status_value,LASSO_SAML2_STATUS_CODE_REQUESTER)) {
1394 /* samlp:Responder */
1395 if (response->Status->StatusCode->StatusCode &&
1396 response->Status->StatusCode->StatusCode->Value) {
1397 status_value = response->Status->StatusCode->StatusCode->Value;
1398 if (lasso_strisequal(status_value,LASSO_LIB_STATUS_CODE_FEDERATION_DOES_NOT_EXIST)) {
1399 return LASSO_LOGIN_ERROR_FEDERATION_NOT_FOUND;
1400 }
1401 if (lasso_strisequal(status_value,LASSO_LIB_STATUS_CODE_UNKNOWN_PRINCIPAL)) {
1402 return LASSO_LOGIN_ERROR_UNKNOWN_PRINCIPAL;
1403 }
1404 }
1405 }
1406 return LASSO_LOGIN_ERROR_STATUS_NOT_SUCCESS;
1407 }
1408
1409 /* Decrypt all EncryptedAssertions */
1410 _lasso_saml20_login_decrypt_assertion(login, samlp2_response);
1411
1412 /* Check there is at least one assertion */
1413 goto_cleanup_if_fail_with_rc (samlp2_response->Assertion != NULL, LASSO_PROFILE_ERROR_MISSING_ASSERTION);
1414
1415 /* In case of verify_hint as 'FORCE', if there's no response signature,
1416 * we reject.
1417 * In case of 'MAYBE', if response signature is present and valid, or
1418 * not present, then we proceed with checking assertion signature(s).
1419 * In any case, if there's a response signature and it's not valid,
1420 * we reject.
1421 */
1422 verify_hint = lasso_profile_get_signature_verify_hint(profile);
1423 if (profile->signature_status == LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) {
1424 if (verify_hint == LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE) {
1425 goto_cleanup_with_rc(profile->signature_status);
1426 }
1427 } else if (profile->signature_status != 0) {
1428 goto_cleanup_with_rc(profile->signature_status);
1429 }
1430
1431 lasso_foreach_full_begin(LassoSaml2Assertion*, assertion, it, samlp2_response->Assertion);
1432 LassoSaml2Subject *subject = NULL;
1433
1434 /* All Assertions MUST come from the same issuer as the Response. */
1435 if (! _lasso_check_assertion_issuer(assertion, profile->remote_providerID)) {
1436 goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_ISSUER);
1437 }
1438
1439 if (profile->signature_status != 0) {
1440 /* When response signature is not present */
1441 if (verify_hint == LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE) {
1442 assertion_signature_status =
1443 lasso_saml20_login_check_assertion_signature(login, assertion);
1444 if (assertion_signature_status) {
1445 goto_cleanup_with_rc(assertion_signature_status);
1446 }
1447 }
1448 } else {
1449 /* response signature is present and valid */
1450 assertion_signature_status = lasso_saml20_login_check_assertion_signature(login,
1451 assertion);
1452 if (assertion_signature_status) {
1453 /* assertion signature is not valid or not present */
1454 if (verify_hint == LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE) {
1455 /* In case of FORCE, we reject right away */
1456 goto_cleanup_with_rc(assertion_signature_status);
1457 } else if (verify_hint == LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE) {
1458 /* In case of MAYBE, if assertion signature is present and invalid, then we reject */
1459 if (assertion_signature_status != LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) {
1460 goto_cleanup_with_rc(assertion_signature_status);
1461 }
1462 }
1463 }
1464 }
1465 lasso_extract_node_or_fail(subject, assertion->Subject, SAML2_SUBJECT,
1466 LASSO_PROFILE_ERROR_MISSING_SUBJECT);
1467
1468 /* Verify Subject->SubjectConfirmationData->InResponseTo */
1469 if (login->private_data->request_id) {
1470 const char *in_response_to = lasso_saml2_assertion_get_in_response_to(assertion);
1471
1472 if (lasso_strisnotequal(in_response_to,login->private_data->request_id)) {
1473 rc = LASSO_LOGIN_ERROR_ASSERTION_DOES_NOT_MATCH_REQUEST_ID;
1474 goto cleanup;
1475 }
1476 }
1477
1478 /** Handle nameid */
1479 lasso_check_good_rc(lasso_saml20_profile_process_name_identifier_decryption(profile,
1480 &subject->NameID, &subject->EncryptedID));
1481
1482 last_assertion = assertion;
1483 lasso_foreach_full_end();
1484
1485 /* set the profile signature status only after all the signatures are
1486 * verified.
1487 */
1488 profile->signature_status = rc;
1489
1490 /* set the default assertion to the last one */
1491 if (last_assertion) {
1492 lasso_assign_gobject (login->private_data->saml2_assertion, last_assertion);
1493 }
1494
1495 switch (verify_hint) {
1496 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
1497 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
1498 break;
1499 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
1500 /* ignore signature errors */
1501 if (rc == LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE) {
1502 rc = 0;
1503 }
1504 break;
1505 default:
1506 g_assert(0);
1507 }
1508 cleanup:
1509 return rc;
1510 }
1511
1512
1513 gint
lasso_saml20_login_accept_sso(LassoLogin * login)1514 lasso_saml20_login_accept_sso(LassoLogin *login)
1515 {
1516 LassoProfile *profile;
1517 LassoSaml2Assertion *assertion;
1518 GList *previous_assertion_ids, *t;
1519 LassoSaml2NameID *ni;
1520 LassoFederation *federation;
1521
1522 profile = LASSO_PROFILE(login);
1523 if (LASSO_SAMLP2_RESPONSE(profile->response)->Assertion == NULL)
1524 return LASSO_PROFILE_ERROR_MISSING_ASSERTION;
1525
1526 assertion = LASSO_SAMLP2_RESPONSE(profile->response)->Assertion->data;
1527 if (assertion == NULL)
1528 return LASSO_PROFILE_ERROR_MISSING_ASSERTION;
1529
1530 previous_assertion_ids = lasso_session_get_assertion_ids(profile->session,
1531 profile->remote_providerID);
1532 lasso_foreach(t, previous_assertion_ids) {
1533 if (lasso_strisequal(t->data, assertion->ID)) {
1534 lasso_release_list_of_strings(previous_assertion_ids);
1535 return LASSO_LOGIN_ERROR_ASSERTION_REPLAY;
1536 }
1537 }
1538 lasso_release_list_of_strings(previous_assertion_ids);
1539
1540 lasso_session_add_assertion(profile->session, profile->remote_providerID,
1541 LASSO_NODE(assertion));
1542
1543 if (assertion->Subject && assertion->Subject->NameID) {
1544 ni = assertion->Subject->NameID;
1545 } else {
1546 return LASSO_PROFILE_ERROR_MISSING_NAME_IDENTIFIER;
1547 }
1548
1549 /* create federation, only if nameidentifier format is Federated */
1550 if (ni && ni->Format
1551 && lasso_strisequal(ni->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT)) {
1552 federation = lasso_federation_new(LASSO_PROFILE(login)->remote_providerID);
1553
1554 lasso_assign_gobject(federation->local_nameIdentifier, ni);
1555 /* add federation in identity */
1556 lasso_identity_add_federation(LASSO_PROFILE(login)->identity, federation);
1557 }
1558
1559 return 0;
1560 }
1561
1562 gint
lasso_saml20_login_build_authn_response_msg(LassoLogin * login)1563 lasso_saml20_login_build_authn_response_msg(LassoLogin *login)
1564 {
1565 LassoProfile *profile;
1566 LassoProvider *remote_provider = NULL;
1567 LassoSaml2Assertion *assertion = NULL;
1568 LassoHttpMethod http_method = LASSO_HTTP_METHOD_NONE;
1569 char *url = NULL;
1570 int rc = 0;
1571
1572 profile = &login->parent;
1573
1574 if (login->protocolProfile != LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST &&
1575 login->protocolProfile != LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT) {
1576 return critical_error(LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE);
1577 }
1578
1579 if (_lasso_login_must_sign_non_authn_request(login)) {
1580 lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile,
1581 profile->response));
1582 } else {
1583 lasso_node_remove_signature(profile->response);
1584 }
1585
1586 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
1587 if (LASSO_IS_PROVIDER(remote_provider) == FALSE)
1588 return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
1589
1590 url = lasso_saml20_login_get_assertion_consumer_service_url(login, remote_provider);
1591
1592 assertion = login->private_data->saml2_assertion;
1593 if (LASSO_IS_SAML2_ASSERTION(assertion) && url) {
1594 LassoSaml2SubjectConfirmationData *subject_confirmation_data;
1595
1596 subject_confirmation_data =
1597 lasso_saml2_assertion_get_subject_confirmation_data(assertion, TRUE);
1598 lasso_assign_string(subject_confirmation_data->Recipient, url);
1599 }
1600
1601 /* If there is a non-encrypted NameID, fix the assertion in the session */
1602 if (assertion && assertion->Subject && assertion->Subject->NameID) {
1603 /* store assertion in session object */
1604 if (profile->session == NULL) {
1605 profile->session = lasso_session_new();
1606 }
1607 lasso_session_add_assertion(profile->session, profile->remote_providerID,
1608 LASSO_NODE(assertion));
1609 }
1610
1611 switch (login->protocolProfile) {
1612 case LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST:
1613 http_method = LASSO_HTTP_METHOD_POST;
1614 break;
1615 case LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT:
1616 http_method = LASSO_HTTP_METHOD_REDIRECT;
1617 break;
1618 default:
1619 message(G_LOG_LEVEL_CRITICAL, "Cannot happen");
1620 break;
1621 }
1622 lasso_check_good_rc(lasso_saml20_profile_build_response_msg(profile, NULL, http_method, url));
1623
1624 cleanup:
1625 lasso_release_string(url);
1626 return rc;
1627 }
1628
1629 static char*
lasso_saml20_login_get_assertion_consumer_service_url(LassoLogin * login,LassoProvider * remote_provider)1630 lasso_saml20_login_get_assertion_consumer_service_url(LassoLogin *login,
1631 LassoProvider *remote_provider)
1632 {
1633 LassoSamlp2AuthnRequest *request;
1634 char *url = NULL;
1635
1636 request = LASSO_SAMLP2_AUTHN_REQUEST(LASSO_PROFILE(login)->request);
1637
1638 if (request->AssertionConsumerServiceURL) {
1639 if (lasso_saml20_provider_check_assertion_consumer_service_url(remote_provider,
1640 request->AssertionConsumerServiceURL,
1641 request->ProtocolBinding)) {
1642 return g_strdup(request->AssertionConsumerServiceURL);
1643 }
1644 }
1645
1646 if (request->AssertionConsumerServiceIndex != -1 || request->ProtocolBinding == NULL) {
1647 url = lasso_saml20_provider_get_assertion_consumer_service_url(remote_provider,
1648 request->AssertionConsumerServiceIndex);
1649 }
1650
1651 if (url == NULL && request->ProtocolBinding) {
1652 url = lasso_saml20_provider_get_assertion_consumer_service_url_by_binding(
1653 remote_provider, request->ProtocolBinding);
1654 }
1655
1656 if (url == NULL) {
1657 message(G_LOG_LEVEL_WARNING,
1658 "can't find assertion consumer service url (going for default)");
1659 url = lasso_saml20_provider_get_assertion_consumer_service_url(remote_provider, -1);
1660 }
1661
1662 return url;
1663 }
1664
1665 gint
lasso_saml20_login_init_idp_initiated_authn_request(LassoLogin * login,const gchar * remote_providerID)1666 lasso_saml20_login_init_idp_initiated_authn_request(LassoLogin *login,
1667 const gchar *remote_providerID)
1668 {
1669 LassoProfile *profile = NULL;
1670 LassoProvider *provider = NULL;
1671 LassoServer *server = NULL;
1672 gchar *default_name_id_format = NULL;
1673 int rc = 0;
1674
1675 profile = &login->parent;
1676 lasso_extract_node_or_fail(server, lasso_profile_get_server(profile), SERVER,
1677 LASSO_PROFILE_ERROR_MISSING_SERVER);
1678 provider = lasso_server_get_provider(server, remote_providerID);
1679 if (! LASSO_IS_PROVIDER(provider))
1680 return LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND;
1681
1682 /* fix roles */
1683 server->parent.role = LASSO_PROVIDER_ROLE_IDP;
1684 provider->role = LASSO_PROVIDER_ROLE_SP;
1685
1686 lasso_assign_string(profile->remote_providerID, remote_providerID);
1687 lasso_assign_new_gobject(profile->request, lasso_samlp2_authn_request_new());
1688 lasso_assign_new_gobject(LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->NameIDPolicy,
1689 lasso_samlp2_name_id_policy_new());
1690 lasso_assign_new_gobject(LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->Issuer,
1691 LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
1692 (char*)remote_providerID)));
1693 default_name_id_format = lasso_provider_get_default_name_id_format(provider);
1694 /* Change default NameIDFormat if default exists */
1695 if (default_name_id_format) {
1696 lasso_assign_new_string(LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->NameIDPolicy->Format,
1697 default_name_id_format);
1698 } else {
1699 /* we eventually used the default of the IDP (not of the target SP), so we reset to
1700 * Lasso default, that is Transient */
1701 lasso_assign_string(LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->NameIDPolicy->Format,
1702 LASSO_SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT);
1703 }
1704 lasso_assign_string(LASSO_SAMLP2_AUTHN_REQUEST(profile->request)->NameIDPolicy->SPNameQualifier,
1705 remote_providerID);
1706 cleanup:
1707
1708 return rc;
1709 }
1710