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