1
/* $Id: logout.c,v 1.124 2004/09/07 14:25:55 nclapies Exp $
3
* Lasso - A free implementation of the Liberty Alliance specifications.
5
* Copyright (C) 2004 Entr'ouvert
6
* http://lasso.entrouvert.org
8
* Authors: Nicolas Clapies <nclapies@entrouvert.com>
9
* Valery Febvre <vfebvre@easter-eggs.com>
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; either version 2 of the License, or
14
* (at your option) any later version.
16
* This program is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
21
* You should have received a copy of the GNU General Public License
22
* along with this program; if not, write to the Free Software
23
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
#include <glib/gprintf.h>
30
#include <lasso/environs/logout.h>
31
#include <lasso/xml/errors.h>
33
#define LASSO_LOGOUT_NODE "LassoLogout"
34
#define LASSO_REMOTE_PROVIDERID_NODE "RemoteProviderID"
36
static GObjectClass *parent_class = NULL;
38
struct _LassoLogoutPrivate
40
gboolean dispose_has_run;
43
/*****************************************************************************/
45
/*****************************************************************************/
48
* lasso_logout_build_request_msg:
49
* @logout: the logout object
51
* This method builds the logout request message.
53
* It gets the single logout protocol profile of the remote provider and :
54
* if it is a SOAP method, then it builds the logout request SOAP message,
55
* sets the msg_body attribute, gets the single logout service url
56
* and sets the msg_url attribute of the logout object.
58
* if it is a HTTP-Redirect method, then it builds the logout request QUERY message,
59
* builds the logout request url, sets the msg_url to the logout request url,
60
* sets the msg_body to NULL
62
* Optionaly ( if private key and certificates paths are set in server object )
63
* it signs the message (with X509 if a SOAP message,
64
* else with simple signature if a QUERY message )
66
* Return value: 0 if ok, else < 0
69
lasso_logout_build_request_msg(LassoLogout *logout)
71
LassoProfile *profile;
72
LassoProvider *provider;
73
xmlChar *protocolProfile = NULL;
75
gchar *url = NULL, *query = NULL;
76
lassoProviderType remote_provider_type;
79
g_return_val_if_fail(LASSO_IS_LOGOUT(logout), -1);
81
profile = LASSO_PROFILE(logout);
83
/* get the remote provider type and get the remote provider object */
84
if (profile->provider_type == lassoProviderTypeSp) {
85
remote_provider_type = lassoProviderTypeIdp;
87
else if (profile->provider_type == lassoProviderTypeIdp) {
88
remote_provider_type = lassoProviderTypeSp;
91
message(G_LOG_LEVEL_CRITICAL, "Invalid provider type\n");
95
provider = lasso_server_get_provider_ref(profile->server, profile->remote_providerID, &err);
96
if (provider == NULL) {
97
message(G_LOG_LEVEL_CRITICAL, err->message);
103
/* get the prototocol profile of the logout request */
104
protocolProfile = lasso_provider_get_singleLogoutProtocolProfile(provider,
105
remote_provider_type,
107
if (protocolProfile == NULL) {
108
message(G_LOG_LEVEL_CRITICAL, "Single logout protocol profile not found\n");
113
/* build the logout request message */
114
if (xmlStrEqual(protocolProfile, lassoLibProtocolProfileSloSpSoap) || \
115
xmlStrEqual(protocolProfile, lassoLibProtocolProfileSloIdpSoap)) {
116
/* sign the request message */
117
lasso_samlp_request_abstract_sign_signature_tmpl(LASSO_SAMLP_REQUEST_ABSTRACT(profile->request),
118
profile->server->private_key,
119
profile->server->certificate);
121
/* build the logout request message */
122
profile->msg_url = lasso_provider_get_soapEndpoint(provider,
123
remote_provider_type,
125
profile->msg_body = lasso_node_export_to_soap(profile->request);
127
else if (xmlStrEqual(protocolProfile,lassoLibProtocolProfileSloSpHttp) || \
128
xmlStrEqual(protocolProfile,lassoLibProtocolProfileSloIdpHttp)) {
129
/* build and optionaly sign the logout request QUERY message */
130
url = lasso_provider_get_singleLogoutServiceURL(provider, remote_provider_type, NULL);
131
query = lasso_node_export_to_query(profile->request,
132
profile->server->signature_method,
133
profile->server->private_key);
134
if ( (url == NULL) || (query == NULL) ) {
135
message(G_LOG_LEVEL_CRITICAL, "Error while building url and query\n");
140
/* build the msg_url */
141
profile->msg_url = g_new(gchar, strlen(url)+strlen(query)+1+1);
142
g_sprintf(profile->msg_url, "%s?%s", url, query);
143
profile->msg_body = NULL;
146
message(G_LOG_LEVEL_CRITICAL, "Invalid logout protocol profile\n");
152
if (protocolProfile != NULL) {
153
xmlFree(protocolProfile);
166
* lasso_logout_build_response_msg:
167
* @logout: the logout object
169
* This method builds the logout response message.
171
* It gets the request message method and :
172
* if it is a SOAP method, then it builds the logout response SOAP message,
173
* sets the msg_body attribute, gets the single logout service return url
174
* and sets the msg_url attribute of the logout object.
176
* if it is a HTTP-Redirect method, then it builds the logout response QUERY message,
177
* builds the logout response url, sets the msg_url with the logout response url,
178
* sets the msg_body with NULL
180
* Optionaly ( if private key and certificates paths are set in server object )
181
* it signs the message (with X509 if a SOAP message,
182
* else with simple signature if a QUERY message )
184
* Return value: 0 if ok, else < 0
187
lasso_logout_build_response_msg(LassoLogout *logout)
189
LassoProfile *profile;
190
LassoProvider *provider;
191
gchar *url = NULL, *query = NULL;
194
gint remote_provider_type;
196
g_return_val_if_fail(LASSO_IS_LOGOUT(logout), -1);
198
profile = LASSO_PROFILE(logout);
200
/* get the provider */
201
provider = lasso_server_get_provider_ref(profile->server, profile->remote_providerID, &err);
202
if (provider == NULL) {
203
message(G_LOG_LEVEL_CRITICAL, err->message);
209
/* get the remote provider type */
210
if (profile->provider_type == lassoProviderTypeSp) {
211
remote_provider_type = lassoProviderTypeIdp;
213
else if (profile->provider_type == lassoProviderTypeIdp) {
214
remote_provider_type = lassoProviderTypeSp;
217
message(G_LOG_LEVEL_CRITICAL, "Invalid provider type\n");
222
/* build logout response message */
223
switch (profile->http_request_method) {
224
case lassoHttpMethodSoap:
225
/* optionaly sign the response message */
226
if (profile->server->private_key) {
227
lasso_samlp_response_abstract_set_signature(LASSO_SAMLP_RESPONSE_ABSTRACT(profile->response),
228
profile->server->signature_method,
229
profile->server->private_key,
230
profile->server->certificate);
233
profile->msg_url = NULL;
234
profile->msg_body = lasso_node_export_to_soap(profile->response);
236
case lassoHttpMethodRedirect:
237
url = lasso_provider_get_singleLogoutServiceReturnURL(provider, remote_provider_type, NULL);
238
query = lasso_node_export_to_query(profile->response,
239
profile->server->signature_method,
240
profile->server->private_key);
241
if ( (url == NULL) || (query == NULL) ) {
242
message(G_LOG_LEVEL_CRITICAL, "Url %s or query %s not found\n", url, query);
247
profile->msg_url = g_new(gchar, strlen(url)+strlen(query)+1+1);
248
g_sprintf(profile->msg_url, "%s?%s", url, query);
249
profile->msg_body = NULL;
252
ret = LASSO_PROFILE_ERROR_MISSING_REQUEST;
268
* lasso_logout_destroy:
269
* @logout: the logout object
271
* destroy the logout object
275
lasso_logout_destroy(LassoLogout *logout)
277
g_object_unref(G_OBJECT(logout));
282
* @logout: the logout object
284
* This method dumps the logout object in string a xml message.
285
* it first adds profile informations.
286
* Next, it adds his logout informations (initial_request, initial_response,
287
* initial_remote_providerID and providerID_index).
289
* Return value: a newly allocated string or NULL
292
lasso_logout_dump(LassoLogout *logout)
294
LassoNode *initial_node = NULL, *child_node = NULL;
295
gchar *dump = NULL, *parent_dump = NULL, *providerID_index_str;
296
LassoNode *node = NULL;
298
g_return_val_if_fail(LASSO_IS_LOGOUT(logout), NULL);
300
parent_dump = lasso_profile_dump(LASSO_PROFILE(logout), "Logout");
301
node = lasso_node_new_from_dump(parent_dump);
304
if (logout->initial_request != NULL) {
305
initial_node = lasso_node_new();
306
LASSO_NODE_GET_CLASS(initial_node)->set_name(initial_node, "InitialLogoutResquest");
307
child_node = lasso_node_copy(logout->initial_request);
308
LASSO_NODE_GET_CLASS(initial_node)->add_child(initial_node, child_node, FALSE);
309
lasso_node_destroy(child_node);
311
LASSO_NODE_GET_CLASS(node)->add_child(node, initial_node, FALSE);
314
if (logout->initial_response != NULL) {
315
initial_node = lasso_node_new();
316
LASSO_NODE_GET_CLASS(initial_node)->set_name(initial_node, "InitialLogoutResponse");
317
child_node = lasso_node_copy(logout->initial_response);
318
LASSO_NODE_GET_CLASS(initial_node)->add_child(initial_node, child_node, FALSE);
319
lasso_node_destroy(child_node);
321
LASSO_NODE_GET_CLASS(node)->add_child(node, initial_node, FALSE);
324
if (logout->initial_remote_providerID != NULL) {
325
LASSO_NODE_GET_CLASS(node)->new_child(node, "InitialRemoteProviderID",
326
logout->initial_remote_providerID, FALSE);
329
/* add providerID_index */
330
providerID_index_str = g_strdup_printf("%d", logout->providerID_index);
331
LASSO_NODE_GET_CLASS(node)->new_child(node, "ProviderIDIndex",
332
providerID_index_str, FALSE);
334
dump = lasso_node_export(node);
336
lasso_node_destroy(node);
342
* lasso_logout_get_next_providerID:
343
* @logout: the logout object
345
* This method returns the provider id from providerID_index in list of providerIDs in session object.
346
* excepted the initial service provider id :
347
* It gets the remote provider id in session from the logout providerID_index.
348
* If it is the initial remote provider id, then it asks the next provider id
349
* from providerID_index + 1;
351
* Return value: a newly allocated string or NULL
354
lasso_logout_get_next_providerID(LassoLogout *logout)
356
LassoProfile *profile;
359
g_return_val_if_fail(LASSO_IS_LOGOUT(logout), NULL);
360
profile = LASSO_PROFILE(logout);
362
g_return_val_if_fail(LASSO_IS_SESSION(profile->session), NULL);
363
providerID = lasso_session_get_provider_index(profile->session, logout->providerID_index);
364
logout->providerID_index++;
365
/* if it is the provider id of the SP requester, then get the next */
366
if (logout->initial_remote_providerID && xmlStrEqual(providerID, logout->initial_remote_providerID)) {
367
providerID = lasso_session_get_provider_index(profile->session, logout->providerID_index);
368
logout->providerID_index++;
375
* lasso_logout_init_request:
377
* @remote_providerID:
378
* @request_method: if set, then it get the protocol profile in metadata
379
* corresponding of this HTTP request method.
381
* First it verifies session and identity are set.
382
* Next, gets federation with the remote provider and gets the name identifier for the request.
383
* gets the protocol profile and build the logout request object.
384
* If the local provider is a Service Provider and if the protocol profile is a HTTP Redirect / GET method,
385
* then removes the assertion.
387
* Return value: 0 if ok, else < 0
390
lasso_logout_init_request(LassoLogout *logout,
391
gchar *remote_providerID,
392
lassoHttpMethod request_method) /* FIXME : support this param to allow the user to choose the request method */
394
LassoProfile *profile = NULL;
395
LassoProvider *provider = NULL;
396
LassoNode *nameIdentifier = NULL;
397
LassoFederation *federation = NULL;
398
xmlChar *content = NULL, *nameQualifier = NULL, *format = NULL;
399
xmlChar *singleLogoutProtocolProfile = NULL;
401
gboolean is_http_redirect_get_method = FALSE;
404
g_return_val_if_fail(LASSO_IS_LOGOUT(logout), -1);
406
profile = LASSO_PROFILE(logout);
408
/* verify if the identity and session exist */
409
if (profile->identity == NULL) {
410
message(G_LOG_LEVEL_CRITICAL, "Identity not found\n");
414
if (profile->session == NULL) {
415
message(G_LOG_LEVEL_CRITICAL, "Session not found\n");
420
/* get the remote provider id */
421
/* If remote_providerID is NULL, then get the first remote provider id in session */
422
if (remote_providerID == NULL) {
423
profile->remote_providerID = lasso_session_get_first_providerID(profile->session);
426
profile->remote_providerID = g_strdup(remote_providerID);
428
if (profile->remote_providerID == NULL) {
429
message(G_LOG_LEVEL_CRITICAL, "No remote provider id to send the logout request\n");
435
federation = lasso_identity_get_federation(profile->identity, profile->remote_providerID);
436
if (federation == NULL) {
437
message(G_LOG_LEVEL_CRITICAL, "Federation not found\n");
442
/* get the name identifier */
443
switch (profile->provider_type) {
444
case lassoProviderTypeSp:
445
/* SP : get the local name identifier, if it is NULL, then get the remote name identifier */
446
nameIdentifier = lasso_federation_get_local_nameIdentifier(federation);
447
if (nameIdentifier == NULL) {
448
nameIdentifier = lasso_federation_get_remote_nameIdentifier(federation);
451
case lassoProviderTypeIdp:
452
/* IDP : get the remote name identifier, if it is NULL, then get the local name identifier */
453
nameIdentifier = lasso_federation_get_remote_nameIdentifier(federation);
454
if (nameIdentifier == NULL) {
455
nameIdentifier = lasso_federation_get_local_nameIdentifier(federation);
459
message(G_LOG_LEVEL_CRITICAL, "Invalid provider type\n");
464
if (nameIdentifier == NULL) {
465
message(G_LOG_LEVEL_CRITICAL, "Name identifier not found for %s\n",
466
profile->remote_providerID);
471
/* get name identifier attributes */
472
content = lasso_node_get_content(nameIdentifier, NULL);
473
nameQualifier = lasso_node_get_attr_value(nameIdentifier, "NameQualifier", NULL);
474
format = lasso_node_get_attr_value(nameIdentifier, "Format", NULL);
476
/* get the provider */
477
provider = lasso_server_get_provider_ref(profile->server, profile->remote_providerID, &err);
478
if (provider == NULL) {
479
message(G_LOG_LEVEL_CRITICAL, err->message);
485
/* Get the single logout protocol profile */
486
if (profile->provider_type == lassoProviderTypeIdp) {
487
singleLogoutProtocolProfile = lasso_provider_get_singleLogoutProtocolProfile(provider, lassoProviderTypeSp, NULL);
489
else if (profile->provider_type == lassoProviderTypeSp) {
490
singleLogoutProtocolProfile = lasso_provider_get_singleLogoutProtocolProfile(provider, lassoProviderTypeIdp, NULL);
493
message(G_LOG_LEVEL_CRITICAL, "Invalid provider type\n");
497
if (singleLogoutProtocolProfile == NULL) {
498
message(G_LOG_LEVEL_CRITICAL, "Single logout protocol profile not found\n");
503
/* before setting profile->request, verify if it is already set */
504
if (LASSO_IS_LOGOUT_REQUEST(profile->request) == TRUE) {
505
lasso_node_destroy(profile->request);
506
profile->request = NULL;
509
/* build a new request object from single logout protocol profile */
510
if (xmlStrEqual(singleLogoutProtocolProfile, lassoLibProtocolProfileSloSpSoap) || \
511
xmlStrEqual(singleLogoutProtocolProfile, lassoLibProtocolProfileSloIdpSoap)) {
512
profile->request = lasso_logout_request_new(profile->server->providerID,
516
lassoSignatureTypeWithX509,
517
lassoSignatureMethodRsaSha1);
519
else if (xmlStrEqual(singleLogoutProtocolProfile, lassoLibProtocolProfileSloSpHttp) || \
520
xmlStrEqual(singleLogoutProtocolProfile, lassoLibProtocolProfileSloIdpHttp)) {
521
is_http_redirect_get_method = TRUE;
522
profile->request = lasso_logout_request_new(profile->server->providerID,
526
lassoSignatureTypeNone,
530
message(G_LOG_LEVEL_CRITICAL, "Invalid single logout protocol profile : %s\n", singleLogoutProtocolProfile);
534
if (LASSO_IS_LOGOUT_REQUEST(profile->request) == FALSE) {
535
message(G_LOG_LEVEL_CRITICAL, "Error while building the request\n");
540
/* set the name identifier in logout object */
541
profile->nameIdentifier = content;
543
/* if logout request from a SP and if an HTTP Redirect / GET method, then remove assertion */
544
if (profile->provider_type == lassoProviderTypeSp && is_http_redirect_get_method == TRUE) {
545
lasso_session_remove_assertion(profile->session, profile->remote_providerID);
549
if (federation != NULL) {
550
lasso_federation_destroy(federation);
552
if (nameIdentifier != NULL ) {
553
lasso_node_destroy(nameIdentifier);
555
if (nameQualifier != NULL) {
556
xmlFree(nameQualifier);
558
if (format != NULL) {
561
if (singleLogoutProtocolProfile != NULL) {
562
xmlFree(singleLogoutProtocolProfile);
569
* lasso_logout_process_request_msg:
570
* @logout: the logout object
571
* @request_msg: the logout request message
572
* @request_method: the logout request method
574
* Processes a logout request.
575
* if it is a SOAP request method then it builds the logout request object
576
* from the SOAP message and optionaly verifies the signature of the logout request.
578
* if it is a HTTP-Redirect request method then it builds the logout request object
579
* from the QUERY message and verify the signature. If there is an error while parsing the query,
580
* then returns the code error LASSO_PROFILE_ERROR_INVALID_QUERY.
582
* Saves the HTTP request method.
583
* Saves the name identifier.
585
* Return value: 0 if OK else LASSO_PROFILE_ERROR_INVALID_QUERY or < 0
587
gint lasso_logout_process_request_msg(LassoLogout *logout,
589
lassoHttpMethod request_method)
591
LassoProfile *profile;
592
LassoProvider *provider;
593
gchar *remote_providerID = NULL;
597
g_return_val_if_fail(LASSO_IS_LOGOUT(logout), -1);
598
g_return_val_if_fail(request_msg != NULL, -1);
600
profile = LASSO_PROFILE(logout);
602
/* rebuild the request message and optionaly verify the signature */
603
switch (request_method) {
604
case lassoHttpMethodSoap:
605
profile->request = lasso_logout_request_new_from_export(request_msg,
606
lassoNodeExportTypeSoap);
608
/* verify requets is a LogoutRequest */
609
if (LASSO_IS_LOGOUT_REQUEST(profile->request) == FALSE) {
610
message(G_LOG_LEVEL_CRITICAL, "Message is not a LogoutRequest\n");
615
/* verify signature */
616
remote_providerID = lasso_node_get_child_content(profile->request, "ProviderID", NULL, NULL);
617
if (remote_providerID == NULL) {
618
message(G_LOG_LEVEL_CRITICAL, "ProviderID not found\n");
622
provider = lasso_server_get_provider_ref(profile->server, remote_providerID, &err);
623
if (provider == NULL) {
624
message(G_LOG_LEVEL_CRITICAL, err->message);
629
if (provider->ca_certificate != NULL) {
630
ret = lasso_node_verify_x509_signature(profile->request, provider->ca_certificate);
633
case lassoHttpMethodRedirect:
634
profile->request = lasso_logout_request_new_from_export(request_msg,
635
lassoNodeExportTypeQuery);
636
/* if problem while rebuilding the response, then return invalid query code error */
637
if (LASSO_IS_LOGOUT_REQUEST(profile->request) == FALSE) {
638
ret = LASSO_PROFILE_ERROR_INVALID_QUERY;
644
message(G_LOG_LEVEL_CRITICAL, "Invalid request method\n");
649
/* set the http request method */
650
profile->http_request_method = request_method;
652
/* Set the NameIdentifier */
653
profile->nameIdentifier = lasso_node_get_child_content(profile->request,
658
if (remote_providerID != NULL ) {
659
xmlFree(remote_providerID);
666
* lasso_logout_process_response_msg:
667
* @logout: the logout object
668
* @response_msg: the response message
669
* @response_method: the response method
671
* Parses the response message and builds the response object :
672
* if there is an error while parsing the HTTP Redirect / GET message,
673
* then returns a LASSO_PROFILE_ERROR_INVALID_QUERY code error.
674
* Get the status code value :
675
* if it is not success, then if the local provider is a Service Provider and response method is SOAP,
676
* then builds a new logout request message for HTTP Redirect / GET method and returns the code error
677
* LASSO_LOGOUT_ERROR_UNSUPPORTED_PROFILE and exits.
679
* Sets the remote provider id.
680
* Sets the relay state.
682
* if it is a SOAP method or, IDP provider type and http method is Redirect / GET, then removes assertion.
684
* If local server is an Identity Provider and if there is no more assertion (Identity Provider has logged out every Service Providers),
685
* then restores the initial response.
686
* Return value: 0 if OK else LASSO_LOGOUT_ERROR_UNSUPPORTED_PROFILE or < 0
689
lasso_logout_process_response_msg(LassoLogout *logout,
691
lassoHttpMethod response_method)
693
gchar *last_providerID = NULL;
694
xmlChar *statusCodeValue = NULL;
695
LassoNode *statusCode = NULL;
696
LassoProfile *profile = NULL;
700
g_return_val_if_fail(LASSO_IS_LOGOUT(logout), -1);
701
g_return_val_if_fail(response_msg != NULL, -1);
703
profile = LASSO_PROFILE(logout);
705
/* before verify if profile->response is set */
706
if (LASSO_IS_LOGOUT_RESPONSE(profile->response) == TRUE) {
707
lasso_node_destroy(profile->response);
708
profile->response = NULL;
711
/* build logout response object */
712
switch (response_method) {
713
case lassoHttpMethodSoap:
714
profile->response = lasso_logout_response_new_from_export(response_msg, lassoNodeExportTypeSoap);
716
case lassoHttpMethodRedirect:
717
profile->response = lasso_logout_response_new_from_export(response_msg, lassoNodeExportTypeQuery);
718
/* if problem while rebuilding the response, then return invalid query code error */
719
if (LASSO_IS_LOGOUT_RESPONSE(profile->response) == FALSE) {
720
ret = LASSO_PROFILE_ERROR_INVALID_QUERY;
725
message(G_LOG_LEVEL_CRITICAL, "Invalid response method\n");
729
if (LASSO_IS_LOGOUT_RESPONSE(profile->response) == FALSE) {
730
message(G_LOG_LEVEL_CRITICAL, "Message is not a LogoutResponse\n");
735
/* get the status code */
736
statusCode = lasso_node_get_child(profile->response, "StatusCode", NULL, NULL);
737
if (statusCode == NULL) {
738
message(G_LOG_LEVEL_CRITICAL, "StatusCode node not found\n");
742
statusCodeValue = lasso_node_get_attr_value(statusCode, "Value", NULL);
744
if (!xmlStrEqual(statusCodeValue, lassoSamlStatusCodeSuccess)) {
746
/* At SP, if the request method was a SOAP type, then rebuild the request message with HTTP method */
747
if (xmlStrEqual(statusCodeValue, lassoLibStatusCodeUnsupportedProfile) && \
748
profile->provider_type == lassoProviderTypeSp && \
749
profile->http_request_method == lassoHttpMethodSoap) {
751
LassoProvider *provider;
754
provider = lasso_server_get_provider_ref(profile->server, profile->remote_providerID, &err);
755
if (provider == NULL) {
756
message(G_LOG_LEVEL_CRITICAL, err->message);
762
/* FIXME : verify the IDP support a HTTP method */
764
/* Build and optionaly sign the logout request QUERY message */
765
url = lasso_provider_get_singleLogoutServiceURL(provider, lassoProviderTypeIdp, NULL);
766
query = lasso_node_export_to_query(profile->request,
767
profile->server->signature_method,
768
profile->server->private_key);
769
profile->msg_url = g_new(gchar, strlen(url)+strlen(query)+1+1);
770
g_sprintf(profile->msg_url, "%s?%s", url, query);
771
profile->msg_body = NULL;
773
/* send a HTTP Redirect / GET method, so first remove session */
774
lasso_session_remove_assertion(profile->session, profile->remote_providerID);
776
ret = LASSO_LOGOUT_ERROR_UNSUPPORTED_PROFILE;
779
message(G_LOG_LEVEL_CRITICAL, "Status code is not success : %s\n", statusCodeValue);
786
/* LogoutResponse status code value is ok */
788
/* set the remote provider id */
789
profile->remote_providerID = lasso_node_get_child_content(profile->response,
794
/* set the msg_relayState */
795
profile->msg_relayState = lasso_node_get_child_content(profile->response, "RelayState", lassoLibHRef, NULL);
797
/* if SOAP method or, if IDP provider type and HTTP Redirect, then remove assertion */
798
if ( (response_method == lassoHttpMethodSoap) || (profile->provider_type == lassoProviderTypeIdp && response_method == lassoHttpMethodRedirect) ) {
799
ret = lasso_session_remove_assertion(profile->session, profile->remote_providerID);
800
if (profile->provider_type == lassoProviderTypeIdp && logout->providerID_index >= 0) {
801
logout->providerID_index--;
805
/* If at IDP and if there is no more assertion, IDP a logged out every SPs, return the initial response to initial SP */
806
if (profile->provider_type == lassoProviderTypeIdp && logout->initial_remote_providerID && profile->session->providerIDs->len == 0) {
807
if (profile->remote_providerID != NULL) {
808
g_free(profile->remote_providerID);
810
if (profile->request != NULL) {
811
lasso_node_destroy(profile->request);
813
if (profile->response != NULL) {
814
lasso_node_destroy(profile->response);
817
profile->remote_providerID = logout->initial_remote_providerID;
818
profile->request = logout->initial_request;
819
profile->response = logout->initial_response;
821
logout->initial_remote_providerID = NULL;
822
logout->initial_request = NULL;
823
logout->initial_response = NULL;
827
if (last_providerID != NULL) {
828
g_free(last_providerID);
835
* lasso_logout_reset_providerID_index:
836
* @logout: the logout object
838
* Reset the providerID_index attribute (set to 0).
842
gint lasso_logout_reset_providerID_index(LassoLogout *logout)
844
g_return_val_if_fail(LASSO_IS_LOGOUT(logout), -1);
846
logout->providerID_index = 0;
852
* lasso_logout_validate_request:
853
* @logout: the logout object
855
* Sets the remote provider id
856
* Sets a logout response with status code value to success.
857
* Verifies federation and authentication.
858
* If the request http method is a SOAP method, then verifies every other
859
* Service Providers supports SOAP method : if not, then sets status code value to
860
* UnsupportedProfile and returns a code error with LASSO_LOGOUT_ERROR_UNSUPPORTED_PROFILE.
862
* Every tests are ok, then removes assertion.
863
* (profile->provider_type == lassoProviderTypeIdp && profile->session->providerIDs->len >= 1)
864
* If local server is an Identity Provider and if there is more than one Service Provider
865
* (except the initial Service Provider),
866
* then saves the initial request, response and remote provider id.
868
* Return value: O if OK else < 0
871
lasso_logout_validate_request(LassoLogout *logout)
873
LassoProfile *profile;
874
LassoFederation *federation = NULL;
875
LassoNode *nameIdentifier, *assertion;
876
LassoNode *statusCode;
877
LassoNodeClass *statusCode_class;
878
xmlChar *remote_providerID;
881
g_return_val_if_fail(LASSO_IS_LOGOUT(logout), -1);
883
profile = LASSO_PROFILE(logout);
885
/* verify logout request */
886
if (profile->request == NULL) {
887
ret = LASSO_PROFILE_ERROR_MISSING_REQUEST;
891
/* Set the remote provider id from the request */
892
remote_providerID = lasso_node_get_child_content(profile->request, "ProviderID",
894
if (remote_providerID == NULL) {
895
message(G_LOG_LEVEL_CRITICAL, "ProviderID in LogoutRequest not found\n");
899
profile->remote_providerID = remote_providerID;
901
/* Set LogoutResponse */
902
switch (profile->http_request_method) {
903
case lassoHttpMethodSoap:
904
profile->response = lasso_logout_response_new(profile->server->providerID,
905
lassoSamlStatusCodeSuccess,
907
lassoSignatureTypeWithX509,
908
lassoSignatureMethodRsaSha1);
910
case lassoHttpMethodRedirect:
911
profile->response = lasso_logout_response_new(profile->server->providerID,
912
lassoSamlStatusCodeSuccess,
914
lassoSignatureTypeNone,
918
message(G_LOG_LEVEL_CRITICAL, "Invalid HTTP request method\n");
922
if (LASSO_IS_LOGOUT_RESPONSE(profile->response) == FALSE) {
923
message(G_LOG_LEVEL_CRITICAL, "Error while building response\n");
928
/* Get the name identifier */
929
nameIdentifier = lasso_node_get_child(profile->request, "NameIdentifier",
931
if (nameIdentifier == NULL) {
932
message(G_LOG_LEVEL_CRITICAL, "Name identifier not found in logout request\n");
933
lasso_profile_set_response_status(profile, lassoLibStatusCodeFederationDoesNotExist);
938
/* verify authentication */
939
if (profile->identity == NULL) {
940
message(G_LOG_LEVEL_WARNING, "Identity not found\n");
941
/* FIXME : use RequestDenied if no identity found ? */
942
lasso_profile_set_response_status(profile, lassoSamlStatusCodeRequestDenied);
946
assertion = lasso_session_get_assertion(profile->session, remote_providerID);
947
if (assertion == NULL) {
948
message(G_LOG_LEVEL_WARNING, "%s has no assertion\n", remote_providerID);
949
lasso_profile_set_response_status(profile, lassoSamlStatusCodeRequestDenied);
953
lasso_node_destroy(assertion);
955
/* Verify federation */
956
federation = lasso_identity_get_federation(profile->identity, remote_providerID);
957
if (federation == NULL) {
958
message(G_LOG_LEVEL_WARNING, "No federation for %s\n", remote_providerID);
959
lasso_profile_set_response_status(profile, lassoLibStatusCodeFederationDoesNotExist);
964
if (lasso_federation_verify_nameIdentifier(federation, nameIdentifier) == FALSE) {
965
message(G_LOG_LEVEL_WARNING, "No name identifier for %s\n", remote_providerID);
966
lasso_profile_set_response_status(profile, lassoLibStatusCodeFederationDoesNotExist);
971
/* if SOAP request method at IDP then verify all the remote service providers support SOAP protocol profile.
972
If one remote authenticated principal service provider doesn't support SOAP
973
then return UnsupportedProfile to original service provider */
974
if (profile->provider_type == lassoProviderTypeIdp && profile->http_request_method == lassoHttpMethodSoap) {
975
gboolean all_http_soap;
976
LassoProvider *provider;
977
gchar *providerID, *protocolProfile;
980
all_http_soap = TRUE;
982
for (i = 0; i<profile->server->providers->len; i++) {
983
provider = g_ptr_array_index(profile->server->providers, i);
984
providerID = lasso_provider_get_providerID(provider);
986
/* if the original service provider then continue */
987
if (xmlStrEqual(remote_providerID, providerID)) {
991
/* if principal is not authenticated with this remote service provider, continue */
992
assertion = lasso_session_get_assertion(profile->session, providerID);
993
if (assertion == NULL) {
997
/* if protocolProfile is SOAP continue else break */
998
protocolProfile = lasso_provider_get_singleLogoutProtocolProfile(provider, lassoProviderTypeSp, NULL);
999
if (protocolProfile == NULL || !xmlStrEqual(protocolProfile, lassoLibProtocolProfileSloSpSoap)) {
1000
all_http_soap = FALSE;
1003
if (protocolProfile != NULL) {
1004
xmlFree(protocolProfile);
1006
if (providerID != NULL) {
1007
xmlFree(providerID);
1011
if (all_http_soap==FALSE) {
1012
lasso_profile_set_response_status(profile, lassoLibStatusCodeUnsupportedProfile);
1013
ret = LASSO_LOGOUT_ERROR_UNSUPPORTED_PROFILE;
1018
/* FIXME : set the status code in response */
1020
/* authentication is ok, federation is ok, propagation support is ok, remove federation */
1021
lasso_session_remove_assertion(profile->session, profile->remote_providerID);
1023
/* if at IDP and nb sp logged > 1, then backup remote provider id,
1024
* request and response
1025
* REMARK : if only initial service provider was logged,
1026
* then profile->session->providerIDs->len == 0,
1027
* else profile->session->providerIDs->len >= 1
1029
if (profile->provider_type == lassoProviderTypeIdp && profile->session->providerIDs->len >= 1) {
1030
logout->initial_remote_providerID = profile->remote_providerID;
1031
logout->initial_request = profile->request;
1032
logout->initial_response = profile->response;
1034
profile->remote_providerID = NULL;
1035
profile->request = NULL;
1036
profile->response = NULL;
1040
if (federation != NULL) {
1041
lasso_federation_destroy(federation);
1047
/*****************************************************************************/
1048
/* overrided parent class methods */
1049
/*****************************************************************************/
1052
lasso_logout_dispose(LassoLogout *logout)
1054
if (logout->private->dispose_has_run) {
1057
logout->private->dispose_has_run = TRUE;
1059
debug("Logout object 0x%x disposed ...\n", logout);
1061
/* unref reference counted objects */
1062
lasso_node_destroy(logout->initial_request);
1063
lasso_node_destroy(logout->initial_response);
1065
parent_class->dispose(G_OBJECT(logout));
1069
lasso_logout_finalize(LassoLogout *logout)
1071
debug("Logout object 0x%x finalized ...\n", logout);
1073
g_free(logout->initial_remote_providerID);
1075
g_free(logout->private);
1077
parent_class->finalize(G_OBJECT(logout));
1080
/*****************************************************************************/
1081
/* instance and class init functions */
1082
/*****************************************************************************/
1085
lasso_logout_instance_init(GTypeInstance *instance,
1088
LassoLogout *logout = LASSO_LOGOUT(instance);
1090
logout->private = g_new (LassoLogoutPrivate, 1);
1091
logout->private->dispose_has_run = FALSE;
1093
logout->initial_request = NULL;
1094
logout->initial_response = NULL;
1095
logout->initial_remote_providerID = NULL;
1097
logout->providerID_index = 0;
1101
lasso_logout_class_init(LassoLogoutClass *class)
1103
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
1105
parent_class = g_type_class_peek_parent(class);
1106
/* override parent class methods */
1107
gobject_class->dispose = (void *)lasso_logout_dispose;
1108
gobject_class->finalize = (void *)lasso_logout_finalize;
1111
GType lasso_logout_get_type() {
1112
static GType this_type = 0;
1115
static const GTypeInfo this_info = {
1116
sizeof (LassoLogoutClass),
1119
(GClassInitFunc) lasso_logout_class_init,
1122
sizeof(LassoLogout),
1124
(GInstanceInitFunc) lasso_logout_instance_init,
1127
this_type = g_type_register_static(LASSO_TYPE_PROFILE,
1136
* @server: the logout object
1137
* @provider_type: the provider type (service provider or identity provider)
1139
* initialises a new logout object
1141
* Return value: a new instance of logout object or NULL
1144
lasso_logout_new(LassoServer *server,
1145
lassoProviderType provider_type)
1147
LassoLogout *logout;
1149
g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
1151
/* set the logout object */
1152
logout = g_object_new(LASSO_TYPE_LOGOUT,
1153
"server", lasso_server_copy(server),
1154
"provider_type", provider_type,
1161
lasso_logout_new_from_dump(LassoServer *server,
1164
LassoLogout *logout;
1165
LassoProfile *profile;
1166
LassoNode *node_dump, *request_node, *response_node;
1167
LassoNode *initial_request_node, *initial_response_node;
1168
gchar *type, *export, *providerID_index_str;
1170
g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
1171
g_return_val_if_fail(dump != NULL, NULL);
1173
logout = LASSO_LOGOUT(g_object_new(LASSO_TYPE_LOGOUT,
1174
"server", lasso_server_copy(server),
1177
profile = LASSO_PROFILE(logout);
1179
node_dump = lasso_node_new_from_dump(dump);
1181
/* profile attributes */
1182
profile->nameIdentifier = lasso_node_get_child_content(node_dump, "NameIdentifier",
1183
lassoLassoHRef, NULL);
1184
profile->remote_providerID = lasso_node_get_child_content(node_dump, "RemoteProviderID",
1185
lassoLassoHRef, NULL);
1186
profile->msg_url = lasso_node_get_child_content(node_dump, "MsgUrl",
1187
lassoLassoHRef, NULL);
1188
profile->msg_body = lasso_node_get_child_content(node_dump, "MsgBody",
1189
lassoLassoHRef, NULL);
1190
profile->msg_relayState = lasso_node_get_child_content(node_dump, "MsgRelayState",
1191
lassoLassoHRef, NULL);
1193
/* rebuild request */
1194
request_node = lasso_node_get_child(node_dump, "LogoutRequest", lassoLibHRef, NULL);
1196
if (LASSO_IS_NODE(request_node) == TRUE) {
1197
export = lasso_node_export(request_node);
1198
profile->request = lasso_logout_request_new_from_export(export,
1199
lassoNodeExportTypeXml);
1201
lasso_node_destroy(request_node);
1205
/* rebuild response */
1206
response_node = lasso_node_get_child(node_dump, "LogoutResponse", lassoLibHRef, NULL);
1207
if (response_node != NULL) {
1208
export = lasso_node_export(response_node);
1209
profile->response = lasso_logout_response_new_from_export(export,
1210
lassoNodeExportTypeXml);
1212
lasso_node_destroy(response_node);
1216
type = lasso_node_get_child_content(node_dump, "ProviderType", lassoLassoHRef, NULL);
1217
profile->provider_type = atoi(type);
1220
/* logout attributes */
1221
/* Initial logout request */
1222
initial_request_node = lasso_node_get_child(node_dump, "InitialRequest", lassoLassoHRef, NULL);
1223
if (initial_request_node != NULL) {
1224
request_node = lasso_node_get_child(node_dump, "LogoutRequest", lassoLibHRef, NULL);
1225
export = lasso_node_export(request_node);
1226
profile->request = lasso_logout_request_new_from_export(export,
1227
lassoNodeExportTypeXml);
1229
lasso_node_destroy(request_node);
1232
/* Initial logout response */
1233
initial_response_node = lasso_node_get_child(node_dump, "InitialResponse", lassoLassoHRef, NULL);
1234
if (initial_response_node != NULL) {
1235
response_node = lasso_node_get_child(node_dump, "LogoutResponse", lassoLibHRef, NULL);
1236
export = lasso_node_export(response_node);
1237
profile->response = lasso_logout_response_new_from_export(export,
1238
lassoNodeExportTypeXml);
1240
lasso_node_destroy(response_node);
1243
/* Initial logout remote provider id */
1244
logout->initial_remote_providerID = lasso_node_get_child_content(node_dump, "InitialRemoteProviderID", lassoLassoHRef, NULL);
1246
/* index provider id */
1248
providerID_index_str = lasso_node_get_child_content(node_dump, "ProviderIDIndex", NULL, NULL);
1250
if (providerID_index_str == NULL) {
1251
message(G_LOG_LEVEL_CRITICAL, "Index ProviderID not found\n");
1254
logout->providerID_index = atoi(providerID_index_str);