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