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 <xmlsec/base64.h>
26
27 #include "../utils.h"
28 #include "providerprivate.h"
29 #include "profileprivate.h"
30 #include "profile.h"
31 #include "provider.h"
32
33 #include "../id-ff/providerprivate.h"
34 #include "../id-ff/profile.h"
35 #include "../id-ff/profileprivate.h"
36 #include "../id-ff/serverprivate.h"
37 #include "../id-ff/sessionprivate.h"
38 #include "../id-ff/login.h"
39
40 #include "../xml/private.h"
41 #include "../xml/soap-1.1/soap_envelope.h"
42 #include "../xml/saml-2.0/samlp2_request_abstract.h"
43 #include "../xml/saml-2.0/samlp2_artifact_resolve.h"
44 #include "../xml/saml-2.0/samlp2_artifact_response.h"
45 #include "../xml/saml-2.0/samlp2_authn_request.h"
46 #include "../xml/saml-2.0/samlp2_name_id_mapping_response.h"
47 #include "../xml/saml-2.0/samlp2_status_response.h"
48 #include "../xml/saml-2.0/samlp2_response.h"
49 #include "../xml/saml-2.0/saml2_assertion.h"
50 #include "../xml/saml-2.0/saml2_xsd.h"
51 #include "../xml/soap-1.1/soap_envelope.h"
52 #include "../xml/misc_text_node.h"
53 #include "../utils.h"
54 #include "../debug.h"
55
56
57
58 static char* lasso_saml20_profile_build_artifact(LassoProvider *provider);
59 static int lasso_saml20_profile_export_to_query(LassoProfile *profile, LassoNode *msg, char **query,
60 LassoSignatureContext context);
61 static gint lasso_profile_saml20_build_artifact_get_request_msg(LassoProfile *profile,
62 const char *service);
63 static gint lasso_profile_saml20_build_artifact_post_request_msg(LassoProfile *profile,
64 const char *service);
65 static gint lasso_profile_saml20_build_artifact_get_response_msg(LassoProfile *profile,
66 const char *service);
67 static gint lasso_profile_saml20_build_artifact_post_response_msg(LassoProfile *profile,
68 const char *service);
69 static char* lasso_saml20_profile_generate_artifact(LassoProfile *profile, int part);
70
71 #define check_msg_body \
72 if (! profile->msg_body) { \
73 return critical_error(LASSO_PROFILE_ERROR_BUILDING_MESSAGE_FAILED); \
74 }
75
76 /*
77 * Helper functions
78 */
79 static int
get_provider(LassoProfile * profile,LassoProvider ** provider_out)80 get_provider(LassoProfile *profile, LassoProvider **provider_out)
81 {
82 LassoProvider *provider;
83 LassoServer *server;
84 int rc = 0;
85
86 lasso_bad_param(PROFILE, profile);
87
88 lasso_extract_node_or_fail(server, profile->server, SERVER,
89 LASSO_PROFILE_ERROR_MISSING_SERVER);
90 provider = lasso_server_get_provider(server, profile->remote_providerID);
91 if (! provider) {
92 return LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND;
93 }
94
95 *provider_out = provider;
96 cleanup:
97 return rc;
98 }
99
100 static char *
get_url(LassoProvider * provider,const char * service,const char * binding)101 get_url(LassoProvider *provider, const char *service, const char *binding)
102 {
103 char *meta;
104 char *result;
105
106 meta = g_strdup_printf("%s %s", service, binding);
107 result = lasso_provider_get_metadata_one(provider, meta);
108 lasso_release_string(meta);
109 return result;
110 }
111
112 static char *
get_response_url(LassoProvider * provider,const char * service,const char * binding)113 get_response_url(LassoProvider *provider, const char *service, const char *binding)
114 {
115 char *meta;
116 char *result;
117
118 meta = g_strdup_printf("%s %s ResponseLocation", service, binding);
119 result = lasso_provider_get_metadata_one(provider, meta);
120 lasso_release_string(meta);
121 if (! result) {
122 result = get_url(provider, service, binding);
123 }
124 return result;
125 }
126
127 static const char*
http_method_to_binding(LassoHttpMethod method)128 http_method_to_binding(LassoHttpMethod method) {
129 switch (method) {
130 case LASSO_HTTP_METHOD_POST:
131 return "HTTP-POST";
132 case LASSO_HTTP_METHOD_REDIRECT:
133 return "HTTP-Redirect";
134 case LASSO_HTTP_METHOD_SOAP:
135 return "SOAP";
136 case LASSO_HTTP_METHOD_ARTIFACT_GET:
137 case LASSO_HTTP_METHOD_ARTIFACT_POST:
138 return "HTTP-Artifact";
139 case LASSO_HTTP_METHOD_PAOS:
140 return "PAOS";
141 default:
142 return "";
143 }
144 }
145
146 /*
147 * Artifact Handling functions
148 */
149
150 /**
151 * lasso_saml20_profile_generate_artifact
152 * @profile: a #LassoProfile
153 * @part: 0 for request, 1 for response
154 *
155 * Generates an artifact for current request or response and sets @profile
156 * attributes accordingly.
157 *
158 * Return value: the generated artifact (internally allocated, don't free)
159 **/
160 static char*
lasso_saml20_profile_generate_artifact(LassoProfile * profile,int part)161 lasso_saml20_profile_generate_artifact(LassoProfile *profile, int part)
162 {
163 LassoNode *what = NULL;
164 lasso_assign_new_string(profile->private_data->artifact,
165 lasso_saml20_profile_build_artifact(&profile->server->parent));
166 if (part == 0) {
167 what = profile->request;
168 } else if (part == 1) {
169 what = profile->response;
170 } else {
171 /* XXX: RequestDenied here? */
172 }
173 /* Remove signature at the response level, if needed if will be on the ArtifactResponse */
174 lasso_node_remove_signature(what);
175 /* Keep an XML copy of the response for later retrieval */
176 lasso_assign_new_string(profile->private_data->artifact_message,
177 lasso_node_export_to_xml(what));
178
179 return profile->private_data->artifact;
180 }
181
182
183 static char*
lasso_saml20_profile_build_artifact(LassoProvider * provider)184 lasso_saml20_profile_build_artifact(LassoProvider *provider)
185 {
186 xmlSecByte samlArt[44], *b64_samlArt = NULL;
187 char *source_succinct_id = NULL;
188 char *ret = NULL;
189 unsigned short index;
190
191 source_succinct_id = lasso_sha1(provider->ProviderID);
192 /* XXX: unchecked return value*/
193 goto_cleanup_if_fail(lasso_saml20_provider_get_artifact_resolution_service_index(provider,
194 &index) == 0);
195 /* Artifact Format is described in saml-bindings-2.0-os, 3.6.4.2. */
196 memcpy(samlArt, "\000\004", 2); /* type code */
197 samlArt[2] = 0xFF & (index >> 8);
198 samlArt[3] = 0xFF & index;
199 memcpy(samlArt+4, source_succinct_id, 20);
200 lasso_build_random_sequence((char*)samlArt+24, 20);
201
202 b64_samlArt = xmlSecBase64Encode(samlArt, 44, 0);
203
204 ret = g_strdup((char*)b64_samlArt);
205 cleanup:
206 if (ret == NULL) {
207 warning("Unable to find an artifact resolution service for entity id %s with %d",
208 provider->ProviderID, provider->role);
209 }
210 lasso_release_string(source_succinct_id);
211 lasso_release_xml_string(b64_samlArt);
212
213 return ret;
214 }
215
216 /*
217 * this function factorize all case for producing SAML artifact messages
218 */
219 static gint
lasso_profile_saml20_build_artifact_msg(LassoProfile * profile,const char * url,int request_or_response,int get_or_post)220 lasso_profile_saml20_build_artifact_msg(LassoProfile *profile,
221 const char *url, int request_or_response, int get_or_post)
222 {
223 char *artifact = lasso_saml20_profile_generate_artifact(profile, request_or_response);
224
225 if (artifact == NULL) {
226 return critical_error(LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED);
227 }
228 /* hack... */
229 if (LASSO_IS_LOGIN(profile)) {
230 LassoLogin *login = (LassoLogin*)profile;
231 lasso_assign_string(login->assertionArtifact, artifact);
232 }
233
234 if (get_or_post == 0) {
235 char *query;
236 if (profile->msg_relayState) {
237 query = lasso_url_add_parameters(NULL, 0, LASSO_SAML2_FIELD_ARTIFACT, artifact, "RelayState",
238 profile->msg_relayState, NULL);
239 } else {
240 query = lasso_url_add_parameters(NULL, 0, LASSO_SAML2_FIELD_ARTIFACT, artifact, NULL);
241 }
242 lasso_assign_new_string(profile->msg_url,
243 lasso_concat_url_query(url, query));
244 lasso_release_string(query);
245 } else {
246 lasso_assign_string(profile->msg_url, url);
247 lasso_assign_string(profile->msg_body, artifact);
248 }
249 return 0;
250 }
251
252 enum {
253 REQUEST = 0,
254 RESPONSE = 1,
255 GET = 0,
256 POST = 1
257 };
258
259 static gint
lasso_profile_saml20_build_artifact_get_request_msg(LassoProfile * profile,const char * url)260 lasso_profile_saml20_build_artifact_get_request_msg(LassoProfile *profile, const char *url)
261 {
262 return lasso_profile_saml20_build_artifact_msg(profile, url, REQUEST, GET);
263 }
264
265 static gint
lasso_profile_saml20_build_artifact_post_request_msg(LassoProfile * profile,const char * url)266 lasso_profile_saml20_build_artifact_post_request_msg(LassoProfile *profile, const char *url)
267 {
268 return lasso_profile_saml20_build_artifact_msg(profile, url, REQUEST, POST);
269 }
270
271 static gint
lasso_profile_saml20_build_artifact_get_response_msg(LassoProfile * profile,const char * url)272 lasso_profile_saml20_build_artifact_get_response_msg(LassoProfile *profile, const char *url)
273 {
274 return lasso_profile_saml20_build_artifact_msg(profile, url, RESPONSE, GET);
275 }
276
277 static gint
lasso_profile_saml20_build_artifact_post_response_msg(LassoProfile * profile,const char * url)278 lasso_profile_saml20_build_artifact_post_response_msg(LassoProfile *profile, const char *url)
279 {
280 return lasso_profile_saml20_build_artifact_msg(profile, url, RESPONSE, POST);
281 }
282
283 int
lasso_saml20_profile_init_artifact_resolve(LassoProfile * profile,LassoProviderRole remote_provider_role,const char * msg,LassoHttpMethod method)284 lasso_saml20_profile_init_artifact_resolve(LassoProfile *profile,
285 LassoProviderRole remote_provider_role, const char *msg, LassoHttpMethod method)
286 {
287 xmlChar **query_fields;
288 char *artifact_b64 = NULL;
289 xmlChar *provider_succinct_id_b64 = NULL;
290 char *provider_succinct_id[21];
291 char artifact[45];
292 LassoSamlp2RequestAbstract *request = NULL;
293 LassoProvider *remote_provider = NULL;
294 int i = 0;
295 int rc = 0;
296 unsigned short index_endpoint = 0;
297
298 if (method == LASSO_HTTP_METHOD_ARTIFACT_GET) {
299 query_fields = lasso_urlencoded_to_strings(msg);
300 for (i=0; query_fields[i]; i++) {
301 if (strncmp((char*)query_fields[i], LASSO_SAML2_FIELD_ARTIFACT "=", 8) == 0) {
302 lasso_assign_string(artifact_b64, (char*)query_fields[i]+8);
303 }
304 }
305 lasso_release_array_of_xml_strings(query_fields);
306 if (artifact_b64 == NULL) {
307 return LASSO_PROFILE_ERROR_MISSING_ARTIFACT;
308 }
309 } else if (method == LASSO_HTTP_METHOD_ARTIFACT_POST) {
310 artifact_b64 = g_strdup(msg);
311 } else {
312 return critical_error(LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD);
313 }
314
315 i = xmlSecBase64Decode((xmlChar*)artifact_b64, (xmlChar*)artifact, 45);
316 if (i < 0 || i > 44) {
317 lasso_release_string(artifact_b64);
318 return LASSO_PROFILE_ERROR_INVALID_ARTIFACT;
319 }
320
321 if (artifact[0] != 0 || artifact[1] != 4) { /* wrong type code */
322 lasso_release_string(artifact_b64);
323 return LASSO_PROFILE_ERROR_INVALID_ARTIFACT;
324 }
325
326 memcpy(provider_succinct_id, artifact+4, 20);
327 provider_succinct_id[20] = 0;
328
329 provider_succinct_id_b64 = xmlSecBase64Encode((xmlChar*)provider_succinct_id, 20, 0);
330
331 lasso_assign_new_string(profile->remote_providerID, lasso_server_get_providerID_from_hash(
332 profile->server, (char*)provider_succinct_id_b64));
333 lasso_release_xml_string(provider_succinct_id_b64);
334 if (profile->remote_providerID == NULL) {
335 return LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND;
336 }
337
338 /* resolve the resolver url using the endpoint index in the artifact string */
339 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
340 index_endpoint = (artifact[2] << 16) + artifact[3];
341 lasso_assign_string(profile->msg_url, lasso_saml20_provider_get_endpoint_url(remote_provider,
342 remote_provider_role,
343 LASSO_SAML2_METADATA_ELEMENT_ARTIFACT_RESOLUTION_SERVICE, NULL, FALSE,
344 FALSE, index_endpoint));
345 if (! profile->msg_url) {
346 debug("looking for index endpoint %d", index_endpoint);
347 return LASSO_PROFILE_ERROR_ENDPOINT_INDEX_NOT_FOUND;
348 }
349
350
351 lasso_assign_new_gobject(profile->request, lasso_samlp2_artifact_resolve_new());
352 request = LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request);
353 lasso_assign_new_string(LASSO_SAMLP2_ARTIFACT_RESOLVE(request)->Artifact, artifact_b64);
354 request->ID = lasso_build_unique_id(32);
355 lasso_assign_string(request->Version, "2.0");
356 request->Issuer = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
357 LASSO_PROVIDER(profile->server)->ProviderID));
358 request->IssueInstant = lasso_get_current_time();
359
360 lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile,
361 (LassoNode*)request));
362
363 cleanup:
364 return rc;
365 }
366
367 int
lasso_saml20_profile_process_artifact_resolve(LassoProfile * profile,const char * msg)368 lasso_saml20_profile_process_artifact_resolve(LassoProfile *profile, const char *msg)
369 {
370 LassoProvider *remote_provider;
371 int rc = 0;
372 LassoProfileSignatureVerifyHint sig_verify_hint;
373
374 /* FIXME: parse only one time the message, reuse the parsed document for signature
375 * validation */
376 lasso_assign_new_gobject(profile->request, lasso_node_new_from_soap(msg));
377 if (profile->request == NULL) {
378 return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
379 }
380 if (! LASSO_IS_SAMLP2_ARTIFACT_RESOLVE(profile->request)) {
381 return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
382 }
383 lasso_assign_string(profile->private_data->artifact,
384 LASSO_SAMLP2_ARTIFACT_RESOLVE(profile->request)->Artifact);
385
386 sig_verify_hint = lasso_profile_get_signature_verify_hint(profile);
387
388 lasso_assign_string(profile->remote_providerID, LASSO_SAMLP2_REQUEST_ABSTRACT(
389 profile->request)->Issuer->content);
390 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
391
392 goto_cleanup_if_fail_with_rc(remote_provider, LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER);
393
394 if (sig_verify_hint != LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE) {
395 profile->signature_status = lasso_provider_verify_signature(remote_provider, msg, "ID",
396 LASSO_MESSAGE_FORMAT_SOAP);
397 }
398
399 switch (lasso_profile_get_signature_verify_hint(profile)) {
400 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
401 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
402 rc = profile->signature_status;
403 break;
404 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
405 break;
406 default:
407 g_assert(0);
408 break;
409 }
410
411 cleanup:
412 return rc;
413 }
414
415 int
lasso_saml20_profile_build_artifact_response(LassoProfile * profile)416 lasso_saml20_profile_build_artifact_response(LassoProfile *profile)
417 {
418 LassoSamlp2StatusResponse *response = NULL;
419 int rc = 0;
420
421 if ( ! LASSO_IS_SAMLP2_REQUEST_ABSTRACT(profile->request)) {
422 return LASSO_PROFILE_ERROR_MISSING_REQUEST;
423 }
424 /* Setup the response */
425 response = LASSO_SAMLP2_STATUS_RESPONSE(lasso_samlp2_artifact_response_new());
426 lasso_assign_new_gobject(profile->response, response);
427 response->ID = lasso_build_unique_id(32);
428 lasso_assign_string(response->Version, "2.0");
429 response->Issuer = LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
430 LASSO_PROVIDER(profile->server)->ProviderID));
431 response->IssueInstant = lasso_get_current_time();
432 lasso_assign_string(response->InResponseTo, LASSO_SAMLP2_REQUEST_ABSTRACT(profile->request)->ID);
433 /* Add content */
434 if (profile->private_data->artifact_message) {
435 xmlDoc *doc;
436 xmlNode *node;
437 char *content = profile->private_data->artifact_message;
438 doc = lasso_xml_parse_memory(content, strlen(content));
439 if (doc) {
440 node = xmlDocGetRootElement(doc);
441 lasso_assign_new_gobject(LASSO_SAMLP2_ARTIFACT_RESPONSE(response)->any,
442 lasso_misc_text_node_new_with_xml_node(node));
443 lasso_release_doc(doc);
444 lasso_saml20_profile_set_response_status(profile,
445 LASSO_SAML2_STATUS_CODE_SUCCESS, NULL);
446 } else {
447 lasso_saml20_profile_set_response_status(profile,
448 LASSO_SAML2_STATUS_CODE_RESPONDER,
449 LASSO_PRIVATE_STATUS_CODE_FAILED_TO_RESTORE_ARTIFACT);
450 }
451 } else {
452 /* if no artifact is present, it is a success anyway */
453 lasso_saml20_profile_set_response_status(profile,
454 LASSO_SAML2_STATUS_CODE_SUCCESS, NULL);
455 }
456 /* Setup the signature */
457 lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile,
458 (LassoNode*)response));
459 /* Serialize the message */
460 lasso_assign_new_string(profile->msg_body, lasso_node_export_to_soap(profile->response));
461 cleanup:
462 return rc;
463 }
464
465 int
lasso_saml20_profile_process_artifact_response(LassoProfile * profile,const char * msg)466 lasso_saml20_profile_process_artifact_response(LassoProfile *profile, const char *msg)
467 {
468 LassoSamlp2ArtifactResponse *artifact_response;
469 int rc = 0;
470
471 artifact_response = (LassoSamlp2ArtifactResponse*)lasso_samlp2_artifact_response_new();
472 lasso_check_good_rc(lasso_saml20_profile_process_any_response(profile,
473 &artifact_response->parent, NULL, msg));
474 /* XXX: check signature status */
475 goto_cleanup_if_fail_with_rc(profile->response != NULL,
476 critical_error(LASSO_PROFILE_ERROR_INVALID_RESPONSE));
477 if (artifact_response->any == NULL) {
478 rc = LASSO_PROFILE_ERROR_MISSING_RESPONSE;
479 } else {
480 if (LASSO_IS_SAMLP2_REQUEST_ABSTRACT(artifact_response->any)) {
481 lasso_assign_gobject(profile->request, artifact_response->any);
482 } else if (LASSO_IS_SAMLP2_STATUS_RESPONSE(artifact_response->any)) {
483 lasso_assign_gobject(profile->response, artifact_response->any);
484 } else {
485 rc = LASSO_PROFILE_ERROR_INVALID_RESPONSE;
486 }
487 }
488
489 cleanup:
490 lasso_release_gobject(artifact_response);
491 return rc;
492 }
493
494 /**
495 * lasso_saml20_profile_is_saml_query:
496 * @query: HTTP query string
497 *
498 * Tests the query string to know if the URL is called as the result of a
499 * SAML redirect (action initiated elsewhere) or not.
500 *
501 * Return value: TRUE if SAML query, FALSE otherwise
502 **/
503 gboolean
lasso_profile_is_saml_query(const gchar * query)504 lasso_profile_is_saml_query(const gchar *query)
505 {
506 gchar *parameters[] = {
507 LASSO_SAML2_FIELD_REQUEST "=", LASSO_SAML2_FIELD_RESPONSE "=",
508 LASSO_SAML2_FIELD_ARTIFACT "=", NULL };
509 gint i;
510
511 g_return_val_if_fail(query, FALSE);
512 for (i=0; parameters[i]; i++) {
513 if (strstr(query, parameters[i]))
514 return TRUE;
515 }
516
517 return FALSE;
518 }
519
520 static void
lasso_saml20_profile_set_session_from_dump_decrypt(LassoSaml2Assertion * assertion,LassoProfile * profile)521 lasso_saml20_profile_set_session_from_dump_decrypt(
522 LassoSaml2Assertion *assertion, LassoProfile *profile)
523 {
524 if (LASSO_IS_SAML2_ASSERTION(assertion) == FALSE) {
525 return;
526 }
527
528 if (assertion->Subject != NULL && ! assertion->Subject->NameID && assertion->Subject->EncryptedID != NULL) {
529 if (assertion->Subject->EncryptedID->original_data) { /* already decrypted */
530 lasso_assign_gobject(assertion->Subject->NameID,
531 assertion->Subject->EncryptedID->original_data);
532 lasso_release_gobject(assertion->Subject->EncryptedID);
533 } else { /* decrypt */
534 int rc;
535 GList *encryption_private_keys =
536 lasso_server_get_encryption_private_keys(profile->server);
537
538 rc = LASSO_PROFILE_ERROR_MISSING_ENCRYPTION_PRIVATE_KEY;
539 lasso_foreach_full_begin(xmlSecKey*, encryption_private_key, it,
540 encryption_private_keys);
541 {
542 rc = lasso_saml2_encrypted_element_decrypt(
543 assertion->Subject->EncryptedID,
544 encryption_private_key,
545 (LassoNode**)&assertion->Subject->NameID);
546 if (rc == 0)
547 break;
548 }
549 lasso_foreach_full_end();
550
551 if (rc == 0) {
552 lasso_release_gobject(assertion->Subject->EncryptedID);
553 } else {
554 message(G_LOG_LEVEL_WARNING, "Could not decrypt EncrypteID from"
555 " assertion in session dump: %s", lasso_strerror(rc));
556 }
557 }
558 }
559 }
560
561 gint
lasso_saml20_profile_set_session_from_dump(LassoProfile * profile)562 lasso_saml20_profile_set_session_from_dump(LassoProfile *profile)
563 {
564 GList *assertions = NULL;
565
566 lasso_bad_param(PROFILE, profile);
567
568 if (lasso_session_count_assertions(profile->session) > 0) {
569 assertions = lasso_session_get_assertions(profile->session, NULL);
570
571 g_list_foreach(assertions,
572 (GFunc)lasso_saml20_profile_set_session_from_dump_decrypt,
573 profile);
574 lasso_release_list(assertions);
575 }
576
577 return 0;
578 }
579
580 /**
581 * lasso_saml20_profile_process_name_identifier_decryption:
582 * @profile: the #LassoProfile object
583 * @name_id: the field containing the #LassoSaml2NameID object
584 * @encrypted_id: the field containing an encrypted #LassoSaml2NameID as a
585 * #LassoSaml2EncryptedElement
586 *
587 * Place content of the NameID in the profile nameIdentifier field, if no NameID is present but an
588 * EncryptedElement is, then decrypt it, store it in place of the name_id field and in the
589 * nameIdentifier field of the profile.
590 *
591 * Return value: 0 if successful,
592 * LASSO_PROFILE_ERROR_MISSING_NAME_IDENTIFIER if no NameID can be found,
593 * LASSO_PROFILE_ERROR_MISSING_ENCRYPTION_PRIVATE_KEY if an encryption element is present but no no
594 * decryption key.
595 */
596 gint
lasso_saml20_profile_process_name_identifier_decryption(LassoProfile * profile,LassoSaml2NameID ** name_id,LassoSaml2EncryptedElement ** encrypted_id)597 lasso_saml20_profile_process_name_identifier_decryption(LassoProfile *profile,
598 LassoSaml2NameID **name_id,
599 LassoSaml2EncryptedElement **encrypted_id)
600 {
601 int rc = 0;
602
603 lasso_bad_param(PROFILE, profile);
604 lasso_null_param(name_id);
605 lasso_null_param(encrypted_id);
606
607 if (*name_id == NULL && *encrypted_id != NULL) {
608 if (! LASSO_IS_SAML2_ENCRYPTED_ELEMENT(*encrypted_id)) {
609 return LASSO_PROFILE_ERROR_MISSING_NAME_IDENTIFIER;
610 }
611 rc = LASSO_PROFILE_ERROR_MISSING_ENCRYPTION_PRIVATE_KEY;
612 lasso_foreach_full_begin(xmlSecKey*, encryption_private_key, it,
613 lasso_server_get_encryption_private_keys(profile->server));
614 {
615 rc = lasso_saml2_encrypted_element_decrypt(*encrypted_id, encryption_private_key,
616 &profile->nameIdentifier);
617 if (rc == 0)
618 break;
619 }
620 lasso_foreach_full_end();
621
622 if (rc)
623 goto cleanup;
624 if (! LASSO_IS_SAML2_NAME_ID(profile->nameIdentifier)) {
625 rc = LASSO_PROFILE_ERROR_MISSING_NAME_IDENTIFIER;
626 goto cleanup;
627 }
628
629 // swap the node contents
630 lasso_assign_gobject(*name_id, LASSO_SAML2_NAME_ID(profile->nameIdentifier));
631 lasso_release_gobject(*encrypted_id);
632 } else {
633 lasso_assign_gobject(profile->nameIdentifier, (LassoNode*)*name_id);
634 }
635 cleanup:
636 return rc;
637 }
638
639 /*
640 * Request handling functions
641 */
642
643 /**
644 * lasso_saml20_profile_process_any_request:
645 * @profile: a #LassoProfile object
646 * @request_node: a #LassoNode object which will be initialized with the content of @request_msg
647 * @request_msg: a string containing the request message as a SOAP XML message, a query string of
648 * the content of SAMLRequest POST field.
649 *
650 * Parse a request message, initialize the given node object with it, try to extract basic SAML
651 * profile information like the remote_provider_id or the name_id and validate the signature.
652 *
653 * Signature validation status is accessible in profile->signature_status, beware that if signature
654 * validation fails no error code will be returned, you must explicitely verify the
655 * profile->signature_status code.
656 *
657 * Return value: 0 if parsing is successful (even if signature validation fails), and otherwise,
658 * LASSO_PROFILE_ERROR_INVALID_MSG, LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE, *
659 * LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND.
660 */
661 int
lasso_saml20_profile_process_any_request(LassoProfile * profile,LassoNode * request_node,const char * request_msg)662 lasso_saml20_profile_process_any_request(LassoProfile *profile,
663 LassoNode *request_node,
664 const char *request_msg)
665 {
666 int rc = 0;
667 LassoProvider *remote_provider = NULL;
668 LassoSamlp2RequestAbstract *request_abstract = NULL;
669 LassoMessageFormat format;
670 xmlDoc *doc = NULL;
671 xmlNode *content = NULL;
672
673 lasso_bad_param(PROFILE, profile);
674
675 /* reset signature_status */
676 profile->signature_status = 0;
677 format = lasso_node_init_from_message_with_format(request_node,
678 request_msg, LASSO_MESSAGE_FORMAT_UNKNOWN, &doc, &content);
679 if (format <= LASSO_MESSAGE_FORMAT_UNKNOWN) {
680 rc = LASSO_PROFILE_ERROR_INVALID_MSG;
681 goto cleanup;
682 }
683 switch (format) {
684 case LASSO_MESSAGE_FORMAT_BASE64:
685 profile->http_request_method = LASSO_HTTP_METHOD_POST;
686 break;
687 case LASSO_MESSAGE_FORMAT_SOAP:
688 profile->http_request_method = LASSO_HTTP_METHOD_SOAP;
689 break;
690 case LASSO_MESSAGE_FORMAT_QUERY:
691 profile->http_request_method = LASSO_HTTP_METHOD_REDIRECT;
692 break;
693 default:
694 rc = LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE;
695 goto cleanup;
696 }
697 lasso_assign_gobject(profile->request, request_node);
698 if (format == LASSO_MESSAGE_FORMAT_QUERY) {
699 lasso_assign_new_string(profile->msg_relayState,
700 lasso_get_relaystate_from_query(request_msg));
701 }
702
703 lasso_extract_node_or_fail(request_abstract, profile->request, SAMLP2_REQUEST_ABSTRACT,
704 LASSO_PROFILE_ERROR_INVALID_MSG);
705 goto_cleanup_if_fail_with_rc(LASSO_IS_SAML2_NAME_ID(request_abstract->Issuer),
706 LASSO_PROFILE_ERROR_MISSING_ISSUER);
707 lasso_assign_string(profile->remote_providerID, request_abstract->Issuer->content);
708
709 rc = get_provider(profile, &remote_provider);
710 goto_cleanup_if_fail(rc == 0);
711
712 /* verify the signature at the request level */
713 if (content && doc && format != LASSO_MESSAGE_FORMAT_QUERY) {
714 profile->signature_status =
715 lasso_provider_verify_saml_signature(remote_provider, content, doc);
716 } else if (format == LASSO_MESSAGE_FORMAT_QUERY) {
717 profile->signature_status =
718 lasso_provider_verify_query_signature(remote_provider, request_msg);
719 } else {
720 profile->signature_status = LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE;
721 }
722
723 cleanup:
724
725 lasso_release_doc(doc);
726 return rc;
727 }
728
729 int
lasso_saml20_profile_process_soap_request(LassoProfile * profile,const char * request_msg)730 lasso_saml20_profile_process_soap_request(LassoProfile *profile,
731 const char *request_msg)
732 {
733 int rc = 0;
734 LassoSaml2NameID *issuer = NULL;
735 LassoProvider *remote_provider = NULL;
736 LassoSamlp2RequestAbstract *request_abstract = NULL;
737
738 lasso_bad_param(PROFILE, profile);
739
740 profile->signature_status = 0;
741 lasso_assign_new_gobject(profile->request, lasso_node_new_from_soap(request_msg));
742 profile->http_request_method = LASSO_HTTP_METHOD_SOAP;
743 lasso_extract_node_or_fail(request_abstract, profile->request, SAMLP2_REQUEST_ABSTRACT,
744 LASSO_PROFILE_ERROR_INVALID_MSG);
745 lasso_extract_node_or_fail(issuer, request_abstract->Issuer, SAML2_NAME_ID,
746 LASSO_PROFILE_ERROR_MISSING_ISSUER);
747 lasso_assign_string(profile->remote_providerID, issuer->content);
748
749 rc = get_provider(profile, &remote_provider);
750 goto_cleanup_if_fail(rc == 0);
751
752 profile->signature_status = lasso_provider_verify_signature(
753 remote_provider, request_msg, "ID", LASSO_MESSAGE_FORMAT_SOAP);
754
755 switch (lasso_profile_get_signature_verify_hint(profile)) {
756 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
757 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
758 rc = profile->signature_status;
759 break;
760 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
761 break;
762 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_LAST:
763 g_assert_not_reached();
764 break;
765 }
766
767 cleanup:
768 return rc;
769 }
770
771 int
lasso_saml20_profile_init_request(LassoProfile * profile,const char * remote_provider_id,gboolean first_in_session,LassoSamlp2RequestAbstract * request_abstract,LassoHttpMethod http_method,LassoMdProtocolType protocol_type)772 lasso_saml20_profile_init_request(LassoProfile *profile,
773 const char *remote_provider_id,
774 gboolean first_in_session,
775 LassoSamlp2RequestAbstract *request_abstract,
776 LassoHttpMethod http_method,
777 LassoMdProtocolType protocol_type)
778 {
779 LassoServer *server = NULL;
780 LassoSession *session = NULL;
781 LassoProvider *remote_provider = NULL;
782 LassoSaml2NameID *name_id = NULL;
783 char *remote_provider_id_auto = NULL;
784 int rc = 0;
785
786 lasso_bad_param(PROFILE, profile);
787 lasso_bad_param(SAMLP2_REQUEST_ABSTRACT, request_abstract);
788
789 if (http_method != LASSO_HTTP_METHOD_ANY &&
790 http_method != LASSO_HTTP_METHOD_REDIRECT &&
791 http_method != LASSO_HTTP_METHOD_POST &&
792 http_method != LASSO_HTTP_METHOD_ARTIFACT_GET &&
793 http_method != LASSO_HTTP_METHOD_ARTIFACT_POST &&
794 http_method != LASSO_HTTP_METHOD_SOAP &&
795 http_method != LASSO_HTTP_METHOD_PAOS) {
796 return critical_error(LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD);
797 }
798
799 /* verify server and session object */
800 lasso_extract_node_or_fail(server, profile->server, SERVER,
801 LASSO_PROFILE_ERROR_MISSING_SERVER);
802 if (LASSO_IS_SESSION(profile->session)) {
803 session = profile->session;
804 }
805
806 /*
807 * With PAOS the ECP client determines the remote provider.
808 * Everthing in the following block of code depends on
809 * establishing the remote provider and subsequetnly operating
810 * on the remote provider.
811 */
812 if (http_method != LASSO_HTTP_METHOD_PAOS) {
813 /* set remote provider Id */
814 if (! remote_provider_id) {
815 if (first_in_session) {
816 if (! session) {
817 return LASSO_PROFILE_ERROR_SESSION_NOT_FOUND;
818 }
819 remote_provider_id_auto = lasso_session_get_provider_index(session, 0);
820 } else {
821 remote_provider_id_auto = lasso_server_get_first_providerID(server);
822 }
823 }
824 if (! remote_provider_id && ! remote_provider_id_auto) {
825 rc = LASSO_PROFILE_ERROR_CANNOT_FIND_A_PROVIDER;
826 goto cleanup;
827 }
828 if (remote_provider_id) {
829 lasso_assign_string(profile->remote_providerID, remote_provider_id);
830 } else {
831 lasso_assign_new_string(profile->remote_providerID, remote_provider_id_auto);
832 }
833 rc = get_provider(profile, &remote_provider);
834 if (rc)
835 goto cleanup;
836 /* set the name identifier */
837 name_id = (LassoSaml2NameID*)lasso_profile_get_nameIdentifier(profile);
838 if (LASSO_IS_SAML2_NAME_ID(name_id)) {
839 lasso_assign_gobject(profile->nameIdentifier, (LassoNode*)name_id);
840 }
841
842 /* verify that this provider supports the current http method */
843 if (http_method == LASSO_HTTP_METHOD_ANY) {
844 http_method = lasso_saml20_provider_get_first_http_method((LassoProvider*)server,
845 remote_provider, protocol_type);
846 }
847 if (http_method == LASSO_HTTP_METHOD_NONE) {
848 rc = LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE;
849 goto cleanup;
850 }
851 if (! lasso_saml20_provider_accept_http_method(
852 (LassoProvider*)server,
853 remote_provider,
854 protocol_type,
855 http_method,
856 TRUE)) {
857 rc = LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE;
858 }
859 }
860 profile->http_request_method = http_method;
861
862 /* initialize request fields */
863 lasso_assign_new_string(request_abstract->ID, lasso_build_unique_id(32));
864 lasso_assign_string(request_abstract->Version, "2.0");
865 lasso_assign_new_gobject(request_abstract->Issuer,
866 LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
867 LASSO_PROVIDER(profile->server)->ProviderID)));
868 lasso_assign_new_string(request_abstract->IssueInstant, lasso_get_current_time());
869 lasso_assign_gobject(profile->request, LASSO_NODE(request_abstract));
870
871 /* set signature */
872 lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile, profile->request));
873
874 cleanup:
875 return rc;
876 }
877
878 static int
lasso_saml20_profile_build_redirect_request_msg(LassoProfile * profile,const char * url)879 lasso_saml20_profile_build_redirect_request_msg(LassoProfile *profile, const char *url)
880 {
881 return lasso_saml20_profile_build_http_redirect(profile,
882 profile->request,
883 url);
884 }
885
886 static int
lasso_saml20_profile_build_post_request_msg(LassoProfile * profile,const char * url)887 lasso_saml20_profile_build_post_request_msg(LassoProfile *profile,
888 const char *url)
889 {
890 lasso_assign_string(profile->msg_url, url);
891 lasso_assign_new_string(profile->msg_body,
892 lasso_node_export_to_base64(profile->request));
893 check_msg_body;
894 return 0;
895 }
896
897 static int
lasso_saml20_profile_build_soap_request_msg(LassoProfile * profile,const char * url)898 lasso_saml20_profile_build_soap_request_msg(LassoProfile *profile, const char *url)
899 {
900 lasso_assign_string(profile->msg_url, url);
901 lasso_assign_new_string(profile->msg_body,
902 lasso_node_export_to_soap(profile->request));
903 check_msg_body;
904 return 0;
905 }
906
907 /*
908 * the url parameters is special for this function, it does not give the destination of the message
909 * (it's implicit for the caller of this function) but where response should be posted later).
910 */
911 static int
lasso_profile_saml20_build_paos_request_msg(LassoProfile * profile,const char * url)912 lasso_profile_saml20_build_paos_request_msg(LassoProfile *profile, const char *url)
913 {
914 int rc = 0;
915 LassoSamlp2AuthnRequest *request;
916 LassoSamlp2IDPList *idp_list = NULL;
917 char *message_id = NULL;
918
919 lasso_extract_node_or_fail(request, profile->request, SAMLP2_AUTHN_REQUEST,
920 LASSO_PROFILE_ERROR_MISSING_REQUEST);
921
922 if (lasso_profile_get_idp_list(profile)) {
923 lasso_extract_node_or_fail(idp_list,
924 lasso_profile_get_idp_list(profile),
925 SAMLP2_IDP_LIST,
926 LASSO_PROFILE_ERROR_INVALID_IDP_LIST);
927 }
928
929 message_id = lasso_profile_get_message_id(profile);
930
931 lasso_assign_new_string(profile->msg_body,
932 lasso_node_export_to_paos_request_full(profile->request,
933 profile->server->parent.ProviderID, url,
934 message_id,
935 profile->msg_relayState,
936 request->IsPassive, request->ProviderName,
937 idp_list));
938
939 check_msg_body;
940
941 cleanup:
942 lasso_release_string(message_id);
943 return rc;
944 }
945
946 int
lasso_saml20_profile_build_request_msg(LassoProfile * profile,const char * service,LassoHttpMethod method,const char * _url)947 lasso_saml20_profile_build_request_msg(LassoProfile *profile, const char *service,
948 LassoHttpMethod method, const char *_url)
949 {
950 char *made_url = NULL, *url;
951 int rc = 0;
952
953 lasso_bad_param(PROFILE, profile);
954
955 lasso_profile_clean_msg_info(profile);
956 url = (char*)_url;
957
958 /* check presence of a request */
959 if (! LASSO_IS_SAMLP2_REQUEST_ABSTRACT(profile->request)) {
960 return critical_error(LASSO_PROFILE_ERROR_MISSING_REQUEST);
961 }
962
963 /* if not explicitely given, automatically determine an URI from the metadatas */
964 if (url == NULL) {
965 LassoProvider *provider;
966
967 lasso_check_good_rc(get_provider(profile, &provider));
968 made_url = url = get_url(provider, service, http_method_to_binding(method));
969 }
970
971
972 // Usage of the Destination attribute on a request is mandated only
973 // in "3.4.5.2" and "3.5.5.2" in saml-bindings-2.0-os for signed requests
974 // and is marked as optional in the XSD schema otherwise.
975 // PAOS is a special case because an SP does not select an IdP - ECP does
976 // it instead. Therefore, this attribute needs to be left unpopulated.
977 if (method == LASSO_HTTP_METHOD_PAOS) {
978 lasso_release_string(((LassoSamlp2RequestAbstract*)profile->request)->Destination);
979 } else if (url) {
980 lasso_assign_string(((LassoSamlp2RequestAbstract*)profile->request)->Destination,
981 url);
982 } else {
983 rc = LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL;
984 goto cleanup;
985 }
986
987 switch (method) {
988 case LASSO_HTTP_METHOD_SOAP:
989 rc = lasso_saml20_profile_build_soap_request_msg(profile, url);
990 break;
991 case LASSO_HTTP_METHOD_POST:
992 rc = lasso_saml20_profile_build_post_request_msg(profile, url);
993 break;
994 case LASSO_HTTP_METHOD_REDIRECT:
995 rc = lasso_saml20_profile_build_redirect_request_msg(profile, url);
996 break;
997 case LASSO_HTTP_METHOD_ARTIFACT_GET:
998 rc = lasso_profile_saml20_build_artifact_get_request_msg(profile, url);
999 break;
1000 case LASSO_HTTP_METHOD_ARTIFACT_POST:
1001 rc = lasso_profile_saml20_build_artifact_post_request_msg(profile, url);
1002 break;
1003 case LASSO_HTTP_METHOD_PAOS:
1004 rc = lasso_profile_saml20_build_paos_request_msg(profile, url);
1005 break;
1006 default:
1007 rc = LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD;
1008 break;
1009 }
1010
1011 cleanup:
1012 lasso_release_string(made_url);
1013 return rc;
1014
1015 }
1016
1017 /*
1018 * Response handling functions
1019 */
1020
1021 int
lasso_saml20_profile_set_response_status(LassoProfile * profile,const char * code1,const char * code2)1022 lasso_saml20_profile_set_response_status(LassoProfile *profile,
1023 const char *code1, const char *code2)
1024 {
1025 LassoSamlp2StatusResponse *status_response = NULL;
1026 LassoSamlp2Status *status = NULL;
1027 LassoSamlp2StatusCode *status_code1 = NULL;
1028 LassoSamlp2StatusCode *status_code2 = NULL;
1029 int rc = 0;
1030
1031 lasso_bad_param(PROFILE, profile);
1032 lasso_null_param(code1);
1033 lasso_extract_node_or_fail(status_response, profile->response, SAMLP2_STATUS_RESPONSE,
1034 LASSO_PROFILE_ERROR_MISSING_RESPONSE);
1035
1036 if (! LASSO_IS_SAMLP2_STATUS(status_response->Status)) {
1037 lasso_assign_new_gobject(status_response->Status,
1038 (LassoSamlp2Status*)lasso_samlp2_status_new());
1039 }
1040 status = status_response->Status;
1041 if (! LASSO_IS_SAMLP2_STATUS_CODE(status->StatusCode)) {
1042 lasso_assign_new_gobject(status->StatusCode,
1043 (LassoSamlp2StatusCode*)lasso_samlp2_status_code_new());
1044 }
1045 status_code1 = status->StatusCode;
1046 lasso_assign_string(status_code1->Value, code1);
1047
1048 if (code2) {
1049 if (! LASSO_IS_SAMLP2_STATUS_CODE(status_code1->StatusCode)) {
1050 lasso_assign_new_gobject(status_code1->StatusCode,
1051 (LassoSamlp2StatusCode*)lasso_samlp2_status_code_new());
1052 }
1053 status_code2 = status_code1->StatusCode;
1054 lasso_assign_string(status_code2->Value, code2);
1055 }
1056
1057 cleanup:
1058 return rc;
1059 }
1060
1061
1062 int
lasso_saml20_profile_init_response(LassoProfile * profile,LassoSamlp2StatusResponse * status_response,const char * status_code1,const char * status_code2)1063 lasso_saml20_profile_init_response(LassoProfile *profile, LassoSamlp2StatusResponse *status_response,
1064 const char *status_code1, const char *status_code2)
1065 {
1066 int rc = 0;
1067
1068 lasso_bad_param(PROFILE, profile);
1069 if (! LASSO_IS_SAMLP2_STATUS_RESPONSE(status_response))
1070 return LASSO_PROFILE_ERROR_MISSING_RESPONSE;
1071 lasso_assign_gobject(profile->response, status_response);
1072
1073 lasso_assign_new_string(status_response->ID, lasso_build_unique_id(32));
1074 lasso_assign_string(status_response->Version, "2.0");
1075 if (LASSO_IS_SERVER(profile->server)) {
1076 lasso_assign_new_gobject(status_response->Issuer,
1077 LASSO_SAML2_NAME_ID(lasso_saml2_name_id_new_with_string(
1078 profile->server->parent.ProviderID)));
1079 }
1080 lasso_assign_new_string(status_response->IssueInstant, lasso_get_current_time());
1081 if (LASSO_IS_SAMLP2_REQUEST_ABSTRACT(profile->request)) {
1082 lasso_assign_string(status_response->InResponseTo,
1083 ((LassoSamlp2RequestAbstract*)profile->request)->ID);
1084 }
1085 lasso_check_good_rc(lasso_profile_saml20_setup_message_signature(profile,
1086 profile->response));
1087 if (status_code1) {
1088 lasso_saml20_profile_set_response_status(profile,
1089 status_code1, status_code2);
1090 }
1091
1092 cleanup:
1093 return rc;
1094 }
1095
1096 int
lasso_saml20_profile_validate_request(LassoProfile * profile,gboolean needs_identity,LassoSamlp2StatusResponse * status_response,LassoProvider ** provider_out)1097 lasso_saml20_profile_validate_request(LassoProfile *profile, gboolean needs_identity,
1098 LassoSamlp2StatusResponse *status_response, LassoProvider **provider_out)
1099 {
1100 int rc = 0;
1101 LassoSamlp2RequestAbstract *request_abstract = NULL;
1102 LassoSaml2NameID *issuer = NULL;
1103 LassoProvider *provider = NULL;
1104
1105 lasso_bad_param(PROFILE, profile);
1106 lasso_bad_param(SAMLP2_STATUS_RESPONSE, status_response);
1107 /* verify request presence */
1108 lasso_extract_node_or_fail(request_abstract, profile->request, SAMLP2_REQUEST_ABSTRACT,
1109 LASSO_PROFILE_ERROR_MISSING_REQUEST);
1110 /* look for identity object */
1111 if (needs_identity) {
1112 goto_cleanup_if_fail_with_rc(LASSO_IS_IDENTITY(profile->identity),
1113 LASSO_PROFILE_ERROR_IDENTITY_NOT_FOUND);
1114 }
1115
1116 /* extract provider */
1117 lasso_extract_node_or_fail(issuer, request_abstract->Issuer, SAML2_NAME_ID,
1118 LASSO_PROFILE_ERROR_MISSING_ISSUER);
1119 lasso_assign_string(profile->remote_providerID, issuer->content);
1120 rc = get_provider(profile, &provider);
1121 if (rc)
1122 goto cleanup;
1123
1124 /* init the response */
1125 lasso_saml20_profile_init_response(profile, status_response,
1126 LASSO_SAML2_STATUS_CODE_SUCCESS, NULL);
1127
1128 switch (lasso_profile_get_signature_verify_hint(profile)) {
1129 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
1130 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
1131 if (profile->signature_status) {
1132 lasso_saml20_profile_set_response_status(profile,
1133 LASSO_SAML2_STATUS_CODE_REQUESTER,
1134 LASSO_LIB_STATUS_CODE_INVALID_SIGNATURE);
1135 return profile->signature_status;
1136 }
1137 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
1138 break;
1139 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_LAST:
1140 g_assert_not_reached();
1141 }
1142
1143 cleanup:
1144 if (provider && provider_out)
1145 *provider_out = provider;
1146 return rc;
1147
1148 }
1149
1150 /**
1151 * lasso_saml20_profile_export_to_query:
1152 * @profile: a #LassoProfile
1153 * @msg: a #LassoNode to export as a query
1154 * @query: an ouput variable to store the result
1155 * @signature_method: the signature method for signing the query
1156 * @private_key_file:(allow-none): the private key to eventually sign the query
1157 * @private_key_password:(allow-none): the password of the private key if there is one
1158 *
1159 * Create a query following the DEFLATE encoding of the SAML 2.0 HTTP
1160 * Redirect binding. If the root message node has an XML signature, signature is removed and query
1161 * is signed.
1162 *
1163 * Return value: 0 if successful, an error code otherwise.
1164 */
1165 static int
lasso_saml20_profile_export_to_query(LassoProfile * profile,LassoNode * msg,char ** query,LassoSignatureContext context)1166 lasso_saml20_profile_export_to_query(LassoProfile *profile, LassoNode *msg, char **query,
1167 LassoSignatureContext context) {
1168 char *unsigned_query = NULL;
1169 char *result = NULL;
1170 int rc = 0;
1171
1172 unsigned_query = lasso_node_build_query(msg);
1173 goto_cleanup_if_fail_with_rc(unsigned_query != NULL,
1174 LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED);
1175 if (profile->msg_relayState) {
1176 unsigned_query = lasso_url_add_parameters(unsigned_query, 1, "RelayState",
1177 profile->msg_relayState, NULL);
1178
1179 if (strlen(profile->msg_relayState) > 80) {
1180 message(G_LOG_LEVEL_WARNING, "Encoded a RelayState of more than 80 bytes, "
1181 "see #3.4.3 of saml-bindings-2.0-os");
1182 }
1183 }
1184 if (lasso_validate_signature_method(context.signature_method)) {
1185 result = lasso_query_sign(unsigned_query, context);
1186 goto_cleanup_if_fail_with_rc(result != NULL,
1187 LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED);
1188 lasso_transfer_string(*query, result);
1189 } else {
1190 lasso_transfer_string(*query, unsigned_query);
1191 }
1192 cleanup:
1193 lasso_release_string(unsigned_query);
1194 lasso_release_string(result);
1195 return rc;
1196 }
1197
1198 /**
1199 * lasso_saml20_profile_build_http_redirect:
1200 * @profile: a #LassoProfile object
1201 * @msg: a #LassoNode object representing a SAML 2.0 message
1202 * @must_sign: wheter to sign the query message using query signatures
1203 * @url: the URL where the query is targeted
1204 *
1205 * Build an HTTP URL with a query-string following the SAML 2.0 HTTP-Redirect binding rules,
1206 * eventually sign it. Any signature at the message level is removed.
1207 *
1208 * Return value: 0 if successful, an error code otherwise.
1209 */
1210 gint
lasso_saml20_profile_build_http_redirect(LassoProfile * profile,LassoNode * msg,const char * url)1211 lasso_saml20_profile_build_http_redirect(LassoProfile *profile,
1212 LassoNode *msg,
1213 const char *url)
1214 {
1215 char *query = NULL;
1216 int rc = 0;
1217 LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE;
1218
1219 goto_cleanup_if_fail_with_rc (url != NULL, LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL);
1220 /* if message is signed, remove XML signature, add query signature */
1221 lasso_assign_signature_context(context, lasso_node_get_signature(msg));
1222 if (lasso_validate_signature_method(context.signature_method)) {
1223 lasso_node_remove_signature(msg);
1224 }
1225 lasso_check_good_rc(lasso_saml20_profile_export_to_query(profile, msg, &query, context));
1226
1227 lasso_assign_new_string(profile->msg_url, lasso_concat_url_query(url, query));
1228 lasso_release(profile->msg_body);
1229 lasso_release(query);
1230 lasso_assign_new_signature_context(context, LASSO_SIGNATURE_CONTEXT_NONE);
1231
1232 cleanup:
1233 return rc;
1234 }
1235
1236 static int
lasso_saml20_profile_build_redirect_response_msg(LassoProfile * profile,const char * url)1237 lasso_saml20_profile_build_redirect_response_msg(LassoProfile *profile, const char *url)
1238 {
1239 return lasso_saml20_profile_build_http_redirect(profile,
1240 profile->response,
1241 url);
1242 }
1243
1244 static int
lasso_saml20_profile_build_post_response_msg(LassoProfile * profile,const char * url)1245 lasso_saml20_profile_build_post_response_msg(LassoProfile *profile, const char *url)
1246 {
1247 lasso_assign_string(profile->msg_url, url);
1248 lasso_assign_new_string(profile->msg_body, lasso_node_export_to_base64(profile->response));
1249 check_msg_body;
1250 return 0;
1251 }
1252
1253 static int
lasso_saml20_profile_build_soap_response_msg(LassoProfile * profile)1254 lasso_saml20_profile_build_soap_response_msg(LassoProfile *profile)
1255 {
1256 lasso_release_string(profile->msg_url);
1257 lasso_assign_new_string(profile->msg_body, lasso_node_export_to_soap(profile->response));
1258 check_msg_body;
1259 return 0;
1260 }
1261
1262
1263 int
lasso_saml20_profile_build_response_msg(LassoProfile * profile,char * service,LassoHttpMethod method,const char * _url)1264 lasso_saml20_profile_build_response_msg(LassoProfile *profile, char *service,
1265 LassoHttpMethod method, const char *_url)
1266 {
1267 LassoProvider *provider;
1268 char *made_url = NULL, *url;
1269 int rc = 0;
1270
1271 lasso_bad_param(PROFILE, profile);
1272
1273 lasso_profile_clean_msg_info(profile);
1274 lasso_check_good_rc(get_provider(profile, &provider));
1275 url = (char*)_url;
1276
1277 /* check presence of a request */
1278 if (! LASSO_IS_SAMLP2_STATUS_RESPONSE(profile->response)) {
1279 return critical_error(LASSO_PROFILE_ERROR_MISSING_RESPONSE);
1280 }
1281
1282 /* if not explicitely given, automatically determine an URI from the metadatas */
1283 if (url == NULL && service && method != LASSO_HTTP_METHOD_SOAP) {
1284 made_url = url = get_response_url(provider, service, http_method_to_binding(method));
1285 }
1286
1287 /* only asynchronous bindings needs an URL for the response, SOAP does not need it, and PAOS
1288 * is special (response is a SOAP request !?! ) */
1289 if (! url) {
1290 switch (method) {
1291 case LASSO_HTTP_METHOD_POST:
1292 case LASSO_HTTP_METHOD_REDIRECT:
1293 case LASSO_HTTP_METHOD_ARTIFACT_GET:
1294 case LASSO_HTTP_METHOD_ARTIFACT_POST:
1295 case LASSO_HTTP_METHOD_PAOS:
1296 goto_cleanup_with_rc(critical_error(LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL));
1297 default:
1298 break;
1299 }
1300 }
1301
1302 if (url) {
1303 lasso_assign_string(((LassoSamlp2StatusResponse*)profile->response)->Destination,
1304 url);
1305 }
1306
1307 switch (method) {
1308 case LASSO_HTTP_METHOD_POST:
1309 rc = lasso_saml20_profile_build_post_response_msg(profile, url);
1310 break;
1311 case LASSO_HTTP_METHOD_REDIRECT:
1312 rc = lasso_saml20_profile_build_redirect_response_msg(profile, url);
1313 break;
1314 case LASSO_HTTP_METHOD_SOAP:
1315 rc = lasso_saml20_profile_build_soap_response_msg(profile);
1316 break;
1317 case LASSO_HTTP_METHOD_ARTIFACT_GET:
1318 rc = lasso_profile_saml20_build_artifact_get_response_msg(profile, url);
1319 break;
1320 case LASSO_HTTP_METHOD_ARTIFACT_POST:
1321 rc = lasso_profile_saml20_build_artifact_post_response_msg(profile, url);
1322 break;
1323 default:
1324 rc= LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE;
1325 break;
1326 }
1327
1328 cleanup:
1329 lasso_release_string(made_url);
1330 return rc;
1331 }
1332
1333 static gboolean
_lasso_saml20_is_valid_issuer(LassoSaml2NameID * name_id)1334 _lasso_saml20_is_valid_issuer(LassoSaml2NameID *name_id) {
1335 if (! LASSO_IS_SAML2_NAME_ID(name_id))
1336 return FALSE;
1337
1338 if (name_id->Format &&
1339 lasso_strisnotequal(name_id->Format,LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENTITY))
1340 {
1341 return FALSE;
1342 }
1343 return TRUE;
1344 }
1345
1346 /**
1347 * lasso_saml20_profile_process_any_response:
1348 * @profile: the SAML 2.0 #LassoProfile object
1349 * @status_response: the prototype for the response object
1350 * @response_msg: the content of the response message
1351 *
1352 * Generic method for SAML 2.0 protocol message handling.
1353 *
1354 * It tries to validate a signature on the response msg, the result of this operation is kept inside
1355 * profile->signature_status. Use it afterward in your specific profile. Beware that it does not
1356 * return an error code if signature validation failed. It let's specific profile accept unsigned
1357 * messages.
1358 *
1359 * Return value: 0 if successful, an error code otherwise.
1360 */
1361 int
lasso_saml20_profile_process_any_response(LassoProfile * profile,LassoSamlp2StatusResponse * status_response,LassoHttpMethod * response_method,const char * response_msg)1362 lasso_saml20_profile_process_any_response(LassoProfile *profile,
1363 LassoSamlp2StatusResponse *status_response,
1364 LassoHttpMethod *response_method,
1365 const char *response_msg)
1366 {
1367 int rc = 0;
1368 LassoProvider *remote_provider = NULL;
1369 LassoServer *server = NULL;
1370 LassoSamlp2StatusResponse *response_abstract = NULL;
1371 LassoSamlp2Status *status = NULL;
1372 LassoSamlp2StatusCode *status_code1 = NULL;
1373 LassoMessageFormat format;
1374 gboolean missing_issuer = FALSE;
1375
1376 xmlDoc *doc = NULL;
1377 xmlNode *content = NULL;
1378
1379 lasso_bad_param(PROFILE, profile);
1380 lasso_bad_param(SAMLP2_STATUS_RESPONSE, status_response);
1381
1382 /* reset signature_status */
1383 profile->signature_status = 0;
1384 format = lasso_node_init_from_message_with_format((LassoNode*)status_response,
1385 response_msg, LASSO_MESSAGE_FORMAT_UNKNOWN, &doc, &content);
1386 if (format <= LASSO_MESSAGE_FORMAT_UNKNOWN) {
1387 rc = LASSO_PROFILE_ERROR_INVALID_MSG;
1388 goto cleanup;
1389 }
1390 if (response_method) {
1391 switch (format) {
1392 case LASSO_MESSAGE_FORMAT_SOAP:
1393 *response_method = LASSO_HTTP_METHOD_SOAP;
1394 break;
1395 case LASSO_MESSAGE_FORMAT_QUERY:
1396 *response_method = LASSO_HTTP_METHOD_REDIRECT;
1397 break;
1398 case LASSO_MESSAGE_FORMAT_BASE64:
1399 *response_method = LASSO_HTTP_METHOD_POST;
1400 break;
1401 default:
1402 return LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE;
1403 }
1404 }
1405 lasso_assign_gobject(profile->response, (LassoNode*)status_response);
1406 lasso_extract_node_or_fail(response_abstract, profile->response, SAMLP2_STATUS_RESPONSE,
1407 LASSO_PROFILE_ERROR_INVALID_MSG);
1408 lasso_extract_node_or_fail(server, profile->server, SERVER,
1409 LASSO_PROFILE_ERROR_MISSING_SERVER);
1410 if (_lasso_saml20_is_valid_issuer(response_abstract->Issuer)) {
1411 lasso_assign_string(profile->remote_providerID, response_abstract->Issuer->content);
1412 remote_provider = lasso_server_get_provider(server, profile->remote_providerID);
1413 } else {
1414 missing_issuer = TRUE;
1415 }
1416
1417 if (remote_provider) {
1418 /* verify the signature at the message level */
1419 if (content && doc && format != LASSO_MESSAGE_FORMAT_QUERY) {
1420 profile->signature_status =
1421 lasso_provider_verify_saml_signature(remote_provider, content, doc);
1422 } else if (format == LASSO_MESSAGE_FORMAT_QUERY) {
1423 profile->signature_status =
1424 lasso_provider_verify_query_signature(remote_provider, response_msg);
1425 } else {
1426 profile->signature_status = LASSO_DS_ERROR_SIGNATURE_VERIFICATION_FAILED;
1427 }
1428 } else {
1429 rc = LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND;
1430 profile->signature_status = LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND;
1431 goto cleanup;
1432 }
1433
1434 /* verify status code */
1435 lasso_extract_node_or_fail(status, status_response->Status, SAMLP2_STATUS,
1436 LASSO_PROFILE_ERROR_MISSING_STATUS_CODE);
1437 lasso_extract_node_or_fail(status_code1, status->StatusCode, SAMLP2_STATUS_CODE,
1438 LASSO_PROFILE_ERROR_MISSING_STATUS_CODE);
1439 if (lasso_strisnotequal(status_code1->Value,LASSO_SAML2_STATUS_CODE_SUCCESS))
1440 {
1441 LassoSamlp2StatusCode *status_code2 = status_code1->StatusCode;
1442 rc = LASSO_PROFILE_ERROR_STATUS_NOT_SUCCESS;
1443
1444 if (!status_code2)
1445 goto cleanup;
1446
1447 if (!status_code2->Value)
1448 goto cleanup;
1449 /* FIXME: what to do with secondary status code ? */
1450 if (lasso_strisequal(status_code2->Value, LASSO_SAML2_STATUS_CODE_REQUEST_DENIED)) {
1451 rc = LASSO_PROFILE_ERROR_REQUEST_DENIED;
1452 }
1453 }
1454
1455 cleanup:
1456 lasso_release_doc(doc);
1457 if (rc) {
1458 return rc;
1459 }
1460 switch (lasso_profile_get_signature_verify_hint(profile)) {
1461 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
1462 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
1463 if (profile->signature_status) {
1464 return LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE;
1465 }
1466 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
1467 break;
1468 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_LAST:
1469 g_assert_not_reached();
1470 }
1471 if (missing_issuer) {
1472 return LASSO_PROFILE_ERROR_MISSING_ISSUER;
1473 }
1474 return 0;
1475 }
1476
1477 /**
1478 * lasso_saml20_profile_process_soap_response:
1479 *
1480 * Generic method for processing SAML 2.0 protocol message as a SOAP response.
1481 *
1482 * Return value: 0 if successful; an error code otherwise.
1483 */
1484 int
lasso_saml20_profile_process_soap_response(LassoProfile * profile,const char * response_msg)1485 lasso_saml20_profile_process_soap_response(LassoProfile *profile,
1486 const char *response_msg)
1487 {
1488 return lasso_saml20_profile_process_soap_response_with_headers(
1489 profile, response_msg, NULL);
1490 }
1491
1492 /**
1493 * lasso_saml20_profile_process_soap_response_with_headers:
1494 * @profile: the SAML 2.0 #LassoProfile object
1495 * @response_msg: xml response message
1496 * @header_return: If non-NULL the soap headers are returned at this
1497 * pointer as a #LassoSoapHeader object.
1498 *
1499 * Generic method for processing SAML 2.0 protocol message as a SOAP response.
1500 * The SOAP headers are returned via the header_return parameter
1501 * if the parameter is non-NULL. The caller is responsible for freeing
1502 * the SOAP header by calling lasso_release_gobject().
1503 *
1504 * Return value: 0 if successful; an error code otherwise.
1505 */
1506 int
lasso_saml20_profile_process_soap_response_with_headers(LassoProfile * profile,const char * response_msg,LassoSoapHeader ** header_return)1507 lasso_saml20_profile_process_soap_response_with_headers(LassoProfile *profile,
1508 const char *response_msg, LassoSoapHeader **header_return)
1509 {
1510 int rc = 0;
1511 LassoSoapEnvelope *envelope = NULL;
1512 LassoSoapHeader *header = NULL;
1513 LassoSoapBody *body = NULL;
1514 LassoSaml2NameID *issuer = NULL;
1515 LassoProvider *remote_provider = NULL;
1516 LassoServer *server = NULL;
1517 LassoSamlp2StatusResponse *response_abstract = NULL;
1518
1519 lasso_bad_param(PROFILE, profile);
1520 lasso_null_param(response_msg);
1521 if (header_return) {
1522 *header_return = NULL;
1523 }
1524
1525 profile->signature_status = 0;
1526
1527 /* Get the SOAP envelope */
1528 lasso_extract_node_or_fail(envelope, lasso_soap_envelope_new_from_message(response_msg),
1529 SOAP_ENVELOPE, LASSO_PROFILE_ERROR_INVALID_SOAP_MSG);
1530
1531 /* Get and validate the SOAP body, assign it to the profile response */
1532 lasso_extract_node_or_fail(body, envelope->Body, SOAP_BODY,
1533 LASSO_SOAP_ERROR_MISSING_BODY);
1534 if (body->any && LASSO_IS_NODE(body->any->data)) {
1535 lasso_assign_gobject(profile->response, body->any->data);
1536 } else {
1537 lasso_release_gobject(profile->response);
1538 goto_cleanup_with_rc(LASSO_SOAP_ERROR_MISSING_BODY);
1539 }
1540
1541 /* Get the optional SOAP header, validate it, optionally return it */
1542 if (envelope->Header) {
1543 lasso_extract_node_or_fail(header, envelope->Header, SOAP_HEADER,
1544 LASSO_PROFILE_ERROR_INVALID_SOAP_MSG);
1545 }
1546 if (header_return) {
1547 if (header) {
1548 lasso_assign_gobject(*header_return, header);
1549 }
1550 }
1551
1552 /* Extract and validate the response data */
1553 lasso_extract_node_or_fail(response_abstract, profile->response, SAMLP2_STATUS_RESPONSE,
1554 LASSO_PROFILE_ERROR_INVALID_MSG);
1555 lasso_extract_node_or_fail(server, profile->server, SERVER,
1556 LASSO_PROFILE_ERROR_MISSING_SERVER);
1557 lasso_extract_node_or_fail(issuer, response_abstract->Issuer, SAML2_NAME_ID,
1558 LASSO_PROFILE_ERROR_MISSING_ISSUER);
1559 lasso_assign_string(profile->remote_providerID, issuer->content);
1560
1561 remote_provider = lasso_server_get_provider(server, profile->remote_providerID);
1562 if (remote_provider == NULL) {
1563 rc = LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND;
1564 goto cleanup;
1565 }
1566
1567 profile->signature_status = lasso_provider_verify_signature(
1568 remote_provider, response_msg, "ID", LASSO_MESSAGE_FORMAT_SOAP);
1569 switch (lasso_profile_get_signature_verify_hint(profile)) {
1570 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
1571 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
1572 rc = profile->signature_status;
1573 break;
1574 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
1575 break;
1576 default:
1577 g_assert(0);
1578 break;
1579 }
1580
1581 cleanup:
1582 lasso_release_gobject(envelope);
1583 return rc;
1584 }
1585
1586 gint
lasso_saml20_profile_build_http_redirect_query_simple(LassoProfile * profile,LassoNode * msg,const char * profile_name,gboolean is_response)1587 lasso_saml20_profile_build_http_redirect_query_simple(LassoProfile *profile,
1588 LassoNode *msg,
1589 const char *profile_name,
1590 gboolean is_response)
1591 {
1592 char *idx = NULL;
1593 char *url = NULL;
1594 LassoProvider *remote_provider = NULL;
1595 int rc = 0;
1596
1597
1598 goto_cleanup_if_fail_with_rc(profile->remote_providerID != NULL,
1599 LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID);
1600 remote_provider = lasso_server_get_provider(profile->server,
1601 profile->remote_providerID);
1602 goto_cleanup_if_fail_with_rc(LASSO_IS_PROVIDER(remote_provider),
1603 LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
1604 if (is_response) {
1605 idx = g_strdup_printf("%s HTTP-Redirect ResponseLocation", profile_name);
1606 url = lasso_provider_get_metadata_one(remote_provider, idx);
1607 lasso_release(idx);
1608 }
1609 if (url == NULL) {
1610 idx = g_strdup_printf("%s HTTP-Redirect", profile_name);
1611 url = lasso_provider_get_metadata_one(remote_provider, idx);
1612 lasso_release(idx);
1613 }
1614 /* remove signature at the message level */
1615 rc = lasso_saml20_profile_build_http_redirect(profile, msg, url);
1616 cleanup:
1617 lasso_release(url);
1618 return rc;
1619 }
1620
1621 gint
lasso_profile_saml20_setup_message_signature(LassoProfile * profile,LassoNode * request_or_response)1622 lasso_profile_saml20_setup_message_signature(LassoProfile *profile, LassoNode *request_or_response)
1623 {
1624 lasso_bad_param(PROFILE, profile);
1625 LassoSignatureContext context = LASSO_SIGNATURE_CONTEXT_NONE;
1626 lasso_error_t rc = 0;
1627
1628 switch (lasso_profile_get_signature_hint(profile)) {
1629 case LASSO_PROFILE_SIGNATURE_HINT_MAYBE:
1630 if (! lasso_flag_sign_messages) {
1631 message(G_LOG_LEVEL_WARNING, "message should be signed but no-sign-messages flag is " \
1632 "activated, so it won't be");
1633 return 0;
1634 }
1635 break;
1636 case LASSO_PROFILE_SIGNATURE_HINT_FORBID:
1637 return 0;
1638 default:
1639 break;
1640 }
1641
1642 if (! LASSO_IS_SERVER(profile->server)) {
1643 return LASSO_PROFILE_ERROR_MISSING_SERVER;
1644 }
1645 lasso_check_good_rc(lasso_server_get_signature_context_for_provider_by_name(profile->server,
1646 profile->remote_providerID, &context));
1647 lasso_check_good_rc(lasso_node_set_signature(request_or_response, context));
1648 cleanup:
1649 return rc;
1650 }
1651
1652 /**
1653 * lasso_saml20_profile_setup_subject:
1654 * @profile: a #LassoProfile object
1655 * @subject: a #LassoSaml2Subject object
1656 *
1657 * Encrypt subject if necessary.
1658 */
1659 int
lasso_saml20_profile_setup_subject(LassoProfile * profile,LassoSaml2Subject * subject)1660 lasso_saml20_profile_setup_subject(LassoProfile *profile,
1661 LassoSaml2Subject *subject)
1662 {
1663 LassoProvider *remote_provider;
1664
1665 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
1666 g_return_val_if_fail (LASSO_IS_PROVIDER(remote_provider), LASSO_ERROR_CAST_FAILED);
1667 if (! (lasso_provider_get_encryption_mode(remote_provider) & LASSO_ENCRYPTION_MODE_NAMEID)) {
1668 return 0;
1669 }
1670 return lasso_saml20_profile_setup_encrypted_node(remote_provider,
1671 (LassoNode**)subject->NameID,
1672 (LassoNode**)subject->EncryptedID);
1673 }
1674
1675 gint
lasso_saml20_profile_setup_encrypted_node(LassoProvider * provider,LassoNode ** node_to_encrypt,LassoNode ** node_destination)1676 lasso_saml20_profile_setup_encrypted_node(LassoProvider *provider,
1677 LassoNode **node_to_encrypt, LassoNode **node_destination)
1678 {
1679 LassoNode *encrypted_node;
1680
1681 if (! LASSO_IS_PROVIDER(provider)) {
1682 return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
1683 }
1684 encrypted_node = (LassoNode*)lasso_node_encrypt(*node_to_encrypt,
1685 lasso_provider_get_encryption_public_key(provider),
1686 lasso_provider_get_encryption_sym_key_type(provider),
1687 provider->ProviderID);
1688 if (! encrypted_node) {
1689 return LASSO_DS_ERROR_ENCRYPTION_FAILED;
1690 }
1691 lasso_assign_new_gobject(*node_destination, encrypted_node);
1692 lasso_release_gobject(*node_to_encrypt);
1693 return 0;
1694 }
1695
1696 /**
1697 * Check the profile->signature_status flag, if signature validation is activated, report it as an
1698 * error, if not not return 0.
1699 */
1700 int
lasso_saml20_profile_check_signature_status(LassoProfile * profile)1701 lasso_saml20_profile_check_signature_status(LassoProfile *profile) {
1702 int rc = 0;
1703
1704 if (profile->signature_status) {
1705 switch (lasso_profile_get_signature_verify_hint(profile)) {
1706 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE:
1707 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE:
1708 rc = profile->signature_status;
1709 break;
1710 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE:
1711 break;
1712 case LASSO_PROFILE_SIGNATURE_VERIFY_HINT_LAST:
1713 g_assert_not_reached();
1714 break;
1715 }
1716 }
1717
1718 return rc;
1719 }
1720