1350 lines
42 KiB
C
1350 lines
42 KiB
C
/* $Id$
|
|
*
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:discovery
|
|
* @short_description: ID-WSF 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.
|
|
*
|
|
* The following example is a service provider asking for a "PP" service (an
|
|
* attribute provider for the "Personal Profile"):
|
|
*
|
|
* <informalexample>
|
|
* <programlisting>
|
|
* LassoServer *server; // initialized before
|
|
* char* session_dump; // initialized before
|
|
*
|
|
* LassoDiscovery *discovery; // discovery service
|
|
* char *soap_answer; // SOAP answer from disco service
|
|
* LassoProfileService *service; // instance to perform on requested service
|
|
*
|
|
* discovery = lasso_discovery_new(server);
|
|
* lasso_wsf_profile_set_session_from_dump(LASSO_WSF_PROFILE(discovery), session_dump);
|
|
* lasso_discovery_init_query(discovery);
|
|
* lasso_discovery_add_requested_service(discovery, LASSO_PP10_HREF);
|
|
* lasso_discovery_build_request_msg(discovery);
|
|
*
|
|
* // service must perform SOAP call to LASSO_WSF_PROFILE(discovery)->msg_url
|
|
* // the SOAP message is LASSO_WSF_PROFILE(discovery)->msg_body. The answer
|
|
* // is stored in char* soap_answer;
|
|
*
|
|
* lasso_discovery_process_query_response_msg(discovery, soap_answer);
|
|
*
|
|
* // get an object to access the first service returned, or NULL if an error happened
|
|
* service = lasso_discovery_get_service(discovery);
|
|
* </programlisting>
|
|
* </informalexample>
|
|
*
|
|
*/
|
|
|
|
#include "../xml/private.h"
|
|
#include <libxml/xpath.h>
|
|
#include <libxml/xpathInternals.h>
|
|
|
|
#include <xmlsec/xmltree.h>
|
|
|
|
#include "../utils.h"
|
|
#include "../xml/soap_binding_correlation.h"
|
|
#include "../xml/saml_assertion.h"
|
|
#include "../xml/saml_attribute.h"
|
|
#include "../xml/saml_attribute_value.h"
|
|
#include "../xml/disco_modify.h"
|
|
#include "../xml/saml_assertion.h"
|
|
#include "../xml/idwsf_strings.h"
|
|
|
|
#include "../id-ff/server.h"
|
|
#include "../id-ff/provider.h"
|
|
#include "../id-ff/providerprivate.h"
|
|
#include "../id-ff/sessionprivate.h"
|
|
|
|
#include "id_wsf.h"
|
|
#include "wsf_profile_private.h"
|
|
#include "wsf_utils.h"
|
|
#include "../utils.h"
|
|
#include "discovery.h"
|
|
|
|
struct _LassoDiscoveryPrivate
|
|
{
|
|
gboolean dispose_has_run;
|
|
GList *new_entry_ids;
|
|
char *security_mech_id;
|
|
};
|
|
|
|
#define assign_resource_id(from,to) \
|
|
if ((from)->ResourceID) {\
|
|
lasso_assign_gobject((to)->ResourceID, (from)->ResourceID); \
|
|
} else if ((from)->EncryptedResourceID) {\
|
|
lasso_assign_gobject((to)->EncryptedResourceID, (from)->EncryptedResourceID); \
|
|
} else { \
|
|
rc = LASSO_WSF_PROFILE_ERROR_MISSING_RESOURCE_ID;\
|
|
goto_cleanup_if_fail(0); \
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* static methods/functions */
|
|
/*****************************************************************************/
|
|
|
|
static gchar* lasso_discovery_build_credential(LassoDiscovery *discovery, const gchar *providerId);
|
|
static LassoWsfProfile *lasso_discovery_build_wsf_profile(LassoDiscovery *discovery,
|
|
LassoDiscoResourceOffering *offering);
|
|
static LassoWsfProfileConstructor lookup_registry(gchar const *service_type);
|
|
static void remove_registry(gchar const *service_type);
|
|
static void set_registry(gchar const *service_type, LassoWsfProfileConstructor constructor);
|
|
static LassoDsKeyInfo* lasso_discovery_build_key_info_node(LassoDiscovery *discovery,
|
|
const gchar *providerID);
|
|
static LassoDiscoResourceOffering* lasso_discovery_get_resource_offering_auto(
|
|
LassoDiscovery *discovery, const gchar *service_type);
|
|
static gint lasso_discovery_init_resource_offering(LassoDiscovery *discovery,
|
|
const gchar *security_mech_id, LassoDiscoResourceOffering **output_offering);
|
|
static gint lasso_discovery_process_modify_msg(LassoDiscovery *discovery);
|
|
static gint lasso_discovery_process_query_msg(LassoDiscovery *discovery);
|
|
static gint lasso_discovery_build_query_response_msg(LassoDiscovery *discovery);
|
|
static gint lasso_discovery_build_modify_response_msg(LassoDiscovery *discovery);
|
|
|
|
/**
|
|
* lasso_discovery_add_insert_entry:
|
|
* @discovery: a #LassoDiscovery object
|
|
* @serviceInstance: an optional #LassoDiscoServiceInstance object
|
|
* @resourceID: the new #LassoDiscoResourceID used to create the #LassoDiscoResrouceOffering
|
|
*
|
|
* Add an #LassoDiscoInsertEntry containing a new #LassoDiscoResourceOffering, and initialize the
|
|
* #LassoDiscoResourceOffering using the #LassoDiscoServiceInstance and #LassoDiscoResourceId
|
|
* object.
|
|
*
|
|
* Return value: the newly created #LassoDiscoInsertEntry or NULL if some preconditions failed.
|
|
**/
|
|
gint
|
|
lasso_discovery_add_insert_entry(LassoDiscovery *discovery,
|
|
LassoDiscoServiceInstance *serviceInstance,
|
|
LassoDiscoResourceID *resourceId)
|
|
{
|
|
LassoDiscoModify *modify = NULL;
|
|
LassoDiscoInsertEntry *insertEntry = NULL;
|
|
LassoDiscoResourceOffering *resourceOffering = NULL;
|
|
int rc = 0;
|
|
|
|
lasso_bad_param(DISCOVERY, discovery);
|
|
lasso_bad_param(DISCO_SERVICE_INSTANCE, serviceInstance);
|
|
lasso_bad_param(DISCO_RESOURCE_ID, resourceId);
|
|
g_return_val_if_fail(LASSO_IS_DISCO_MODIFY(LASSO_WSF_PROFILE(discovery)->request), LASSO_PARAM_ERROR_NON_INITIALIZED_OBJECT);
|
|
|
|
lasso_extract_node_or_fail(modify, LASSO_WSF_PROFILE(discovery)->request, DISCO_MODIFY,
|
|
LASSO_PROFILE_ERROR_MISSING_REQUEST);
|
|
resourceOffering = lasso_disco_resource_offering_new(serviceInstance);
|
|
lasso_assign_gobject(resourceOffering->ResourceID, resourceId);
|
|
insertEntry = lasso_disco_insert_entry_new(resourceOffering);
|
|
lasso_list_add_gobject(modify->InsertEntry, insertEntry);
|
|
|
|
cleanup:
|
|
lasso_release_gobject(resourceOffering);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_add_remove_entry:
|
|
* @discovery: a #LassoDiscovery object
|
|
* @entryID: the idenitfier of a ResourceOffering to remove.
|
|
*
|
|
* Add a RemoveEntry to the current Modify message for a Discovery service,
|
|
* to remove the resource offering identified by entryID (returned in the
|
|
* response to a Modify/InsertEntry message).
|
|
*
|
|
* Return value: 0 if successful, an error code otherwise.
|
|
**/
|
|
gint
|
|
lasso_discovery_add_remove_entry(LassoDiscovery *discovery,
|
|
const gchar *entryID)
|
|
{
|
|
LassoDiscoModify *modify = NULL;
|
|
gint rc = 0;
|
|
|
|
lasso_bad_param(DISCOVERY, discovery);
|
|
lasso_null_param(entryID);
|
|
lasso_extract_node_or_fail(modify, LASSO_WSF_PROFILE(discovery)->request, DISCO_MODIFY,
|
|
LASSO_PROFILE_ERROR_MISSING_REQUEST);
|
|
|
|
lasso_list_add_new_gobject(modify->RemoveEntry, lasso_disco_remove_entry_new(entryID));
|
|
|
|
cleanup:
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_add_requested_service_type:
|
|
* @discovery: a #LassoDiscovery
|
|
* @service_type: requested service type
|
|
* @option: option to the requested service
|
|
*
|
|
* Adds a request for service of @service_type to the disco:Query being built.
|
|
*
|
|
* Return value: 0 if successful
|
|
**/
|
|
gint
|
|
lasso_discovery_add_requested_service_type(LassoDiscovery *discovery,
|
|
const gchar *service_type,
|
|
const gchar *option)
|
|
{
|
|
LassoDiscoRequestedServiceType *rst = NULL;
|
|
LassoDiscoOptions *opts = NULL;
|
|
LassoDiscoQuery *query = NULL;
|
|
gint rc = 0;
|
|
|
|
lasso_bad_param(DISCOVERY, discovery);
|
|
lasso_null_param(service_type);
|
|
lasso_extract_node_or_fail(query, LASSO_WSF_PROFILE(discovery)->request, DISCO_QUERY,
|
|
LASSO_PARAM_ERROR_NON_INITIALIZED_OBJECT);
|
|
|
|
rst = lasso_disco_requested_service_type_new(service_type);
|
|
if (option != NULL) {
|
|
opts = lasso_disco_options_new();
|
|
lasso_list_add_string(opts->Option, option);
|
|
lasso_assign_new_gobject(rst->Options, opts);
|
|
}
|
|
lasso_list_add_new_gobject(query->RequestedServiceType, rst);
|
|
|
|
cleanup:
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_init_query
|
|
* @discovery: a #LassoDiscovery
|
|
* @security_mech_id: (allow-none): identifier of a wished security mechanism, or NULL if any is ok
|
|
*
|
|
* Initializes a disco:Query message.
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
gint
|
|
lasso_discovery_init_query(LassoDiscovery *discovery, const gchar *security_mech_id)
|
|
{
|
|
LassoWsfProfile *profile = NULL;
|
|
LassoDiscoQuery *query = NULL;
|
|
LassoDiscoResourceOffering *offering = NULL;
|
|
gint rc = 0;
|
|
|
|
lasso_bad_param(DISCOVERY, discovery);
|
|
|
|
profile = &discovery->parent;
|
|
/* 1. Get an offering */
|
|
rc = lasso_discovery_init_resource_offering(discovery, security_mech_id, &offering);
|
|
goto_cleanup_if_fail(! rc);
|
|
|
|
/* 2. Create SOAP envelope and set profile->request */
|
|
query = lasso_disco_query_new();
|
|
lasso_wsf_profile_init_soap_request(profile, LASSO_NODE(query));
|
|
assign_resource_id(offering, query);
|
|
|
|
cleanup:
|
|
lasso_release_gobject(query);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_init_modify:
|
|
* @discovery: a #LassoDiscovery
|
|
* @security_mech_id: (allow-none): the security mechanism identifier
|
|
*
|
|
* Initializes a disco Modify/InsertEntry
|
|
*
|
|
* Return value: 0 on success; an error code otherwise.
|
|
**/
|
|
gint
|
|
lasso_discovery_init_modify(LassoDiscovery *discovery,
|
|
const char *security_mech_id)
|
|
{
|
|
LassoWsfProfile *profile = NULL;
|
|
LassoDiscoModify *modify = NULL;
|
|
LassoDiscoResourceOffering *offering = NULL;
|
|
gint rc = 0;
|
|
|
|
lasso_bad_param(DISCOVERY, discovery);
|
|
|
|
profile = &discovery->parent;
|
|
/* 1. Get an offering */
|
|
rc = lasso_discovery_init_resource_offering(discovery, security_mech_id, &offering);
|
|
goto_cleanup_if_fail (! rc);
|
|
|
|
/* 2. Set message content */
|
|
modify = lasso_disco_modify_new();
|
|
assign_resource_id(offering, modify);
|
|
lasso_wsf_profile_init_soap_request(profile, LASSO_NODE(modify));
|
|
cleanup:
|
|
lasso_release_gobject(modify);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_process_request_msg:
|
|
* @discovery: a #LassoDiscovery object
|
|
* @message: a serialized SOAP message
|
|
* @security_mech_id: (allow-none): the security mech id to use for validating authorizations
|
|
*
|
|
* Process a received SOAP message for the discovery service.
|
|
*
|
|
* Return value: 0 if successfull, an error code otherwise.
|
|
*/
|
|
gint
|
|
lasso_discovery_process_request_msg(LassoDiscovery *discovery, const gchar *message,
|
|
const gchar *security_mech_id)
|
|
{
|
|
gint rc = 0;
|
|
LassoWsfProfile *profile = NULL;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
|
|
profile = LASSO_WSF_PROFILE(discovery);
|
|
rc = lasso_wsf_profile_process_soap_request_msg(profile, message,
|
|
security_mech_id);
|
|
if (rc) {
|
|
return rc;
|
|
}
|
|
if (LASSO_IS_DISCO_MODIFY(profile->request)) {
|
|
return lasso_discovery_process_modify_msg(discovery);
|
|
} else if (LASSO_IS_DISCO_QUERY(profile->request)) {
|
|
return lasso_discovery_process_query_msg(discovery);
|
|
} else {
|
|
return LASSO_PROFILE_ERROR_INVALID_MSG;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_build_modify_response_msg:
|
|
* @discovery: a #LassoDiscovery
|
|
*
|
|
* Builds a disco:ModifyResponse message; answer to the disco:Modify passed
|
|
* to lasso_discovery_process_modify_msg(). It inserts and removed
|
|
* ResourceOfferings from identity; it must be saved afterwards.
|
|
*
|
|
* Sets @msg_body to the SOAP answer.
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
static gint
|
|
lasso_discovery_build_modify_response_msg(LassoDiscovery *discovery)
|
|
{
|
|
/* FIXME: Check all error cases, set the right status code,
|
|
and don't return without building a response, and
|
|
ensure atomicity, everything fails or everythig succeed. */
|
|
|
|
LassoWsfProfile *profile = NULL;
|
|
LassoDiscoModify *request = NULL;
|
|
LassoDiscoModifyResponse *response = NULL;
|
|
LassoUtilityStatus *status = NULL;
|
|
LassoDiscoRemoveEntry *remove_entry = NULL;
|
|
LassoDiscoInsertEntry *insert_entry = NULL;
|
|
char *new_entry_ids = NULL;
|
|
char *t_new_entry_ids = NULL;
|
|
GList *iter = NULL;
|
|
int res = 0;
|
|
int res2 = 0;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
|
|
profile = LASSO_WSF_PROFILE(discovery);
|
|
request = LASSO_DISCO_MODIFY(profile->request);
|
|
response = LASSO_DISCO_MODIFY_RESPONSE(profile->response);
|
|
|
|
if (profile->identity == NULL) {
|
|
return LASSO_PROFILE_ERROR_IDENTITY_NOT_FOUND;
|
|
}
|
|
|
|
/* First verify remove entries are all ok */
|
|
for (iter = request->RemoveEntry; iter != NULL; iter = g_list_next(iter)) {
|
|
if (! LASSO_IS_DISCO_REMOVE_ENTRY(iter->data)) {
|
|
continue;
|
|
}
|
|
remove_entry = LASSO_DISCO_REMOVE_ENTRY(iter->data);
|
|
|
|
if (! lasso_identity_get_resource_offering(profile->identity,
|
|
remove_entry->entryID)) {
|
|
res = LASSO_PROFILE_ERROR_MISSING_RESOURCE_OFFERING;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Then remove the entries */
|
|
if (res == 0) {
|
|
for (iter = request->RemoveEntry; iter != NULL; iter = g_list_next(iter)) {
|
|
remove_entry = LASSO_DISCO_REMOVE_ENTRY(iter->data);
|
|
if (! lasso_identity_remove_resource_offering(profile->identity,
|
|
remove_entry->entryID)) {
|
|
/* Set the right error code */
|
|
res = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (request->InsertEntry) {
|
|
new_entry_ids = g_malloc(10 * g_list_length(request->InsertEntry));
|
|
t_new_entry_ids = new_entry_ids;
|
|
}
|
|
|
|
for (iter = request->InsertEntry; iter != NULL; iter = g_list_next(iter)) {
|
|
if (! LASSO_IS_DISCO_INSERT_ENTRY(iter->data)) {
|
|
continue;
|
|
}
|
|
insert_entry = LASSO_DISCO_INSERT_ENTRY(iter->data);
|
|
|
|
lasso_identity_add_resource_offering(profile->identity,
|
|
insert_entry->ResourceOffering);
|
|
|
|
t_new_entry_ids = g_stpcpy(t_new_entry_ids,
|
|
insert_entry->ResourceOffering->entryID);
|
|
t_new_entry_ids = g_stpcpy(t_new_entry_ids, " ");
|
|
}
|
|
if (t_new_entry_ids) {
|
|
t_new_entry_ids[-1] = 0; /* remove trailing white space */
|
|
}
|
|
|
|
if (new_entry_ids) {
|
|
response->newEntryIDs = g_strdup(new_entry_ids);
|
|
lasso_release(new_entry_ids);
|
|
}
|
|
|
|
if (res != 0) {
|
|
lasso_assign_string(status->code, LASSO_DISCO_STATUS_CODE_FAILED);
|
|
}
|
|
|
|
res2 = lasso_wsf_profile_build_soap_response_msg(profile);
|
|
if (res != 0) {
|
|
return res;
|
|
} else {
|
|
return res2;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_process_modify_response_msg:
|
|
* @discovery: a #LassoDiscovery
|
|
* @message: the disco:ModifyResponse SOAP message
|
|
*
|
|
* Processes a disco:ModifyResponse SOAP message.
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
gint
|
|
lasso_discovery_process_modify_response_msg(LassoDiscovery *discovery, const gchar *message)
|
|
{
|
|
LassoWsfProfile *profile = NULL;
|
|
LassoDiscoModifyResponse *response = NULL;
|
|
int rc = 0;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
g_return_val_if_fail(message != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
|
|
|
|
profile = LASSO_WSF_PROFILE(discovery);
|
|
|
|
rc = lasso_wsf_profile_process_soap_response_msg(profile, message);
|
|
if (rc) {
|
|
return rc;
|
|
}
|
|
|
|
response = LASSO_DISCO_MODIFY_RESPONSE(profile->response);
|
|
|
|
if (strcmp(response->Status->code, LASSO_DISCO_STATUS_CODE_OK) != 0) {
|
|
return LASSO_PROFILE_ERROR_STATUS_NOT_SUCCESS;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_build_response_msg:
|
|
* @discovery: a #LassoDiscovery object
|
|
*
|
|
* Execute needed action for the received request, and produce a response message.
|
|
*
|
|
* If any critical error occur, it tries to produce a SOAP fault.
|
|
*
|
|
* Return value: 0 on success; or an error code otherwise.
|
|
*/
|
|
gint
|
|
lasso_discovery_build_response_msg(LassoDiscovery *discovery)
|
|
{
|
|
gint rc = LASSO_PROFILE_ERROR_INVALID_MSG;
|
|
LassoWsfProfile *profile = NULL;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
profile = &discovery->parent;
|
|
|
|
if (G_IS_OBJECT(profile->request)) {
|
|
|
|
if (LASSO_IS_DISCO_MODIFY(profile->request)) {
|
|
rc = lasso_discovery_build_modify_response_msg(discovery);
|
|
}
|
|
if (LASSO_IS_DISCO_QUERY(profile->request)) {
|
|
rc = lasso_discovery_build_query_response_msg(discovery);
|
|
}
|
|
}
|
|
if (rc < 0) {
|
|
rc = lasso_wsf_profile_build_soap_fault_response_msg(profile, rc);
|
|
}
|
|
rc = lasso_wsf_profile_build_soap_response_msg(profile);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_build_query_response_msg
|
|
* @discovery: a #LassoDiscovery
|
|
*
|
|
* Builds a disco:QueryResponse message; answer to the disco:Query passed to
|
|
* lasso_discovery_process_query_msg(). It looks up resource offerings in the
|
|
* principal identity and extracts those of the requested service type.
|
|
*
|
|
* Sets @msg_body to the SOAP answer.
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
static gint
|
|
lasso_discovery_build_query_response_msg(LassoDiscovery *discovery)
|
|
{
|
|
LassoWsfProfile *profile = NULL;
|
|
LassoDiscoQuery *request = NULL;
|
|
LassoDiscoQueryResponse *response = NULL;
|
|
LassoSoapEnvelope *envelope = NULL;
|
|
LassoSoapFault *fault = NULL;
|
|
GList *offerings = NULL;
|
|
GList *iter = NULL;
|
|
GList *iter2 = NULL;
|
|
GList *iter3 = NULL;
|
|
int res = 0;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
|
|
profile = LASSO_WSF_PROFILE(discovery);
|
|
request = LASSO_DISCO_QUERY(profile->request);
|
|
envelope = profile->soap_envelope_response;
|
|
response = LASSO_DISCO_QUERY_RESPONSE(profile->response);
|
|
|
|
if (profile->identity == NULL) {
|
|
fault = lasso_soap_fault_new();
|
|
fault->faultcode = LASSO_SOAP_FAULT_CODE_SERVER;
|
|
fault->faultstring = LASSO_SOAP_FAULT_STRING_IDENTITY_NOT_FOUND;
|
|
lasso_list_add_gobject(envelope->Body->any, fault);
|
|
return lasso_wsf_profile_build_soap_response_msg(profile);
|
|
}
|
|
|
|
iter = request->RequestedServiceType;
|
|
while (iter) {
|
|
LassoDiscoRequestedServiceType *service_type = iter->data;
|
|
iter = g_list_next(iter);
|
|
offerings = g_list_concat(offerings, lasso_identity_get_offerings(
|
|
profile->identity,
|
|
service_type->ServiceType));
|
|
}
|
|
|
|
/* build response */
|
|
response->ResourceOffering = offerings;
|
|
|
|
/* Add needed credentials for offerings */
|
|
iter = offerings;
|
|
while (iter) {
|
|
LassoDiscoResourceOffering *resource_offering = iter->data;
|
|
iter = g_list_next(iter);
|
|
iter2 = resource_offering->ServiceInstance->Description;
|
|
while (iter2) {
|
|
LassoDiscoDescription *description = LASSO_DISCO_DESCRIPTION(iter2->data);
|
|
iter3 = description->SecurityMechID;
|
|
while (iter3) {
|
|
if (lasso_security_mech_id_is_saml_authentication(
|
|
iter3->data) == TRUE) {
|
|
gchar *credentialRef = lasso_discovery_build_credential(
|
|
discovery, NULL);
|
|
lasso_list_add_new_string(description->CredentialRef, (void*)credentialRef);
|
|
}
|
|
iter3 = g_list_next(iter3);
|
|
}
|
|
iter2 = g_list_next(iter2);
|
|
}
|
|
}
|
|
|
|
res = lasso_wsf_profile_build_soap_response_msg(profile);
|
|
|
|
return res;
|
|
}
|
|
|
|
const char*
|
|
get_assertion_id(xmlNode *node) {
|
|
return (char*)xmlGetProp(node, (xmlChar*)"AssertionID");
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_process_query_response_msg:
|
|
* @discovery: a #LassoDiscovery
|
|
* @message: the disco:QueryResponse message
|
|
*
|
|
* Processes a disco:QueryResponse message.
|
|
* Extract credentials from the response and put them in the session,
|
|
* for later use by a request from a #LassoWsfProfile.
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
gint
|
|
lasso_discovery_process_query_response_msg(LassoDiscovery *discovery, const gchar *message)
|
|
{
|
|
LassoWsfProfile *profile = NULL;
|
|
LassoDiscoQueryResponse *response;
|
|
int rc = 0;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCOVERY(discovery),
|
|
LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
g_return_val_if_fail(message != NULL,
|
|
LASSO_PARAM_ERROR_INVALID_VALUE);
|
|
|
|
profile = LASSO_WSF_PROFILE(discovery);
|
|
rc = lasso_wsf_profile_process_soap_response_msg(profile, message);
|
|
if (rc)
|
|
goto cleanup;
|
|
response = LASSO_DISCO_QUERY_RESPONSE(profile->response);
|
|
if (strcmp(response->Status->code, LASSO_DISCO_STATUS_CODE_OK) != 0 &&
|
|
strcmp(response->Status->code, LASSO_DISCO_STATUS_CODE_DISCO_OK) != 0) {
|
|
return LASSO_PROFILE_ERROR_STATUS_NOT_SUCCESS;
|
|
}
|
|
/** Process the credentials, add them to the session */
|
|
if (response->Credentials) {
|
|
GList *assertions = response->Credentials->any;
|
|
for (; assertions; assertions = g_list_next(assertions)) {
|
|
xmlNode *assertion = (xmlNode*)assertions->data;
|
|
if (! (assertion->type == XML_ELEMENT_NODE &&
|
|
strcmp((char*)assertion->name, "Assertion") == 0)) {
|
|
continue;
|
|
}
|
|
if (profile->session) {
|
|
lasso_session_add_assertion_with_id(profile->session,
|
|
get_assertion_id(assertion),
|
|
assertion);
|
|
} else {
|
|
rc = LASSO_PROFILE_ERROR_SESSION_NOT_FOUND;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
}
|
|
cleanup:
|
|
return rc;
|
|
}
|
|
|
|
|
|
/**
|
|
* lasso_discovery_get_service:
|
|
* @discovery: a #LassoDiscovery
|
|
* @service_type: the requested service type
|
|
*
|
|
* After a disco:query message, creates a #LassoDataService instance for the
|
|
* requested @service_type with the first resource offering found or the first resource offering
|
|
* matching the service type.
|
|
*
|
|
* Return value:(transfer full)(allow-none): a newly created #LassoDataService object; or NULL if an
|
|
* error occured.
|
|
**/
|
|
LassoWsfProfile*
|
|
lasso_discovery_get_service(LassoDiscovery *discovery, const char *service_type)
|
|
{
|
|
LassoWsfProfile *profile = NULL;
|
|
LassoDiscoQueryResponse *response = NULL;
|
|
GList *iter = NULL;
|
|
LassoDiscoResourceOffering *offering = NULL;
|
|
LassoWsfProfile *service = NULL;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCOVERY(discovery), NULL);
|
|
profile = LASSO_WSF_PROFILE(discovery);
|
|
g_return_val_if_fail(LASSO_IS_DISCO_QUERY_RESPONSE(profile->response), NULL);
|
|
response = LASSO_DISCO_QUERY_RESPONSE(profile->response);
|
|
|
|
iter = response->ResourceOffering;
|
|
for (;iter; iter = g_list_next(iter)) {
|
|
LassoDiscoResourceOffering *t = iter->data;
|
|
|
|
if (! LASSO_IS_DISCO_RESOURCE_OFFERING(t)) {
|
|
continue;
|
|
}
|
|
if (t->ServiceInstance == NULL)
|
|
continue;
|
|
if (service_type == NULL || strcmp(t->ServiceInstance->ServiceType, service_type) == 0) {
|
|
offering = t;
|
|
break;
|
|
}
|
|
}
|
|
if (offering) {
|
|
service = lasso_discovery_build_wsf_profile(discovery, offering);
|
|
}
|
|
return service;
|
|
}
|
|
|
|
|
|
/**
|
|
* lasso_discovery_get_services:
|
|
* @discovery: a #LassoDiscovery
|
|
*
|
|
* After a disco:query message, creates a GList object of #LassoDataService.
|
|
*
|
|
* Return value:(transfer full)(element-type LassoNode): a newly created GList object of #LassoDataService;
|
|
* or NULL if an error occured.
|
|
**/
|
|
GList*
|
|
lasso_discovery_get_services(LassoDiscovery *discovery)
|
|
{
|
|
LassoWsfProfile *profile = NULL;
|
|
LassoDiscoQueryResponse *response;
|
|
GList *iter;
|
|
LassoDiscoResourceOffering *offering;
|
|
LassoWsfProfile *service;
|
|
GList *services = NULL;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCOVERY(discovery), NULL);
|
|
profile = LASSO_WSF_PROFILE(discovery);
|
|
goto_cleanup_if_fail(LASSO_IS_DISCO_QUERY_RESPONSE(profile->response));
|
|
response = LASSO_DISCO_QUERY_RESPONSE(profile->response);
|
|
|
|
iter = response->ResourceOffering;
|
|
while (iter) {
|
|
offering = iter->data;
|
|
iter = g_list_next(iter);
|
|
if (offering->ServiceInstance == NULL) {
|
|
continue;
|
|
}
|
|
service = lasso_discovery_build_wsf_profile(discovery, offering);
|
|
lasso_list_add_new_gobject(services, service);
|
|
}
|
|
|
|
cleanup:
|
|
return services;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_register_constructor_for_service_type:
|
|
* @service_type: the URI of the service type
|
|
* @constructor: a constructor function for the profile handling this service type
|
|
*
|
|
* This function permits to subclass of #LassoWsfProfile to register a
|
|
* constructor for the service type they supports.
|
|
*/
|
|
void
|
|
lasso_discovery_register_constructor_for_service_type(const gchar *service_type,
|
|
LassoWsfProfileConstructor constructor)
|
|
{
|
|
LassoWsfProfileConstructor old_constructor;
|
|
|
|
g_return_if_fail(service_type);
|
|
g_return_if_fail(constructor);
|
|
old_constructor = lookup_registry(service_type);
|
|
if (old_constructor) {
|
|
message(G_LOG_LEVEL_WARNING, "Service type already registered: %s", service_type);
|
|
return;
|
|
}
|
|
set_registry(service_type, constructor);
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_unregister_constructor_for_service_type:
|
|
* @service_type: the URI of the service type
|
|
* @constructor: a constructor function for the profile handling this service type
|
|
*
|
|
* This function permits to subclass of #LassoWsfProfile to unregister a
|
|
* constructor for the service type they previously registered using
|
|
* lasso_discovery_register_constructor_for_service_type().
|
|
*/
|
|
void
|
|
lasso_discovery_unregister_constructor_for_service_type(
|
|
gchar const *service_type,
|
|
LassoWsfProfileConstructor constructor) {
|
|
LassoWsfProfileConstructor old_constructor;
|
|
|
|
g_return_if_fail(service_type);
|
|
g_return_if_fail(constructor);
|
|
old_constructor = lookup_registry(service_type);
|
|
if (old_constructor != constructor) {
|
|
message(G_LOG_LEVEL_WARNING,
|
|
"Mismatch of constructors when unregistering service type: %s",
|
|
service_type);
|
|
return;
|
|
}
|
|
remove_registry(service_type);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* private methods */
|
|
/*****************************************************************************/
|
|
|
|
static LassoNodeClass *parent_class = NULL;
|
|
static GHashTable *registry = NULL;
|
|
|
|
/**
|
|
* lasso_discovery_process_modify_msg:
|
|
* @discovery: a #LassoDiscovery
|
|
* @message: the disco:Modify SOAP message
|
|
*
|
|
* Processes a disco:Modify message. Rebuilds a request object from the
|
|
* message and extracts ResourceID.
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
static gint
|
|
lasso_discovery_process_modify_msg(LassoDiscovery *discovery)
|
|
{
|
|
LassoWsfProfile *profile = NULL;
|
|
LassoDiscoModify *request = NULL;
|
|
LassoDiscoModifyResponse *response = NULL;
|
|
gint rc = 0;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
g_return_val_if_fail(LASSO_IS_DISCO_MODIFY(LASSO_WSF_PROFILE(discovery)->request),
|
|
LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
|
|
profile = LASSO_WSF_PROFILE(discovery);
|
|
request = LASSO_DISCO_MODIFY(profile->request);
|
|
assign_resource_id(request, discovery);
|
|
response = lasso_disco_modify_response_new(
|
|
lasso_utility_status_new(LASSO_DST_STATUS_CODE_OK));
|
|
rc = lasso_wsf_profile_init_soap_response(profile, LASSO_NODE(response));
|
|
cleanup:
|
|
lasso_release_gobject(response);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_process_query_msg:
|
|
* @discovery: a #LassoDiscovery
|
|
*
|
|
* Processes a disco:Query SOAP message. Rebuilds a request object from the
|
|
* message and extracts ResourceID.
|
|
*
|
|
* Return value: 0 on success; or a negative value otherwise.
|
|
**/
|
|
static gint
|
|
lasso_discovery_process_query_msg(LassoDiscovery *discovery)
|
|
{
|
|
LassoWsfProfile *profile = NULL;
|
|
LassoDiscoQuery *request = NULL;
|
|
LassoDiscoQueryResponse *response = NULL;
|
|
gint rc = 0;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
g_return_val_if_fail(LASSO_IS_DISCO_QUERY(LASSO_WSF_PROFILE(discovery)->request),
|
|
LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
|
|
profile = LASSO_WSF_PROFILE(discovery);
|
|
request = LASSO_DISCO_QUERY(profile->request);
|
|
assign_resource_id(request, discovery);
|
|
response = lasso_disco_query_response_new(
|
|
lasso_utility_status_new(LASSO_DST_STATUS_CODE_OK));
|
|
rc = lasso_wsf_profile_init_soap_response(profile, LASSO_NODE(response));
|
|
cleanup:
|
|
lasso_release_gobject(response);
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_init_resource_offering:
|
|
* @discovery: a #LassoDiscovery object
|
|
* @security_mech_id: (allow-none): a security mechanism string identifier
|
|
* @output_offering: (allow-none) (out): a pointer to a variable to hold the found resource offering
|
|
*
|
|
* Return value: 0 if successfull, an error code otherwise.
|
|
**/
|
|
static gint
|
|
lasso_discovery_init_resource_offering(LassoDiscovery *discovery,
|
|
const gchar *security_mech_id, LassoDiscoResourceOffering **output_offering)
|
|
{
|
|
gint rc = 0;
|
|
LassoDiscoResourceOffering *offering = NULL;
|
|
|
|
g_return_val_if_fail(LASSO_IS_DISCOVERY(discovery), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
|
|
|
|
if (! (offering = lasso_wsf_profile_get_resource_offering(&discovery->parent))) {
|
|
offering = lasso_discovery_get_resource_offering_auto(discovery, LASSO_DISCO_HREF);
|
|
lasso_wsf_profile_set_resource_offering(&discovery->parent, offering);
|
|
}
|
|
goto_cleanup_if_fail_with_rc(LASSO_IS_DISCO_RESOURCE_OFFERING(offering),
|
|
LASSO_PROFILE_ERROR_MISSING_RESOURCE_OFFERING);
|
|
rc = lasso_wsf_profile_set_security_mech_id(&discovery->parent, security_mech_id);
|
|
goto_cleanup_if_fail (! rc);
|
|
rc = lasso_wsf_profile_set_msg_url_from_description(&discovery->parent);
|
|
goto_cleanup_if_fail (! rc);
|
|
cleanup:
|
|
if (output_offering) {
|
|
lasso_assign_gobject(*output_offering, offering);
|
|
}
|
|
lasso_release_gobject(offering);
|
|
return rc;
|
|
}
|
|
/**
|
|
* lasso_discovery_build_key_info_node:
|
|
* @discovery: a #LassoDiscovery object
|
|
* @providerID: the provider ID of the provider whose public key is requested.
|
|
*
|
|
* Construct a #LassoDsKeyInfo containing the public key of the targeted web
|
|
* service provider. Fills the Modulus and Exponent composant of the RsaKeyValue.
|
|
* It does not handle DSAKeyValue.
|
|
*
|
|
* Return value: a new #LassoDsKeyIfno or NULL if no provider or no public key were found.
|
|
*/
|
|
static LassoDsKeyInfo*
|
|
lasso_discovery_build_key_info_node(LassoDiscovery *discovery, const gchar *providerID)
|
|
{
|
|
LassoWsfProfile *profile;
|
|
LassoDsKeyInfo *key_info = NULL;
|
|
LassoDsRsaKeyValue *rsa_key_value = NULL;
|
|
LassoDsKeyValue *key_value = NULL;
|
|
LassoProvider *provider = NULL;
|
|
xmlSecKeyInfoCtx *ctx = NULL;
|
|
xmlDoc *doc = NULL;
|
|
xmlNode *key_info_node = NULL;
|
|
xmlNode *xmlnode = NULL;
|
|
xmlXPathContext *xpathCtx = NULL;
|
|
xmlXPathObject *xpathObj = NULL;
|
|
GList *public_keys = NULL;
|
|
xmlSecKey *public_key = NULL;
|
|
|
|
lasso_return_val_if_invalid_param(DISCOVERY, discovery, NULL);
|
|
g_return_val_if_fail(providerID != NULL, NULL);
|
|
|
|
profile = &discovery->parent;
|
|
provider = lasso_server_get_provider(profile->server, providerID);
|
|
if (provider == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
public_keys = lasso_provider_get_public_keys(provider);
|
|
if (public_keys == NULL) {
|
|
return NULL;
|
|
}
|
|
public_key = (xmlSecKey*)public_keys->data;
|
|
if (public_key == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
ctx = xmlSecKeyInfoCtxCreate(NULL);
|
|
xmlSecKeyInfoCtxInitialize(ctx, NULL);
|
|
ctx->mode = xmlSecKeyInfoModeWrite;
|
|
ctx->keyReq.keyType = xmlSecKeyDataTypePublic;
|
|
|
|
doc = xmlSecCreateTree((xmlChar*)"KeyInfo",
|
|
(xmlChar*)"http://www.w3.org/2000/09/xmldsig#");
|
|
key_info_node = xmlDocGetRootElement(doc);
|
|
xmlSecAddChild(key_info_node, (xmlChar*)"KeyValue",
|
|
(xmlChar*)"http://www.w3.org/2000/09/xmldsig#");
|
|
|
|
xmlSecKeyInfoNodeWrite(key_info_node, public_key, ctx);
|
|
|
|
xpathCtx = xmlXPathNewContext(doc);
|
|
xmlXPathRegisterNs(xpathCtx, (xmlChar*)"ds",
|
|
(xmlChar*)"http://www.w3.org/2000/09/xmldsig#");
|
|
|
|
rsa_key_value = lasso_ds_rsa_key_value_new();
|
|
xpathObj = xmlXPathEvalExpression((xmlChar*)"//ds:Modulus", xpathCtx);
|
|
if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr) {
|
|
xmlnode = xpathObj->nodesetval->nodeTab[0];
|
|
rsa_key_value->Modulus = (gchar *) xmlNodeGetContent(xmlnode);
|
|
}
|
|
xmlXPathFreeObject(xpathObj);
|
|
|
|
xpathObj = xmlXPathEvalExpression((xmlChar*)"//ds:Exponent", xpathCtx);
|
|
if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr) {
|
|
xmlnode = xpathObj->nodesetval->nodeTab[0];
|
|
rsa_key_value->Exponent = (gchar *) xmlNodeGetContent(xmlnode);
|
|
}
|
|
xmlXPathFreeObject(xpathObj);
|
|
|
|
key_value = lasso_ds_key_value_new();
|
|
key_value->RSAKeyValue = rsa_key_value;
|
|
key_info = lasso_ds_key_info_new();
|
|
key_info->KeyValue = key_value;
|
|
|
|
xmlXPathFreeContext(xpathCtx);
|
|
lasso_release_doc(doc);
|
|
|
|
return key_info;
|
|
}
|
|
|
|
static LassoDiscoResourceOffering*
|
|
lasso_discovery_get_resource_offering_auto(LassoDiscovery *discovery, const gchar *service_type)
|
|
{
|
|
LassoWsfProfile *profile = LASSO_WSF_PROFILE(discovery);
|
|
LassoDiscoResourceOffering *resource_offering = NULL;
|
|
LassoSession *session = NULL;
|
|
GList *assertions = NULL;
|
|
LassoSamlAssertion *assertion = NULL;
|
|
LassoSamlAttribute *attribute = NULL;
|
|
LassoSamlAttributeValue *attribute_value = NULL;
|
|
LassoDiscoResourceOffering *offering = NULL;
|
|
GList *iter = NULL;
|
|
GList *iter2 = NULL;
|
|
GList *iter3 = NULL;
|
|
GList *iter4 = NULL;
|
|
|
|
if (profile->session == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
session = profile->session;
|
|
assertions = lasso_session_get_assertions(session, NULL);
|
|
for (iter = assertions; iter != NULL; iter = g_list_next(iter)) {
|
|
if (! LASSO_IS_SAML_ASSERTION(iter->data)) {
|
|
continue;
|
|
}
|
|
assertion = LASSO_SAML_ASSERTION(iter->data);
|
|
if (assertion->AttributeStatement == NULL) {
|
|
continue;
|
|
}
|
|
for (iter2 = assertion->AttributeStatement->Attribute; iter2 != NULL;
|
|
iter2 = g_list_next(iter2)) {
|
|
if (! LASSO_IS_SAML_ATTRIBUTE(iter2->data)) {
|
|
continue;
|
|
}
|
|
attribute = LASSO_SAML_ATTRIBUTE(iter2->data);
|
|
if (strcmp(attribute->attributeName, "DiscoveryResourceOffering") != 0) {
|
|
continue;
|
|
}
|
|
for (iter3 = attribute->AttributeValue; iter3 != NULL;
|
|
iter3 = g_list_next(iter3)) {
|
|
if (! LASSO_IS_SAML_ATTRIBUTE_VALUE(iter3->data)) {
|
|
continue;
|
|
}
|
|
attribute_value = LASSO_SAML_ATTRIBUTE_VALUE(iter3->data);
|
|
for (iter4 = attribute_value->any; iter4 != NULL;
|
|
iter4 = g_list_next(iter4)) {
|
|
if (! LASSO_IS_DISCO_RESOURCE_OFFERING(iter4->data)) {
|
|
continue;
|
|
}
|
|
offering = LASSO_DISCO_RESOURCE_OFFERING(iter4->data);
|
|
if (offering->ServiceInstance == NULL) {
|
|
continue;
|
|
}
|
|
if (strcmp(offering->ServiceInstance->ServiceType,
|
|
service_type) == 0) {
|
|
resource_offering = offering;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
lasso_release_list(assertions);
|
|
return resource_offering;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_build_credential:
|
|
* @discovery: an ID-WSF 1.0 discovery service object
|
|
* @providerId: the providerId for which the credential is build
|
|
*
|
|
* This function create a SAML assertion associating the public key of the given provider with its
|
|
* provider ID. This assertion will be signed by our own private key, creating a kind of
|
|
* certificate.
|
|
*
|
|
* Return value: the value of the attribute AssertionID of the created assertion.
|
|
*/
|
|
static gchar*
|
|
lasso_discovery_build_credential(LassoDiscovery *discovery, const gchar *providerId)
|
|
{
|
|
LassoWsfProfile *profile = NULL;
|
|
LassoSoapHeader *header = NULL;
|
|
LassoSoapBindingProvider *provider = NULL;
|
|
LassoDiscoQueryResponse *response = NULL;
|
|
LassoDiscoCredentials *credentials = NULL;
|
|
LassoSamlAssertion *assertion = NULL;
|
|
LassoSamlAuthenticationStatement *authentication_statement = NULL;
|
|
LassoSamlSubject *subject = NULL;
|
|
LassoSamlNameIdentifier *name_identifier = NULL;
|
|
LassoSamlSubjectConfirmation *subject_confirmation = NULL;
|
|
LassoDsKeyInfo *key_info = NULL;
|
|
GList *iter = NULL;
|
|
LassoProvider *our_provider =
|
|
LASSO_PROVIDER(LASSO_WSF_PROFILE(discovery)->server);
|
|
gchar *assertionID = NULL;
|
|
|
|
lasso_return_val_if_invalid_param(DISCOVERY, discovery, NULL);
|
|
|
|
/* Init assertion informations */
|
|
assertion = lasso_saml_assertion_new();
|
|
assertion->AssertionID = lasso_build_unique_id(32);
|
|
assertion->MajorVersion = LASSO_SAML_MAJOR_VERSION_N;
|
|
assertion->MinorVersion = LASSO_SAML_MINOR_VERSION_N;
|
|
assertion->IssueInstant = lasso_get_current_time();
|
|
lasso_assign_string(assertion->Issuer, our_provider->ProviderID);
|
|
|
|
/* Add AuthenticationStatement */
|
|
authentication_statement = LASSO_SAML_AUTHENTICATION_STATEMENT(
|
|
lasso_saml_authentication_statement_new());
|
|
authentication_statement->AuthenticationInstant = lasso_get_current_time();
|
|
|
|
subject = LASSO_SAML_SUBJECT(lasso_saml_subject_new());
|
|
|
|
/* NameIdentifier */
|
|
name_identifier = lasso_saml_name_identifier_new();
|
|
name_identifier->NameQualifier = g_strdup(
|
|
our_provider->ProviderID);
|
|
|
|
/* If no providerId was given use the one from the request */
|
|
if (providerId == NULL) {
|
|
header = LASSO_WSF_PROFILE(discovery)->soap_envelope_request->Header;
|
|
iter = header->Other;
|
|
while (iter) {
|
|
if (LASSO_IS_SOAP_BINDING_PROVIDER(iter->data) == TRUE) {
|
|
provider = LASSO_SOAP_BINDING_PROVIDER(iter->data);
|
|
break;
|
|
}
|
|
}
|
|
providerId = provider->providerID;
|
|
}
|
|
|
|
if (providerId != NULL) {
|
|
lasso_assign_string(name_identifier->Format, LASSO_LIB_NAME_IDENTIFIER_FORMAT_ENTITYID);
|
|
lasso_assign_string(name_identifier->content, providerId);
|
|
} else {
|
|
goto exit;
|
|
}
|
|
subject->NameIdentifier = name_identifier;
|
|
|
|
/* SubjectConfirmation */
|
|
subject_confirmation = lasso_saml_subject_confirmation_new();
|
|
lasso_list_add_string(subject_confirmation->ConfirmationMethod,
|
|
LASSO_SAML_CONFIRMATION_METHOD_HOLDER_OF_KEY);
|
|
|
|
/* Add public key value in credential */
|
|
key_info = lasso_discovery_build_key_info_node(discovery, provider->providerID);
|
|
if (key_info != NULL) {
|
|
subject_confirmation->KeyInfo = key_info;
|
|
}
|
|
subject->SubjectConfirmation = subject_confirmation;
|
|
|
|
/* Add the subject in the authentication statement */
|
|
LASSO_SAML_SUBJECT_STATEMENT_ABSTRACT(authentication_statement)->Subject = subject;
|
|
assertion->AuthenticationStatement = authentication_statement;
|
|
|
|
/* FIXME: add resource access statement */
|
|
|
|
/* Add credential to disco:QueryResponse */
|
|
response = LASSO_DISCO_QUERY_RESPONSE(profile->response);
|
|
credentials = lasso_disco_credentials_new();
|
|
lasso_list_add_gobject(credentials->any, assertion);
|
|
lasso_assign_gobject(response->Credentials, credentials);
|
|
|
|
lasso_assign_string(assertionID, assertion->AssertionID);
|
|
|
|
exit:
|
|
lasso_release_gobject(assertion);
|
|
lasso_release_gobject(credentials);
|
|
|
|
return assertionID;
|
|
}
|
|
|
|
static GHashTable *
|
|
get_constructors_registry()
|
|
{
|
|
if (registry == NULL) {
|
|
registry = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
|
|
}
|
|
return registry;
|
|
}
|
|
|
|
static LassoWsfProfileConstructor
|
|
lookup_registry(gchar const *service_type) {
|
|
gpointer *t;
|
|
|
|
g_return_val_if_fail(service_type, NULL);
|
|
t = g_hash_table_lookup(get_constructors_registry(), service_type);
|
|
return (LassoWsfProfileConstructor)t;
|
|
}
|
|
|
|
static void
|
|
remove_registry(gchar const *service_type)
|
|
{
|
|
g_return_if_fail(service_type);
|
|
g_hash_table_remove(get_constructors_registry(), service_type);
|
|
}
|
|
|
|
static void
|
|
set_registry(gchar const *service_type, LassoWsfProfileConstructor constructor)
|
|
{
|
|
g_return_if_fail(service_type);
|
|
g_return_if_fail(constructor);
|
|
g_hash_table_insert(get_constructors_registry(),
|
|
g_strdup(service_type), constructor);
|
|
}
|
|
|
|
static LassoWsfProfile *
|
|
lasso_discovery_build_wsf_profile(LassoDiscovery *discovery, LassoDiscoResourceOffering *offering)
|
|
{
|
|
LassoWsfProfile *a_wsf_profile = NULL;
|
|
LassoWsfProfileConstructor a_constructor;
|
|
LassoServer *server;
|
|
gchar *service_type = NULL;
|
|
|
|
g_return_val_if_fail(offering, NULL);
|
|
g_return_val_if_fail(offering->ServiceInstance, NULL);
|
|
g_return_val_if_fail(offering->ServiceInstance->ServiceType, NULL);
|
|
|
|
service_type = offering->ServiceInstance->ServiceType;
|
|
a_constructor = lookup_registry(service_type);
|
|
server = LASSO_WSF_PROFILE(discovery)->server;
|
|
|
|
if (a_constructor) {
|
|
a_wsf_profile = a_constructor(server, offering);
|
|
} else {
|
|
message(G_LOG_LEVEL_WARNING, "No constructor registered for service type: %s", service_type);
|
|
a_wsf_profile = LASSO_WSF_PROFILE(lasso_data_service_new_full(server, offering));
|
|
}
|
|
lasso_assign_gobject(a_wsf_profile->session, discovery->parent.session);
|
|
|
|
return a_wsf_profile;
|
|
}
|
|
|
|
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)
|
|
{
|
|
LassoDiscovery *discovery = LASSO_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)
|
|
{
|
|
LassoDiscovery *discovery = LASSO_DISCOVERY(object);
|
|
lasso_release(discovery->private_data);
|
|
discovery->private_data = NULL;
|
|
G_OBJECT_CLASS(parent_class)->finalize(object);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* instance and class init functions */
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
instance_init(LassoDiscovery *discovery)
|
|
{
|
|
discovery->private_data = g_new0(LassoDiscoveryPrivate, 1);
|
|
discovery->private_data->dispose_has_run = FALSE;
|
|
}
|
|
|
|
static void
|
|
class_init(LassoDiscoveryClass *klass, void *unused G_GNUC_UNUSED)
|
|
{
|
|
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_discovery_get_type()
|
|
{
|
|
static GType this_type = 0;
|
|
|
|
if (!this_type) {
|
|
static const GTypeInfo this_info = {
|
|
sizeof(LassoDiscoveryClass),
|
|
NULL,
|
|
NULL,
|
|
(GClassInitFunc) class_init,
|
|
NULL,
|
|
NULL,
|
|
sizeof(LassoDiscovery),
|
|
0,
|
|
(GInstanceInitFunc) instance_init,
|
|
NULL
|
|
};
|
|
|
|
this_type = g_type_register_static(LASSO_TYPE_WSF_PROFILE,
|
|
"LassoDiscovery", &this_info, 0);
|
|
}
|
|
return this_type;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_new:
|
|
* @server: the #LassoServer
|
|
*
|
|
* Creates a new #LassoDiscovery.
|
|
*
|
|
* Return value: a newly created #LassoDiscovery object; or NULL if an error occured.
|
|
**/
|
|
LassoDiscovery*
|
|
lasso_discovery_new(LassoServer *server)
|
|
{
|
|
LassoDiscovery *discovery = NULL;
|
|
|
|
g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
|
|
|
|
discovery = g_object_new(LASSO_TYPE_DISCOVERY, NULL);
|
|
lasso_wsf_profile_init(&discovery->parent, server, NULL);
|
|
|
|
return discovery;
|
|
}
|
|
|
|
/**
|
|
* lasso_discovery_new_full:
|
|
* @server: the #LassoServer
|
|
* @offering: the #LassoDiscoResourceOffering
|
|
*
|
|
* Creates a new #LassoDiscovery.
|
|
*
|
|
* Return value: a newly created #LassoDiscovery object; or NULL if an error occured.
|
|
**/
|
|
LassoDiscovery*
|
|
lasso_discovery_new_full(LassoServer *server, LassoDiscoResourceOffering *offering)
|
|
{
|
|
LassoDiscovery *discovery = NULL;
|
|
|
|
g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
|
|
|
|
discovery = g_object_new(LASSO_TYPE_DISCOVERY, NULL);
|
|
lasso_wsf_profile_init(&discovery->parent, server, offering);
|
|
|
|
return discovery;
|
|
}
|