/* $Id: discovery.c,v 1.75 2007/01/03 23:35:17 Exp $ * * Lasso - A free implementation of the Liberty Alliance specifications. * * Copyright (C) 2004-2007 Entr'ouvert * http://lasso.entrouvert.org * * Authors: See AUTHORS file in top-level directory. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * SECTION:idwsf2_discovery * @short_description: ID-WSF 2.0 Discovery Service profile * * The Discovery service usually runs on the principal identity provider and * knowns about resources and services related to the principal. Attribute * providers can register themselves as offering resources for an user while * other services can ask where to find a given resource. */ #include "../xml/private.h" #include #include #include #include "../xml/saml_attribute_value.h" #include "../xml/xml_enc.h" #include "../xml/saml-2.0/saml2_assertion.h" #include "../xml/saml-2.0/samlp2_name_id_policy.h" #include "../xml/id-wsf-2.0/disco_query.h" #include "../xml/id-wsf-2.0/disco_requested_service.h" #include "../xml/id-wsf-2.0/disco_svc_md_register.h" #include "../xml/id-wsf-2.0/disco_svc_md_register_response.h" #include "../xml/id-wsf-2.0/disco_svc_md_association_add.h" #include "../xml/id-wsf-2.0/disco_svc_md_association_add_response.h" #include "../xml/id-wsf-2.0/disco_svc_md_association_add_response.h" #include "../xml/id-wsf-2.0/disco_abstract.h" #include "../xml/id-wsf-2.0/disco_provider_id.h" #include "../xml/id-wsf-2.0/disco_service_type.h" #include "../xml/id-wsf-2.0/disco_security_context.h" #include "../xml/id-wsf-2.0/disco_service_context.h" #include "../xml/id-wsf-2.0/disco_endpoint_context.h" #include "../xml/id-wsf-2.0/sec_token.h" #include "../xml/ws/wsa_endpoint_reference.h" #include "../id-ff/server.h" #include "../id-ff/provider.h" #include "../id-ff/providerprivate.h" #include "discovery.h" #include "profile.h" #include "identity.h" #include "server.h" #include "session.h" #include "../utils.h" struct _LassoIdWsf2DiscoveryPrivate { gboolean dispose_has_run; GList *new_entry_ids; char *security_mech_id; }; /*****************************************************************************/ /* public methods */ /*****************************************************************************/ /** * lasso_idwsf2_discovery_metadata_register_self: * @discovery: a #LassoIdWsf2Discovery * @service_type: the service type of the registered metadata, for example LASSO_IDWSF2_DISCO_HREF * @abstract: label/title of the service, free form * @soap_endpoint: URL of the SoapEndpoint to the service * @svcMDID: identifier of the metadatas if caller wants to specify which identifier it wants. * If NULL, a random identifier will be generated. * * Register metadata service on itself as an ID-WSF Provider (WSP). * Typically used for an IdP to register itself as Discovery service. * * Return value: the svcMDID of the new metadata object if the call is successfull, NULL otherwise. These * value must be freed using g_free. **/ gchar* lasso_idwsf2_discovery_metadata_register_self(LassoIdWsf2Discovery *discovery, const gchar *service_type, const gchar *abstract, const gchar *soap_endpoint, const gchar *svcMDID) { LassoIdWsf2Profile *profile; LassoProvider *provider; gchar *provider_id; LassoIdWsf2DiscoSvcMetadata *metadata; char *new_svcMDID; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), NULL); g_return_val_if_fail(service_type != NULL && service_type[0] != '\0', NULL); g_return_val_if_fail(abstract != NULL && abstract[0] != '\0', NULL); g_return_val_if_fail(soap_endpoint != NULL && soap_endpoint[0] != '\0', NULL); profile = LASSO_IDWSF2_PROFILE(discovery); provider = LASSO_PROVIDER(LASSO_PROFILE(profile)->server); provider_id = provider->ProviderID; metadata = lasso_idwsf2_disco_svc_metadata_new_full( service_type, abstract, provider_id, soap_endpoint); if (svcMDID != NULL) { metadata->svcMDID = g_strdup(svcMDID); } else { metadata->svcMDID = lasso_build_unique_id(32); } lasso_server_add_svc_metadata(LASSO_PROFILE(profile)->server, metadata); new_svcMDID = g_strdup(metadata->svcMDID); g_object_unref(metadata); return new_svcMDID; } /** * lasso_idwsf2_discovery_init_metadata_register: * @discovery: a #LassoIdWsf2Discovery * @service_type: the service type of the registered metadata, for example LASSO_IDWSF2_DISCO_HREF * @abstract: label/title of the service, free form * @disco_provider_id: provider identifier of the discovery service * @soap_endpoint: URL of the SoapEndpoint to the service * * Initialise a ID-WSF service metadata registration request to a Discovery service * specified by disco_provider_id. * * Return value: 0 on success; an error code otherwise. **/ gint lasso_idwsf2_discovery_init_metadata_register(LassoIdWsf2Discovery *discovery, const gchar *service_type, const gchar *abstract, const gchar *disco_provider_id, const gchar *soap_endpoint) { LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); LassoIdWsf2DiscoSvcMDRegister *metadata_register; LassoProvider *provider; gchar *sp_provider_id; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); g_return_val_if_fail(service_type != NULL && service_type[0] != '\0', LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); g_return_val_if_fail(abstract != NULL && abstract[0] != '\0', LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); g_return_val_if_fail(disco_provider_id != NULL && disco_provider_id[0] != '\0', LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); g_return_val_if_fail(soap_endpoint != NULL && soap_endpoint[0] != '\0', LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); /* Get the providerId of this SP */ provider = LASSO_PROVIDER(LASSO_PROFILE(profile)->server); sp_provider_id = provider->ProviderID; /* Get a MetadataRegister node */ metadata_register = lasso_idwsf2_disco_svc_md_register_new_full( service_type, abstract, sp_provider_id, soap_endpoint); /* Create a request with this xml node */ lasso_idwsf2_profile_init_soap_request(profile, LASSO_NODE(metadata_register), LASSO_IDWSF2_DISCO_HREF); return 0; } /** * lasso_idwsf2_discovery_process_metadata_register_msg: * @discovery: a #LassoIdWsf2Discovery * @message: received metadata register soap request * * Process received metadata register request. * If successful, register the service metadata into the discovery service. * * Return value: 0 on success; or a negative value otherwise. **/ gint lasso_idwsf2_discovery_process_metadata_register_msg(LassoIdWsf2Discovery *discovery, const gchar *message) { LassoIdWsf2Profile *profile; LassoIdWsf2DiscoSvcMDRegisterResponse *response; LassoSoapEnvelope *envelope; int rc = 0; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); profile = LASSO_IDWSF2_PROFILE(discovery); g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); rc = lasso_idwsf2_profile_process_soap_request_msg(profile, message); if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_REGISTER(LASSO_PROFILE(profile)->request)) { rc = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; } /* OK case */ if (rc == 0) { LassoIdWsf2DiscoSvcMDRegister *request; GList *SvcMD; lasso_release_list_of_gobjects(discovery->metadatas); request = LASSO_IDWSF2_DISCO_SVC_MD_REGISTER(LASSO_PROFILE(profile)->request); /* Allocate an ID and add the metadatas */ for (SvcMD = request->SvcMD; SvcMD != NULL; SvcMD = g_list_next(SvcMD)) { if (LASSO_IS_IDWSF2_DISCO_SVC_METADATA(SvcMD->data)) { lasso_list_add_gobject(discovery->metadatas, SvcMD->data); lasso_assign_new_string( LASSO_IDWSF2_DISCO_SVC_METADATA( SvcMD->data)->svcMDID, lasso_build_unique_id(32)); lasso_server_add_svc_metadata(LASSO_PROFILE(profile)->server, LASSO_IDWSF2_DISCO_SVC_METADATA(SvcMD->data)); } } } /* Build response */ response = lasso_idwsf2_disco_svc_md_register_response_new(); /* OK case */ if (rc == 0) { GList *SvcMDs; /* Return the allocated IDs */ response->Status = lasso_idwsf2_util_status_new_with_code(LASSO_DISCO_STATUS_CODE_OK, NULL); for (SvcMDs = discovery->metadatas; SvcMDs != NULL; SvcMDs = g_list_next(SvcMDs)) { lasso_list_add_string(response->SvcMDID, LASSO_IDWSF2_DISCO_SVC_METADATA(SvcMDs->data)->svcMDID); } /* KO case */ } else { /* Return a failed status, with a second level code for explanation */ response->Status = lasso_idwsf2_util_status_new_with_code(LASSO_DISCO_STATUS_CODE_FAILED, lasso_strerror(rc)); } lasso_assign_new_gobject(profile->soap_envelope_response, lasso_idwsf2_profile_build_soap_envelope(NULL, LASSO_PROVIDER(LASSO_PROFILE(profile)->server)->ProviderID)); if (LASSO_IS_SOAP_ENVELOPE(profile->soap_envelope_response)) { envelope = profile->soap_envelope_response; envelope->Body->any = g_list_append(envelope->Body->any, response); } else { rc = LASSO_SOAP_ERROR_MISSING_ENVELOPE; g_critical("soap_envelope_response is missing"); } return rc; } /** * lasso_idwsf2_discovery_process_metadata_register_response_msg: * @discovery: a #LassoIdWsf2Discovery * @message: received metadata register soap response * * Process received metadata register response. * Check response status code. * If successful, save into @discovery->svcMDID the service metadata identifier * found in the response. * * Return value: 0 on success; or a negative value otherwise. **/ gint lasso_idwsf2_discovery_process_metadata_register_response_msg(LassoIdWsf2Discovery *discovery, const gchar *message) { LassoIdWsf2Profile *profile; LassoIdWsf2DiscoSvcMDRegisterResponse *response; int rc = 0; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); profile = LASSO_IDWSF2_PROFILE(discovery); g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); /* Process response */ rc = lasso_idwsf2_profile_process_soap_response_msg(profile, message); if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_REGISTER_RESPONSE(LASSO_PROFILE(profile)->response)) { rc = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; } /* If the response has been correctly processed, */ /* put interesting data into the discovery object */ if (rc == 0) { response = LASSO_IDWSF2_DISCO_SVC_MD_REGISTER_RESPONSE( LASSO_PROFILE(profile)->response); if (response->SvcMDID != NULL) { lasso_assign_list_of_strings(discovery->svcMDIDs, response->SvcMDID); } else { rc = LASSO_DISCOVERY_ERROR_SVC_METADATA_REGISTER_FAILED; } } return rc; } /** * lasso_idwsf2_discovery_init_metadata_association_add: * @discovery: a #LassoIdWsf2Discovery * @svcMDID: identifier of the service metadata the user wants to associate with * * Initialise a request to associate a user account to a service metadata, allowing * a WSC to request this service for data related to this user account. * * Return value: 0 on success; or a negative value otherwise. **/ gint lasso_idwsf2_discovery_init_metadata_association_add(LassoIdWsf2Discovery *discovery, const gchar *svcMDID) { LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); LassoSession *session = LASSO_PROFILE(profile)->session; LassoIdWsf2DiscoSvcMDAssociationAdd *md_association_add; LassoWsAddrEndpointReference *epr; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); g_return_val_if_fail(svcMDID != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); g_return_val_if_fail(LASSO_IS_SESSION(session), LASSO_PROFILE_ERROR_SESSION_NOT_FOUND); /* Build a MetadataRegister node */ md_association_add = lasso_idwsf2_disco_svc_md_association_add_new(); md_association_add->SvcMDID = g_list_append(md_association_add->SvcMDID, g_strdup(svcMDID)); /* Create a request with this xml node */ lasso_idwsf2_profile_init_soap_request(profile, LASSO_NODE(md_association_add), LASSO_IDWSF2_DISCO_HREF); epr = lasso_session_get_endpoint_reference(session, LASSO_IDWSF2_DISCO_HREF); if (epr != NULL) { LASSO_PROFILE(profile)->msg_url = g_strdup(epr->Address->content); } return 0; } /** * lasso_idwsf2_discovery_process_metadata_association_add_msg: * @discovery: a #LassoIdWsf2Discovery * @message: received metadata association add soap request * * Process received metadata association add request. * * Return value: 0 on success; or a negative value otherwise. **/ gint lasso_idwsf2_discovery_process_metadata_association_add_msg(LassoIdWsf2Discovery *discovery, const gchar *message) { LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); LassoIdWsf2DiscoSvcMDAssociationAddResponse *response; LassoSoapEnvelope *envelope; int res = 0; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); /* Process request */ res = lasso_idwsf2_profile_process_soap_request_msg(profile, message); if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD(LASSO_PROFILE(profile)->request)) { res = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; } /* Build response */ response = lasso_idwsf2_disco_svc_md_association_add_response_new(); envelope = profile->soap_envelope_response; envelope->Body->any = g_list_append(envelope->Body->any, response); lasso_assign_gobject(LASSO_PROFILE(profile)->response, LASSO_NODE(response)); return res; } /** * lasso_idwsf2_discovery_register_metadata: * @discovery: a #LassoIdWsf2Discovery * * Add service metadata identifier into user identity object. * * Return value: 0 on success; or a negative value otherwise. **/ gint lasso_idwsf2_discovery_register_metadata(LassoIdWsf2Discovery *discovery) { LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); LassoIdWsf2DiscoSvcMDAssociationAdd *request; LassoIdWsf2DiscoSvcMDAssociationAddResponse *response; LassoIdentity *identity; GList *i; int res = 0; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); /* verify if identity already exists else create it */ if (LASSO_PROFILE(profile)->identity == NULL) { LASSO_PROFILE(profile)->identity = lasso_identity_new(); } identity = LASSO_PROFILE(profile)->identity; if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD(LASSO_PROFILE(profile)->request)) { res = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; } else if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD_RESPONSE( LASSO_PROFILE(profile)->response)) { res = LASSO_PROFILE_ERROR_MISSING_RESPONSE; } /* If the request has been correctly processed, */ /* put interesting data into the discovery object */ request = LASSO_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD(LASSO_PROFILE(profile)->request); /* Copy the service metadatas with given svcMDIDs into the identity object */ for (i = g_list_first(request->SvcMDID); i != NULL; i = g_list_next(i)) { lasso_identity_add_svc_md_id(identity, (gchar *)(i->data)); } /* Set response status code */ response = LASSO_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD_RESPONSE( LASSO_PROFILE(profile)->response); if (res == 0) { response->Status = lasso_idwsf2_util_status_new(); response->Status->code = g_strdup(LASSO_DISCO_STATUS_CODE_OK); } else { response->Status = lasso_idwsf2_util_status_new(); response->Status->code = g_strdup(LASSO_DISCO_STATUS_CODE_FAILED); } return res; } /** * lasso_idwsf2_discovery_process_metadata_association_add_response_msg: * @discovery: a #LassoIdWsf2Discovery * @message: received metadata association add soap response * * Process received metadata association add response. * Check response status code. * * Return value: 0 on success; or a negative value otherwise. **/ gint lasso_idwsf2_discovery_process_metadata_association_add_response_msg( LassoIdWsf2Discovery *discovery, const gchar *message) { LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); LassoIdWsf2DiscoSvcMDAssociationAddResponse *response; int res = 0; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); /* Process response */ res = lasso_idwsf2_profile_process_soap_response_msg(profile, message); if (res != 0) { return res; } if (! LASSO_IS_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD_RESPONSE( LASSO_PROFILE(profile)->response)) { return LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; } /* Check response status code */ response = LASSO_IDWSF2_DISCO_SVC_MD_ASSOCIATION_ADD_RESPONSE( LASSO_PROFILE(profile)->response); if (response->Status == NULL || response->Status->code == NULL) { return LASSO_PROFILE_ERROR_MISSING_STATUS_CODE; } if (strcmp(response->Status->code, LASSO_DISCO_STATUS_CODE_OK) != 0) { return LASSO_DISCOVERY_ERROR_SVC_METADATA_ASSOCIATION_ADD_FAILED; } return 0; } /** * lasso_idwsf2_discovery_init_query * @discovery: a #LassoIdWsf2Discovery * @security_mech_id: obsolete ; can be NULL * * Initialise a request for ID-WSF discovery Query to a discovery service. * * Return value: 0 on success; or a negative value otherwise. **/ gint lasso_idwsf2_discovery_init_query(LassoIdWsf2Discovery *discovery, G_GNUC_UNUSED const gchar *security_mech_id) { /* FIXME: add support of security mechanims */ LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); LassoSession *session = LASSO_PROFILE(profile)->session; LassoWsAddrEndpointReference *epr; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); g_return_val_if_fail(LASSO_IS_SESSION(session), LASSO_PROFILE_ERROR_SESSION_NOT_FOUND); lasso_assign_new_gobject(LASSO_PROFILE(profile)->request, (LassoNode*)lasso_idwsf2_disco_query_new()); lasso_idwsf2_profile_init_soap_request(profile, LASSO_PROFILE(profile)->request, LASSO_IDWSF2_DISCO_HREF); epr = lasso_session_get_endpoint_reference(session, LASSO_IDWSF2_DISCO_HREF); if (epr != NULL) { LASSO_PROFILE(profile)->msg_url = g_strdup(epr->Address->content); } return 0; } /** * lasso_idwsf2_discovery_add_requested_service_type * @discovery: a #LassoIdWsf2Discovery * @service_type: the service type (or data profile) requested * * Select the requested service type which will be queried. * * Return value: 0 on success; or a negative value otherwise. **/ gint lasso_idwsf2_discovery_add_requested_service_type(LassoIdWsf2Discovery *discovery, const gchar *service_type) { LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); LassoIdWsf2DiscoQuery *query; LassoIdWsf2DiscoRequestedService *service; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); g_return_val_if_fail(LASSO_IS_IDWSF2_DISCO_QUERY(LASSO_PROFILE(profile)->request), LASSO_PROFILE_ERROR_MISSING_REQUEST); query = LASSO_IDWSF2_DISCO_QUERY(LASSO_PROFILE(profile)->request); service = lasso_idwsf2_disco_requested_service_new(); service->ServiceType = g_list_append(service->ServiceType, g_strdup(service_type)); query->RequestedService = g_list_append(query->RequestedService, service); return 0; } /** * lasso_idwsf2_discovery_process_query_msg: * @discovery: a #LassoIdWsf2Discovery * @message: received query soap request * * Process received query request. * * Return value: 0 on success; or a negative value otherwise. **/ gint lasso_idwsf2_discovery_process_query_msg(LassoIdWsf2Discovery *discovery, const gchar *message) { LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); int res = 0; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); /* Process request */ res = lasso_idwsf2_profile_process_soap_request_msg(profile, message); if (! LASSO_IS_IDWSF2_DISCO_QUERY(LASSO_PROFILE(profile)->request)) { res = LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; } return res; } /** * lasso_idwsf2_discovery_build_epr: * @service: a #LassoIdWsf2DiscoRequestedService containing the query criteria * @identity: a #LassoIdentity of the current user * @server: current #LassoServer * * Build an EndpointReference (EPR) which contains all the information about a WSP providing * the requested service type and matching other query criteria to allow a WSC to request it. * * Return value: the newly built EPR; or NULL if no WSP match the query criteria. **/ static LassoWsAddrEndpointReference* lasso_idwsf2_discovery_build_epr(LassoIdWsf2DiscoRequestedService *service, LassoIdentity *identity, LassoServer *server) { gchar *service_type = NULL; GList *svcMDIDs; GList *svcMDs; LassoIdWsf2DiscoSvcMetadata *svcMD; LassoWsAddrEndpointReference *epr; LassoWsAddrMetadata *metadata; LassoIdWsf2DiscoSecurityContext *security_context; LassoIdWsf2SecToken *sec_token; LassoSaml2Assertion *assertion; LassoSaml2Subject *subject; LassoFederation* federation; LassoProvider *provider; LassoSaml2EncryptedElement *encrypted_element; LassoIdWsf2DiscoEndpointContext *endpoint_context; LassoIdWsf2DiscoServiceContext *service_context; if (service != NULL && service->ServiceType != NULL && service->ServiceType->data != NULL) { service_type = (gchar *)service->ServiceType->data; } else { /* Can only search for service type at the moment */ return NULL; } svcMDIDs = lasso_identity_get_svc_md_ids(identity); svcMDs = lasso_server_get_svc_metadatas_with_id_and_type(server, svcMDIDs, service_type); if (svcMDs == NULL) { return NULL; } /* FIXME : foreach on the whole list and build an epr for each svcMD */ svcMD = svcMDs->data; if (svcMD == NULL || svcMD->ServiceContext == NULL || svcMD->ServiceContext->data == NULL) { g_list_foreach(svcMDs, (GFunc)lasso_node_destroy, NULL); g_list_free(svcMDs); return NULL; } /* Build EndpointReference */ epr = lasso_wsa_endpoint_reference_new(); service_context = LASSO_IDWSF2_DISCO_SERVICE_CONTEXT(svcMD->ServiceContext->data); endpoint_context = LASSO_IDWSF2_DISCO_ENDPOINT_CONTEXT( service_context->EndpointContext->data); /* XXX: there may be more than one endpoint context */ epr->Address = lasso_wsa_attributed_uri_new_with_string( (gchar*)endpoint_context->Address->data); metadata = lasso_wsa_metadata_new(); /* Abstract */ metadata->any = g_list_append(metadata->any, lasso_idwsf2_disco_abstract_new_with_string(svcMD->Abstract)); /* ProviderID */ metadata->any = g_list_append(metadata->any, lasso_idwsf2_disco_provider_id_new_with_string(svcMD->ProviderID)); /* ServiceType */ metadata->any = g_list_append(metadata->any, lasso_idwsf2_disco_service_type_new_with_string( (char*)service_context->ServiceType->data)); /* Framework */ if (endpoint_context->Framework != NULL) { metadata->any = g_list_append(metadata->any, g_object_ref((GObject*)endpoint_context->Framework->data)); } /* Identity token */ federation = lasso_identity_get_federation(identity, svcMD->ProviderID); if (federation != NULL) { assertion = LASSO_SAML2_ASSERTION(lasso_saml2_assertion_new()); /* Identity token Subject */ subject = LASSO_SAML2_SUBJECT(lasso_saml2_subject_new()); if (federation->remote_nameIdentifier != NULL) { subject->NameID = g_object_ref(federation->remote_nameIdentifier); } else { subject->NameID = g_object_ref(federation->local_nameIdentifier); } assertion->Subject = subject; /* Encrypt NameID */ provider = g_hash_table_lookup(server->providers, svcMD->ProviderID); if (provider && provider->private_data->encryption_mode & LASSO_ENCRYPTION_MODE_NAMEID && provider->private_data->encryption_public_key != NULL) { encrypted_element = LASSO_SAML2_ENCRYPTED_ELEMENT(lasso_node_encrypt( LASSO_NODE(assertion->Subject->NameID), provider->private_data->encryption_public_key, provider->private_data->encryption_sym_key_type)); if (encrypted_element != NULL) { assertion->Subject->EncryptedID = encrypted_element; lasso_release_gobject(assertion->Subject->NameID); } else { /** FIXME: find a return value for this case */ } } sec_token = LASSO_IDWSF2_SEC_TOKEN(lasso_idwsf2_sec_token_new()); sec_token->any = LASSO_NODE(assertion); security_context = LASSO_IDWSF2_DISCO_SECURITY_CONTEXT( lasso_idwsf2_disco_security_context_new()); security_context->SecurityMechID = g_list_append( security_context->SecurityMechID, g_strdup(LASSO_SECURITY_MECH_TLS_BEARER)); security_context->Token = g_list_append(security_context->Token, sec_token); metadata->any = g_list_append(metadata->any, security_context); } epr->Metadata = metadata; /* Free resources */ g_list_foreach(svcMDs, (GFunc)lasso_node_destroy, NULL); g_list_free(svcMDs); return epr; } /** * lasso_idwsf2_discovery_build_query_response_eprs: * @discovery: a #LassoIdWsf2Discovery * * Build a query response containing one or more EndpointReference (EPR) for each WSP providing * the requested service type and matching other query criteria to allow a WSC to request them. * * Return value: 0 on success; or a negative value otherwise. **/ gint lasso_idwsf2_discovery_build_query_response_eprs(LassoIdWsf2Discovery *discovery) { LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); LassoIdentity *identity = LASSO_PROFILE(profile)->identity; LassoServer *server = LASSO_PROFILE(profile)->server; LassoIdWsf2DiscoQuery* request; LassoIdWsf2DiscoRequestedService *service = NULL; LassoIdWsf2DiscoQueryResponse *response; LassoWsAddrEndpointReference *epr; LassoSoapEnvelope *envelope; int res = 0; if (! LASSO_IS_IDWSF2_DISCO_QUERY(LASSO_PROFILE(profile)->request)) { res = LASSO_PROFILE_ERROR_MISSING_REQUEST; } else if (! LASSO_IS_IDENTITY(identity)) { res = LASSO_PROFILE_ERROR_IDENTITY_NOT_FOUND; } if (res == 0) { request = LASSO_IDWSF2_DISCO_QUERY(LASSO_PROFILE(profile)->request); /* FIXME : foreach on the list instead */ if (request->RequestedService != NULL) { service = LASSO_IDWSF2_DISCO_REQUESTED_SERVICE( request->RequestedService->data); } if (service == NULL) { res = LASSO_DISCOVERY_ERROR_MISSING_REQUESTED_SERVICE; } } /* Build response */ response = lasso_idwsf2_disco_query_response_new(); if (res == 0) { /* FIXME : foreach here as well */ epr = lasso_idwsf2_discovery_build_epr(service, identity, server); if (epr != NULL) { response->EndpointReference = g_list_append(response->EndpointReference, epr); /* XXX : Should probably check if the epr contains a SecurityContext, */ /* otherwise return a "federation not found" error code */ } else { res = LASSO_DISCOVERY_ERROR_FAILED_TO_BUILD_ENDPOINT_REFERENCE; } } /* Set response status code */ if (res == 0) { response->Status = lasso_idwsf2_util_status_new(); response->Status->code = g_strdup(LASSO_DISCO_STATUS_CODE_OK); } else { response->Status = lasso_idwsf2_util_status_new(); response->Status->code = g_strdup(LASSO_DISCO_STATUS_CODE_FAILED); /* XXX : May add secondary status codes here */ } envelope = profile->soap_envelope_response; envelope->Body->any = g_list_append(envelope->Body->any, response); return res; } /** * lasso_idwsf2_discovery_process_query_response_msg: * @discovery: a #LassoIdWsf2Discovery * @message: received query soap response * * Process received query response. * Copy returned EPRs into session object. * Check response status code. * * Return value: 0 on success; or a negative value otherwise. **/ gint lasso_idwsf2_discovery_process_query_response_msg(LassoIdWsf2Discovery *discovery, const gchar *message) { LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); LassoSession *session = LASSO_PROFILE(profile)->session; LassoIdWsf2DiscoQueryResponse *response; int res = 0; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE); g_return_val_if_fail(LASSO_IS_SESSION(session), LASSO_PROFILE_ERROR_SESSION_NOT_FOUND); /* Process request */ res = lasso_idwsf2_profile_process_soap_response_msg(profile, message); if (res != 0) { return res; } if (! LASSO_IS_IDWSF2_DISCO_QUERY_RESPONSE(LASSO_PROFILE(profile)->response)) { return LASSO_PROFILE_ERROR_INVALID_SOAP_MSG; } /* Check response status code */ response = LASSO_IDWSF2_DISCO_QUERY_RESPONSE(LASSO_PROFILE(profile)->response); if (response->Status == NULL || response->Status->code == NULL) { return LASSO_PROFILE_ERROR_MISSING_STATUS_CODE; } if (strcmp(response->Status->code, LASSO_DISCO_STATUS_CODE_OK) != 0) { return LASSO_DISCOVERY_ERROR_SVC_METADATA_ASSOCIATION_ADD_FAILED; } /* If the response has been correctly processed, */ /* put interesting data into the discovery object */ response = LASSO_IDWSF2_DISCO_QUERY_RESPONSE(LASSO_PROFILE(profile)->response); /* FIXME : foreach on the list instead */ if (response->EndpointReference != NULL && response->EndpointReference->data != NULL) { lasso_session_add_endpoint_reference(session, response->EndpointReference->data); } return 0; } /** * lasso_idwsf2_discovery_get_service: * @discovery: a #LassoIdWsf2Discovery * @service_type: the requested service type * * After a discovery query message, create a #LassoIdWsf2DataService instance for the * requested @service_type. * * Return value: a newly created #LassoIdWsf2DataService object; or NULL if an error occured. **/ LassoIdWsf2DataService* lasso_idwsf2_discovery_get_service(LassoIdWsf2Discovery *discovery, G_GNUC_UNUSED const gchar *service_type) { /* FIXME: service_type is unused, should we remove it from public API ? */ LassoIdWsf2Profile *profile = LASSO_IDWSF2_PROFILE(discovery); LassoIdWsf2DiscoQueryResponse *response; LassoWsAddrEndpointReference *epr = NULL; LassoIdWsf2DataService *service; g_return_val_if_fail(LASSO_IS_IDWSF2_DISCOVERY(discovery), NULL); g_return_val_if_fail(LASSO_IS_IDWSF2_DISCO_QUERY_RESPONSE( LASSO_PROFILE(profile)->response), NULL); response = LASSO_IDWSF2_DISCO_QUERY_RESPONSE(LASSO_PROFILE(profile)->response); /* FIXME : foreach on the list instead */ if (response->EndpointReference != NULL && response->EndpointReference->data != NULL) { epr = LASSO_WSA_ENDPOINT_REFERENCE(response->EndpointReference->data); } else { return NULL; } service = lasso_idwsf2_data_service_new_full(LASSO_PROFILE(profile)->server, epr); lasso_assign_gobject(LASSO_PROFILE(service)->session, LASSO_PROFILE(profile)->session); return service; } /*****************************************************************************/ /* private methods */ /*****************************************************************************/ static LassoNodeClass *parent_class = NULL; static xmlNode* get_xmlNode(LassoNode *node, gboolean lasso_dump) { xmlNode *xmlnode; xmlnode = parent_class->get_xmlNode(node, lasso_dump); xmlNodeSetName(xmlnode, (xmlChar*)"Discovery"); xmlSetProp(xmlnode, (xmlChar*)"DiscoveryDumpVersion", (xmlChar*)"2"); return xmlnode; } /*****************************************************************************/ /* overrided parent class methods */ /*****************************************************************************/ static void dispose(GObject *object) { LassoIdWsf2Discovery *discovery = LASSO_IDWSF2_DISCOVERY(object); if (discovery->private_data->dispose_has_run == TRUE) return; discovery->private_data->dispose_has_run = TRUE; G_OBJECT_CLASS(parent_class)->dispose(object); } static void finalize(GObject *object) { LassoIdWsf2Discovery *discovery = LASSO_IDWSF2_DISCOVERY(object); g_free(discovery->private_data); discovery->private_data = NULL; G_OBJECT_CLASS(parent_class)->finalize(object); } /*****************************************************************************/ /* instance and class init functions */ /*****************************************************************************/ static void instance_init(LassoIdWsf2Discovery *discovery) { discovery->private_data = g_new0(LassoIdWsf2DiscoveryPrivate, 1); discovery->private_data->dispose_has_run = FALSE; } static void class_init(LassoIdWsf2DiscoveryClass *klass) { parent_class = g_type_class_peek_parent(klass); LASSO_NODE_CLASS(klass)->get_xmlNode = get_xmlNode; G_OBJECT_CLASS(klass)->dispose = dispose; G_OBJECT_CLASS(klass)->finalize = finalize; } GType lasso_idwsf2_discovery_get_type() { static GType this_type = 0; if (!this_type) { static const GTypeInfo this_info = { sizeof(LassoIdWsf2DiscoveryClass), NULL, NULL, (GClassInitFunc) class_init, NULL, NULL, sizeof(LassoIdWsf2Discovery), 0, (GInstanceInitFunc) instance_init, NULL }; this_type = g_type_register_static(LASSO_TYPE_IDWSF2_PROFILE, "LassoIdWsf2Discovery", &this_info, 0); } return this_type; } /** * lasso_idwsf2_discovery_new: * @server: the #LassoServer * * Create a new #LassoIdWsf2Discovery. * * Return value: a newly created #LassoIdWsf2Discovery object; or NULL if an error occured. **/ LassoIdWsf2Discovery* lasso_idwsf2_discovery_new(LassoServer *server) { LassoIdWsf2Discovery *discovery = NULL; g_return_val_if_fail(LASSO_IS_SERVER(server), NULL); discovery = g_object_new(LASSO_TYPE_IDWSF2_DISCOVERY, NULL); LASSO_PROFILE(discovery)->server = g_object_ref(server); return discovery; }