1 /* $Id$
2  *
3  *
4  *
5  * Lasso - A free implementation of the Liberty Alliance specifications.
6  *
7  * Copyright (C) 2004-2007 Entr'ouvert
8  * http://lasso.entrouvert.org
9  *
10  * Authors: See AUTHORS file in top-level directory.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, see <http://www.gnu.org/licenses/>.
24  */
25 
26 #include "id_ff_extensions.h"
27 #include "../xml/idwsf_strings.h"
28 #include "id_ff_extensions_private.h"
29 #include "../xml/disco_description.h"
30 #include "../xml/disco_resource_offering.h"
31 #include "../xml/disco_service_instance.h"
32 #include "../xml/id-wsf-2.0/disco_service_context.h"
33 #include "../id-ff/profile.h"
34 #include "../id-ff/server.h"
35 #include "../id-ff/loginprivate.h"
36 #include "../id-ff/serverprivate.h"
37 #include "../id-ff/identityprivate.h"
38 #include "../xml/saml_attribute.h"
39 #include "../xml/saml_attribute_value.h"
40 #include "../xml/saml_attribute_statement.h"
41 #include "../id-wsf-2.0/server.h"
42 
43 /**
44  * SECTION:id-ff-extensions
45  *
46  * Those functions are called from ID-FF part of lasso when ID-WSF support is enabled. They enable
47  * the boot-straping of the ID-WSF services, notably the access to the Discovery service (see
48  * #LassoDiscovery).
49  */
50 
51 /**
52  * lasso_login_assertion_add_discovery:
53  * @login: a #LassoLogin object
54  * @assertion: a #LassoSamlAssertion object
55  *
56  * Adds AttributeStatement and ResourceOffering attributes to @assertion of a @login object if there
57  * is a discovery service registerered in the @LassoLogin.server field.
58  * .
59  **/
60 void
lasso_login_assertion_add_discovery(LassoLogin * login,LassoSamlAssertion * assertion)61 lasso_login_assertion_add_discovery(LassoLogin *login, LassoSamlAssertion *assertion)
62 {
63 	LassoProfile *profile = LASSO_PROFILE(login);
64 	LassoDiscoResourceOffering *resourceOffering;
65 	LassoDiscoServiceInstance *serviceInstance, *newServiceInstance;
66 	LassoSamlAttributeStatement *attributeStatement;
67 	LassoSamlAttribute *attribute;
68 	LassoSamlAttributeValue *attributeValue;
69 
70 	serviceInstance = lasso_server_get_service(profile->server, LASSO_DISCO_HREF);
71 	if (LASSO_IS_DISCO_SERVICE_INSTANCE(serviceInstance) &&
72 			login->private_data->resourceId) {
73 		newServiceInstance = lasso_disco_service_instance_copy(serviceInstance);
74 
75 		resourceOffering = lasso_disco_resource_offering_new(newServiceInstance);
76 		lasso_release_gobject(newServiceInstance);
77 		lasso_assign_gobject(resourceOffering->ResourceID, login->private_data->resourceId);
78 
79 		attributeValue = lasso_saml_attribute_value_new();
80 		lasso_list_add_new_gobject(attributeValue->any, resourceOffering);
81 
82 		attribute = lasso_saml_attribute_new();
83 		lasso_assign_string(attribute->attributeName, "DiscoveryResourceOffering");
84 		lasso_assign_string(attribute->attributeNameSpace, LASSO_DISCO_HREF);
85 		lasso_list_add_new_gobject(attribute->AttributeValue, attributeValue);
86 
87 		attributeStatement = lasso_saml_attribute_statement_new();
88 		lasso_list_add_new_gobject(attributeStatement->Attribute, attribute);
89 
90 		lasso_assign_new_gobject(assertion->AttributeStatement, attributeStatement);
91 
92 		/* FIXME: Add CredentialsRef and saml:Advice Assertions */
93 	}
94 }
95 
96 
97 /**
98  * lasso_login_set_encryptedResourceId:
99  * @login: a #LassoLogin object
100  * @encryptedResourceId: the #LassoDiscoEncryptedResourceID to setup in the login object
101  *
102  * Set the #LassoDiscoEncryptedResourceID to place the next produced assertions as an ID-WSF 1.0
103  * bootstrap.
104  *
105  * Return value: 0 on success; or a negative value otherwise.
106  **/
107 int
lasso_login_set_encryptedResourceId(LassoLogin * login,LassoDiscoEncryptedResourceID * encryptedResourceId)108 lasso_login_set_encryptedResourceId(LassoLogin *login,
109 		LassoDiscoEncryptedResourceID *encryptedResourceId)
110 {
111 	g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
112 	g_return_val_if_fail(LASSO_IS_DISCO_ENCRYPTED_RESOURCE_ID(encryptedResourceId),
113 			LASSO_PARAM_ERROR_INVALID_VALUE);
114 
115 	lasso_assign_gobject(login->private_data->encryptedResourceId, encryptedResourceId);
116 
117 	return 0;
118 }
119 
120 
121 /**
122  * lasso_login_set_resourceId:
123  * @login: a #LassoLogin
124  * @content: a resourceID identifier
125  *
126  * Set the resourceId to place in the next produced assertion for ID-WSF bootstrap.
127  *
128  * Return value: 0 on success; or a negative value otherwise.
129  **/
130 int
lasso_login_set_resourceId(LassoLogin * login,const char * content)131 lasso_login_set_resourceId(LassoLogin *login, const char *content)
132 {
133 	g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
134 	g_return_val_if_fail(content != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
135 
136 	lasso_assign_new_gobject(login->private_data->resourceId, lasso_disco_resource_id_new(content));
137 	return 0;
138 }
139 
140 
141 /**
142  * lasso_server_add_service:
143  * @server: a #LassoServer
144  * @service: a #LassoNode object implementing representing a service endpoint.
145  *
146  * Add a service to the registry of service of this #LassoServer object.
147  *
148  * Return value: 0 on success; a negative value if an error occured.
149  **/
150 gint
lasso_server_add_service(LassoServer * server,LassoNode * service)151 lasso_server_add_service(LassoServer *server, LassoNode *service)
152 {
153 	g_return_val_if_fail(LASSO_IS_SERVER(server), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
154 	g_return_val_if_fail(service != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
155 
156 	if (LASSO_IS_DISCO_SERVICE_INSTANCE(service)) {
157 		g_hash_table_insert(server->services,
158 				g_strdup(LASSO_DISCO_SERVICE_INSTANCE(service)->ServiceType),
159 				g_object_ref(service));
160 	} else if (LASSO_IS_IDWSF2_DISCO_SVC_METADATA(service)) {
161 		return lasso_server_add_svc_metadata(server,
162 				LASSO_IDWSF2_DISCO_SVC_METADATA(service));
163 	} else {
164 		return LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ;
165 	}
166 	return 0;
167 }
168 
169 
170 static void
add_service_childnode(G_GNUC_UNUSED gchar * key,LassoNode * value,xmlNode * xmlnode)171 add_service_childnode(G_GNUC_UNUSED gchar *key, LassoNode *value, xmlNode *xmlnode)
172 {
173 	xmlAddChild(xmlnode, lasso_node_get_xmlNode(LASSO_NODE(value), TRUE));
174 }
175 
176 
177 void
lasso_server_dump_id_wsf_services(LassoServer * server,xmlNode * xmlnode)178 lasso_server_dump_id_wsf_services(LassoServer *server, xmlNode *xmlnode)
179 {
180 	if (g_hash_table_size(server->services)) {
181 		xmlNode *t;
182 		t = xmlNewTextChild(xmlnode, NULL, (xmlChar*)"Services", NULL);
183 		g_hash_table_foreach(server->services,
184 				(GHFunc)add_service_childnode, t);
185 	}
186 }
187 
188 
189 void
lasso_server_init_id_wsf_services(LassoServer * server,xmlNode * t)190 lasso_server_init_id_wsf_services(LassoServer *server, xmlNode *t) {
191 	xmlNode *t2 = t->children;
192 	/* Services */
193 	if (strcmp((char*)t->name, "Services") == 0) {
194 		while (t2) {
195 			LassoDiscoServiceInstance *s;
196 			if (t2->type != XML_ELEMENT_NODE) {
197 				t2 = t2->next;
198 				continue;
199 			}
200 			s = g_object_new(LASSO_TYPE_DISCO_SERVICE_INSTANCE, NULL);
201 			LASSO_NODE_GET_CLASS(s)->init_from_xml(LASSO_NODE(s), t2);
202 			g_hash_table_insert(server->services, g_strdup(s->ServiceType), s);
203 			t2 = t2->next;
204 		}
205 	}
206 }
207 
208 
209 /**
210  * lasso_identity_add_resource_offering:
211  * @identity: a #LassoIdentity object
212  * @offering: a #LassoDiscoResourceOffering object to add
213  *
214  * Add a new offering to the identity object to be retrieved later by
215  * lasso_identity_get_offerings() or lasso_identity_get_resource_offering().
216  * It also allocate an entryId identifier for the offering, look into
217  * offering->entryID to get it after this call.
218  *
219  * Return value: Always 0, there should not be any error (if memory is not exhausted).
220  */
221 gint
lasso_identity_add_resource_offering(LassoIdentity * identity,LassoDiscoResourceOffering * offering)222 lasso_identity_add_resource_offering(LassoIdentity *identity,
223 		LassoDiscoResourceOffering *offering)
224 {
225 	char entry_id_s[20];
226 
227 	g_return_val_if_fail(LASSO_IS_IDENTITY(identity), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
228 	g_return_val_if_fail(LASSO_IS_DISCO_RESOURCE_OFFERING(offering),
229 		LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
230 
231 	do {
232 		g_snprintf(entry_id_s, 18, "%d", identity->private_data->last_entry_id);
233 		identity->private_data->last_entry_id++;
234 	} while (g_hash_table_lookup(identity->private_data->resource_offerings_map, entry_id_s));
235 	lasso_assign_string(offering->entryID, entry_id_s);
236 	g_hash_table_insert(identity->private_data->resource_offerings_map,
237 		g_strdup(offering->entryID), g_object_ref(offering));
238 	identity->is_dirty = TRUE;
239 
240 	return 0;
241 }
242 
243 
244 /**
245  * lasso_identity_remove_resource_offering:
246  * @identity: a #LassoIdentity
247  * @entryID: the resource offering entry ID
248  *
249  * Remove resource offering about identity with @entryID
250  *
251  * Return value: TRUE on success; FALSE if the offering was not found.
252  **/
253 gboolean
lasso_identity_remove_resource_offering(LassoIdentity * identity,const char * entryID)254 lasso_identity_remove_resource_offering(LassoIdentity *identity, const char *entryID)
255 {
256 	g_return_val_if_fail(LASSO_IS_IDENTITY(identity), FALSE);
257 	g_return_val_if_fail(entryID != NULL, LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
258 
259 	if (g_hash_table_remove(identity->private_data->resource_offerings_map, entryID)) {
260 		identity->is_dirty = TRUE;
261 		return TRUE;
262 	} else {
263 		return FALSE;
264 	}
265 }
266 
267 
268 /* Context type for the callback add_matching_resource_offering_to_list */
269 struct HelperStruct {
270 	GList *list;
271 	const char *service_type;
272 };
273 
274 
275 /*
276  * Helper function for lasso_identity_get_offerings, match them with a service
277  * type string */
278 static
add_matching_resource_offering_to_list(G_GNUC_UNUSED char * name,LassoDiscoResourceOffering * offering,struct HelperStruct * ctx)279 void add_matching_resource_offering_to_list(G_GNUC_UNUSED char *name, LassoDiscoResourceOffering *offering,
280 	struct HelperStruct *ctx)
281 {
282 	if (ctx->service_type == NULL ||
283 		( offering->ServiceInstance != NULL &&
284 		offering->ServiceInstance->ServiceType != NULL &&
285 		strcmp(offering->ServiceInstance->ServiceType, ctx->service_type) == 0)) {
286 		lasso_list_add_gobject(ctx->list, offering);
287 	}
288 }
289 
290 
291 /**
292  * lasso_identity_get_offerings:
293  * @identity: a #LassoIdentity
294  * @service_type: a char* string representing the type of service we are looking for
295  *
296  * Returns a list of #LassoDiscoResourceOffering associated to this service type.
297  *
298  * Return value:(transfer full)(element-type LassoDiscoResourceOffering): a newly allocated list of #LassoDiscoResourceOffering
299  */
300 GList*
lasso_identity_get_offerings(LassoIdentity * identity,const char * service_type)301 lasso_identity_get_offerings(LassoIdentity *identity, const char *service_type)
302 {
303 	struct HelperStruct ctx = { NULL, service_type };
304 
305 	g_return_val_if_fail(LASSO_IS_IDENTITY(identity), NULL);
306 
307 	g_hash_table_foreach(identity->private_data->resource_offerings_map,
308 		(GHFunc)add_matching_resource_offering_to_list, &ctx);
309 
310 	return ctx.list;
311 }
312 
313 
314 /**
315  * lasso_identity_resource_offering:
316  * @identity: a #LassoIdentity
317  * @entryID: the entryID of the researched #LassoDiscoResourceOffering
318  *
319  * Lookup a #LassoDiscoResourceOffering corresponding to entryID, entryID is
320  * usually allocated by lasso_identity_add_resource_offering() inside
321  * offering->entryID.
322  *
323  * Return value:(transfer none)(allow-none): a #LassoDiscoResourceOffering, your must ref it if you intend
324  * to keep it around.
325  */
326 LassoDiscoResourceOffering*
lasso_identity_get_resource_offering(LassoIdentity * identity,const char * entryID)327 lasso_identity_get_resource_offering(LassoIdentity *identity, const char *entryID)
328 {
329 	g_return_val_if_fail(LASSO_IS_IDENTITY(identity), NULL);
330 	g_return_val_if_fail(entryID != NULL, NULL);
331 
332 	return g_hash_table_lookup(identity->private_data->resource_offerings_map, entryID);
333 }
334 
335 
336 /**
337  * lasso_server_add_service_from_dump:
338  * @server: a #LassoServer
339  * @dump: the XML dump of a #LassoNode representing a service endpoint.
340  *
341  * An utility function that parse a #LassoNode dump an try to add it as a
342  * service using lasso_server_add_service.
343  *
344  * Return value: 0 if succesfull, LASSO_PARAM_ERROR_BAD_TYPE_OF_NULL_OBJECT if
345  * said dump is not a #LassoNode or is not of the righ type,
346  * LASSO_PARAM_ERROR_INVALID_VALUE if dump is NULL.
347  **/
348 gint
lasso_server_add_service_from_dump(LassoServer * server,const gchar * dump)349 lasso_server_add_service_from_dump(LassoServer *server, const gchar *dump)
350 {
351 	LassoNode *node;
352 	gint return_code;
353 
354 	g_return_val_if_fail(dump != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
355 
356 	node = lasso_node_new_from_dump(dump);
357 
358 	return_code = lasso_server_add_service(server, node);
359 
360 	g_object_unref(node);
361 
362 	return return_code;
363 }
364 
365 
366 /**
367  * lasso_server_get_service:
368  * @server: a #LassoServer
369  * @serviceType: the service type
370  *
371  * Look up a disco service instance corresponding to this service type.
372  *
373  * Return value:(transfer none)(allow-none): the #LassoDiscoServiceInstance, NULL if it was not found.
374  *     The #LassoDiscoServiceInstance is owned by Lasso and should not be
375  *     freed.
376  **/
377 LassoDiscoServiceInstance*
lasso_server_get_service(LassoServer * server,const gchar * serviceType)378 lasso_server_get_service(LassoServer *server, const gchar *serviceType)
379 {
380 	return g_hash_table_lookup(server->services, serviceType);
381 }
382