1 /* $Id$
2 *
3 * Lasso - A free implementation of the Liberty Alliance specifications.
4 *
5 * Copyright (C) 2004-2007 Entr'ouvert
6 * http://lasso.entrouvert.org
7 *
8 * Authors: See AUTHORS file in top-level directory.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /**
25 * SECTION:login
26 * @short_description: Single Sign-On and Federation Profile
27 *
28 * The Single Sign On process allows a user to log in once to an identity
29 * provider (IdP), and to be then transparently loged in to the required
30 * service providers (SP) belonging to the IP "circle of trust". Subordinating
31 * different identities of the same user within a circle of trust to a unique
32 * IP is called "Identity Federation". The liberty Alliance specifications
33 * allows, thanks to this federation, strong and unique authentication coupled
34 * with control by the user of his personal informations. The explicit user
35 * agreement is necessary before proceeding to Identity Federation.
36 *
37 * <para>
38 * The service provider must implement the following process:
39 * <itemizedlist>
40 * <listitem><para>creating an authentication request with
41 * lasso_login_init_authn_request();</para></listitem>
42 * <listitem><para>sending it to the identity provider with
43 * lasso_login_build_authn_request_msg();</para></listitem>
44 * <listitem><para>receiving and processing the answer:
45 * <itemizedlist>
46 * <listitem>either an authentication response with
47 * lasso_login_process_authn_response_msg()</listitem>
48 * <listitem>or an artifact with lasso_login_init_request() then sending the
49 * request to the IdP with lasso_login_build_request_msg() and processing the
50 * new answer with lasso_login_process_response_msg().</listitem>
51 * </itemizedlist>
52 * </para></listitem>
53 * </itemizedlist>
54 * </para>
55 *
56 * <para>Our first example shows how to initiate a request toward an ID-FF 1.2 or SAML 2.0 identity
57 * provider. It supposes that we already initialized a #LassoServer object with the metadatas or our
58 * provider (and its private key if we want to sign the request), and that we added the metadatas of
59 * the targetted IdP with the method lasso_server_add_provider(). </para>
60 *
61 * <example>
62 * <title>Service Provider Login URL</title>
63 * <programlisting>
64 * LassoLogin *login;
65 * int rc; // hold return codes
66 *
67 * login = lasso_login_new(server);
68 * rc = lasso_login_init_authn_request(login, "http://identity-provider-id/",
69 * LASSO_HTTP_METHOD_REDIRECT);
70 * if (rc != 0) {
71 * ... // handle errors, most of them are related to bad initialization
72 * }
73 *
74 * // customize AuthnRequest
75 * // protocolProfile is the protocolProfile of the provider http://identity-provider-id/
76 * if (protocolProfile == LASSO_LIBERTY_1_2) {
77 * LassoLibAuthnRequest *request = LASSO_LIB_AUTHN_REQUEST(LASSO_PROFILE(login)->request);
78 * request->NameIDPolicy = strdup(LASSO_LIB_NAMEID_POLICY_TYPE_FEDERATED);
79 * request->ForceAuthn = TRUE;
80 * request->IsPassive = FALSE;
81 * // tell the IdP how to return the response
82 * request->ProtocolProfile = strdup(LASSO_LIB_PROTOCOL_PROFILE_BRWS_ART);
83 * } else if (protocolProfile == LASSO_SAML_2_0) {
84 * LassoSamlp2AuthnRequest *request = LASSO_SAMLP2_AUTHN_REQUEST(LASSO_PROFILE(login)->request);
85 * if (request->NameIDPolicy->Format) {
86 * g_free(request->NameIDPolicy->Format);
87 * }
88 * request->NameIDPolicy->Format = g_strdup(LASSO_NAME_IDENTIFIER_FORMAT_PERSISTENT);
89 * // Allow creation of new federation
90 * //
91 * request->NameIDPolicy->AllowCreate = 1;
92 * request->ForceAuthn = TRUE;
93 * request->IsPassive = FALSE;
94 * // tell the IdP how to return the response
95 * if (request->ProtocolBinding) {
96 * g_free(request->ProtocolBinding);
97 * }
98 * // here we expect an artifact response, it could be post, redirect or PAOS.
99 * request->ProtocolBinding = g_strdup(LASSO_SAML2_METADATA_BINDING_ARTIFACT);
100 }
101 * // Lasso will choose whether to sign the request by looking at the IdP
102 * // metadatas and at our metadatas, but you can always force him to sign or to
103 * // not sign using the method lasso_profile_set_signature_hint() on the
104 * // LassoLogin object.
105 *
106 * rc = lasso_login_build_authn_request_msg(login);
107 * if (rc != 0) {
108 .... // handle errors
109 // could be that the requested binding (POST, Redirect, etc..) is not supported (LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE)
110 // or that we could not sign the request (LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED).
111 * }
112 *
113 * // redirect user to identity provider
114 // we chose the Redirect binding, so we have to generate a redirect HTTP response to the URL returned by Lasso
115 * printf("Location: %s\n\nRedirected to IdP\n", LASSO_PROFILE(login)->msg_url);
116 * </programlisting>
117 * </example>
118 *
119 * <para>Next example shows how to receive the response from the identity
120 * provider for ID-FF 1.2.</para>
121 *
122 * <example>
123 * <title>Service Provider Assertion Consumer Service URL for ID-FF 1.2</title>
124 * <programlisting>
125 * LassoLogin *login;
126 * char *request_method = getenv("REQUEST_METHOD");
127 * char *artifact_msg = NULL, *lares = NULL, *lareq = NULL;
128 * char *name_identifier;
129 * lassoHttpMethod method;
130 * int rc = 0;
131 *
132 * login = lasso_login_new(server);
133 * if (strcmp(request_method, "GET") == 0) {
134 * artifact_msg = getenv("QUERY_STRING");
135 * method = LASSO_HTTP_METHOD_REDIRECT;
136 * } else {
137 * // read submitted form; if it has a LAREQ field, put it in lareq,
138 * // if it has a LARES field, put it in lares
139 * if (lareq) {
140 * artifact_msg = lareq;
141 * } else if (lares) {
142 * response_msg = lares;
143 * } else {
144 * // bail out
145 * }
146 * method = LASSO_HTTP_METHOD_POST;
147 * }
148 *
149 * if (artifact_msg) {
150 * // we received an artifact response,
151 * // it means we did not really receive the response,
152 * // only a token to redeem the real response from the identity
153 * // provider through a SOAP resolution call
154 * rc = lasso_login_init_request(login, artifact_msg, method);
155 * if (rc != 0) {
156 * ... // handle errors
157 * // there is usually no error at this step, only
158 * // if the IdP response is malformed
159 * }
160 * rc = lasso_login_build_request_msg(login);
161 * if (rc != 0) {
162 * ... // handle errors
163 * // as for AuthnRequest generation, it generally is caused
164 * // by a bad initialization like an impossibility to load
165 * // the private key.
166 * }
167 * // makes a SOAP call, soap_call is NOT a Lasso function
168 * soap_answer_msg = soap_call(LASSO_PROFILE(login)->msg_url,
169 * LASSO_PROFILE(login)->msg_body);
170 * rc = lasso_login_process_response_msg(login, soap_answer_msg);
171 * if (rc != 0) {
172 * ... // handle errors
173 * // here you can know if the IdP refused the request,
174 * }
175 * } else if (response_msg) {
176 * lasso_login_process_authn_response_msg(login, response_msg);
177 * }
178 *
179 * // looks up name_identifier in local file, database, whatever and gets back
180 * // two things: identity_dump and session_dump
181 * name_identifier = LASSO_PROFILE(login)->nameIdentifier
182 * lasso_profile_set_identity_from_dump(LASSO_PROFILE(login), identity_dump);
183 * lasso_profile_set_session_from_dump(LASSO_PROFILE(login), session_dump);
184 *
185 * lasso_login_accept_sso(login);
186 *
187 * if (lasso_profile_is_identity_dirty(LASSO_PROFILE(login))) {
188 * LassoIdentity *identity;
189 * char *identity_dump;
190 * identity = lasso_profile_get_identity(LASSO_PROFILE(login));
191 * identity_dump = lasso_identity_dump(identity);
192 * // record identity_dump in file, database...
193 * }
194 *
195 * if (lasso_profile_is_session_dirty(LASSO_PROFILE(login))) {
196 * LassoSession *session;
197 * char *session_dump;
198 * session = lasso_profile_get_session(LASSO_PROFILE(login));
199 * session_dump = lasso_session_dump(session);
200 * // record session_dump in file, database...
201 * }
202 *
203 * // redirect user anywhere
204 * printf("Location: %s\n\nRedirected to site root\n", login->msg_url);
205 * </programlisting>
206 * </example>
207 *
208 * <para>The implement an IdP you must create a single sign-on service endpoint, the needed APIs for
209 * this are lasso_login_process_authn_request_msg(), lasso_login_validate_request_msg(),
210 * lasso_login_build_assertion(), lasso_login_build_authn_response_msg() and
211 * lasso_login_build_artifact_msg(). You will have to chose between
212 * lasso_login_build_authn_response_msg() and lasso_login_build_artifact_msg() depending on the
213 * requested protocol for the response by the service provider</para>
214 *
215 * <example>
216 * <title>Identity provider single sign-on service</title>
217 * <programlisting>
218 * LassoLogin *login;
219 * char *request_method = getenv("REQUEST_METHOD");
220 * char *artifact_msg = NULL, *lares = NULL, *lareq = NULL;
221 * char *name_identifier;
222 * lassoHttpMethod method;
223 * int rc = 0;
224 *
225 * login = lasso_login_new(server);
226 * if (strcmp(request_method, 'GET')) { // AuthnRequest send with the HTTP-Redirect binding
227 * //
228 * lasso_profile_set_signature_verify_hint(LASSO_PROFILE(login),
229 * LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE);
230 * rc = lasso_process_authn_request_msg(login, getenv("QUERY_STRING"));
231 * if (rc != 0) {
232 * // handle errors
233 * }
234 *
235 *
236 * } else {
237 *
238 * </programlisting>
239 * </example>
240 *
241 */
242
243 #include <xmlsec/base64.h>
244
245 #include <config.h>
246 #include "lasso_config.h"
247 #include "../utils.h"
248 #include "../debug.h"
249 #include "login.h"
250 #include "provider.h"
251 #include "../xml/private.h"
252 #include "../xml/lib_authentication_statement.h"
253 #include "../xml/lib_subject.h"
254 #include "../xml/saml_advice.h"
255 #include "../xml/saml_attribute.h"
256 #include "../xml/saml_attribute_value.h"
257 #include "../xml/saml_audience_restriction_condition.h"
258 #include "../xml/saml_conditions.h"
259 #include "../xml/samlp_response.h"
260 #include "../xml/saml-2.0/saml2_encrypted_element.h"
261 #include "../xml/misc_text_node.h"
262
263
264 #include "profileprivate.h"
265 #include "providerprivate.h"
266 #include "serverprivate.h"
267 #include "sessionprivate.h"
268 #include "identityprivate.h"
269 #include "loginprivate.h"
270 #include "../saml-2.0/loginprivate.h"
271 #include "../lasso_config.h"
272
273 #ifdef LASSO_WSF_ENABLED
274 #include "../id-wsf/id_ff_extensions_private.h"
275 #endif
276
277 #define LASSO_LOGIN_GET_PRIVATE(o) \
278 (G_TYPE_INSTANCE_GET_PRIVATE ((o), LASSO_TYPE_LOGIN, LassoLoginPrivate))
279
280
281 static void lasso_login_build_assertion_artifact(LassoLogin *login);
282
283 /*****************************************************************************/
284 /* static methods/functions */
285 /*****************************************************************************/
286
287 /**
288 * lasso_login_build_assertion:
289 * @login: a #LassoLogin
290 * @authenticationMethod: the authentication method
291 * @authenticationInstant: the time at which the authentication took place
292 * @notBefore: the earliest time instant at which the assertion is valid
293 * @notOnOrAfter: the time instant at which the assertion has expired
294 *
295 * Builds an assertion and stores it in profile session.
296 * @authenticationInstant, reauthenticateOnOrAfter, @notBefore and
297 * @notOnOrAfter may be NULL. If @authenticationInstant is NULL, the current
298 * time will be used. Time values must be encoded in UTC.
299 *
300 * Construct the authentication assertion for the response. It must be called after validating the
301 * request using lasso_login_validate_request_msg(). The created assertion is accessed using
302 * lasso_login_get_assertion().
303 *
304 * Return value: 0 on success; or
305 * <itemizedlist>
306 * <listitem><para>
307 * #LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin object,
308 * </para></listitem>
309 * <listitem><para>
310 * #LASSO_PROFILE_ERROR_IDENTITY_NOT_FOUND if no identity object was found in the login profile object.
311 * </para></listitem>
312 * <listitem><para>
313 * #LASSO_PROFILE_ERROR_MISSING_RESPONSE if no response object is present ( it is normally initialized
314 * by lasso_login_process_authn_request_msg() )
315 * </para></listitem>
316 * <listitem><para>
317 * #LASSO_PROFILE_ERROR_FEDERATION_NOT_FOUND if a #LASSO_SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT or #LASSO_SAML2_NAME_IDENTIFIER_FORMAT_ENCRYPTED NameID format is asked and no corresponding federation was found in the #LassoIdentity object,
318 * </para></listitem>
319 * <listitem><para>
320 * #LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND if encryption is needed and the request issuing provider is unknown (it as not been registered in the #LassoServer object),
321 * </para></listitem>
322 * <listitem><para>
323 * #LASSO_DS_ERROR_ENCRYPTION_FAILED if encryption is needed but it failed,
324 * </para></listitem>
325 * </itemizedlist>
326 *
327 **/
328 int
lasso_login_build_assertion(LassoLogin * login,const char * authenticationMethod,const char * authenticationInstant,const char * reauthenticateOnOrAfter,const char * notBefore,const char * notOnOrAfter)329 lasso_login_build_assertion(LassoLogin *login,
330 const char *authenticationMethod,
331 const char *authenticationInstant,
332 const char *reauthenticateOnOrAfter,
333 const char *notBefore,
334 const char *notOnOrAfter)
335 {
336 LassoSamlAssertion *assertion;
337 LassoLibAuthenticationStatement *as;
338 LassoSamlNameIdentifier *nameIdentifier = NULL;
339 LassoProfile *profile;
340 LassoFederation *federation;
341 LassoProvider *provider = NULL;
342 LassoSaml2EncryptedElement *encrypted_element = NULL;
343 LassoSamlSubjectStatementAbstract *ss;
344 lasso_error_t rc = 0;
345
346 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
347
348 profile = LASSO_PROFILE(login);
349
350 if (profile->identity == NULL)
351 return LASSO_PROFILE_ERROR_IDENTITY_NOT_FOUND;
352
353 IF_SAML2(profile) {
354 return lasso_saml20_login_build_assertion(login,
355 authenticationMethod, authenticationInstant,
356 notBefore, notOnOrAfter);
357 }
358
359 federation = g_hash_table_lookup(profile->identity->federations,
360 profile->remote_providerID);
361
362 assertion = LASSO_SAML_ASSERTION(lasso_lib_assertion_new_full(
363 LASSO_PROVIDER(profile->server)->ProviderID,
364 LASSO_SAMLP_REQUEST_ABSTRACT(profile->request)->RequestID,
365 profile->remote_providerID, notBefore, notOnOrAfter));
366
367 if (strcmp(login->nameIDPolicy, LASSO_LIB_NAMEID_POLICY_TYPE_ONE_TIME) == 0 ||
368 federation == NULL) {
369 /* if NameIDPolicy is 'onetime', don't use a federation */
370 nameIdentifier = lasso_saml_name_identifier_new();
371 lasso_assign_new_string(nameIdentifier->content, lasso_build_unique_id(32));
372 lasso_assign_string(nameIdentifier->NameQualifier,
373 LASSO_PROVIDER(profile->server)->ProviderID);
374 lasso_assign_string(nameIdentifier->Format,
375 LASSO_LIB_NAME_IDENTIFIER_FORMAT_ONE_TIME);
376
377 as = lasso_lib_authentication_statement_new_full(authenticationMethod,
378 authenticationInstant, reauthenticateOnOrAfter,
379 NULL, nameIdentifier);
380 lasso_assign_new_gobject(profile->nameIdentifier, LASSO_NODE(nameIdentifier));
381 } else {
382 as = lasso_lib_authentication_statement_new_full(authenticationMethod,
383 authenticationInstant, reauthenticateOnOrAfter,
384 LASSO_SAML_NAME_IDENTIFIER(federation->remote_nameIdentifier),
385 LASSO_SAML_NAME_IDENTIFIER(federation->local_nameIdentifier));
386 }
387
388 /* Encrypt NameID */
389 provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
390 ss = LASSO_SAML_SUBJECT_STATEMENT_ABSTRACT(as);
391 if (provider
392 && (lasso_provider_get_encryption_mode(provider) & LASSO_ENCRYPTION_MODE_NAMEID)) {
393 encrypted_element = LASSO_SAML2_ENCRYPTED_ELEMENT(lasso_node_encrypt(
394 LASSO_NODE(ss->Subject->NameIdentifier),
395 lasso_provider_get_encryption_public_key(provider),
396 lasso_provider_get_encryption_sym_key_type(provider),
397 provider->ProviderID));
398 if (encrypted_element != NULL) {
399 lasso_assign_new_gobject(ss->Subject->EncryptedNameIdentifier, encrypted_element);
400 lasso_release_gobject(ss->Subject->NameIdentifier);
401 }
402 }
403
404 /* add session index */
405 if (lasso_provider_get_first_http_method(&login->parent.server->parent,
406 provider, LASSO_MD_PROTOCOL_TYPE_SINGLE_LOGOUT) != LASSO_HTTP_METHOD_NONE) {
407 lasso_assign_string(as->SessionIndex, assertion->AssertionID);
408 }
409
410 assertion->AuthenticationStatement = LASSO_SAML_AUTHENTICATION_STATEMENT(as);
411
412 /* Save signing material in assertion private datas to be able to sign later */
413 lasso_check_good_rc(lasso_server_set_signature_for_provider_by_name(login->parent.server,
414 profile->remote_providerID, (LassoNode*)assertion));
415
416 lasso_list_add_gobject(LASSO_SAMLP_RESPONSE(profile->response)->Assertion,
417 assertion);
418
419 #ifdef LASSO_WSF_ENABLED
420 lasso_login_assertion_add_discovery(login, assertion);
421 #endif
422
423 /* store assertion in session object */
424 if (profile->session == NULL) {
425 profile->session = lasso_session_new();
426 }
427 lasso_assign_gobject(login->assertion, LASSO_SAML_ASSERTION(assertion));
428 lasso_check_good_rc(lasso_session_add_assertion(profile->session, profile->remote_providerID,
429 LASSO_NODE(assertion)));
430
431 if (LASSO_SAMLP_REQUEST_ABSTRACT(profile->request)->MajorVersion == 1 &&
432 LASSO_SAMLP_REQUEST_ABSTRACT(profile->request)->MinorVersion < 2) {
433 /* pre-id-ff 1.2, saml 1.0 */
434
435 /* needs assertion artifact */
436 lasso_login_build_assertion_artifact(login);
437
438 assertion->MinorVersion = 0;
439
440 ss = LASSO_SAML_SUBJECT_STATEMENT_ABSTRACT(assertion->AuthenticationStatement);
441 ss->Subject = LASSO_SAML_SUBJECT(lasso_saml_subject_new());
442 ss->Subject->NameIdentifier = LASSO_SAML_NAME_IDENTIFIER(g_object_ref(profile->nameIdentifier));
443 ss->Subject->SubjectConfirmation = lasso_saml_subject_confirmation_new();
444 /* liberty-architecture-bindings-profiles-v1.1.pdf, page 24, line 729 */
445 lasso_list_add_string(ss->Subject->SubjectConfirmation->ConfirmationMethod,
446 LASSO_SAML_CONFIRMATION_METHOD_ARTIFACT01);
447 lasso_assign_string(ss->Subject->SubjectConfirmation->SubjectConfirmationData,
448 login->assertionArtifact);
449
450 if (nameIdentifier) {
451 /* draft-liberty-idff-protocols-schemas-1.2-errata-v2.0.pdf */
452 lasso_release_string(nameIdentifier->NameQualifier);
453 lasso_release_string(nameIdentifier->Format);
454 }
455 }
456
457 cleanup:
458 lasso_release_gobject(assertion);
459 return rc;
460 }
461
462 /**
463 * lasso_login_must_ask_for_consent_private:
464 * @login: a #LassoLogin
465 *
466 * Evaluates if it is necessary to ask the consent of the Principal.
467 * This method doesn't take the isPassive value into account.
468 *
469 * Return value: TRUE if consent should be asked, FALSE otherwise.
470 **/
471 static gboolean
lasso_login_must_ask_for_consent_private(LassoLogin * login)472 lasso_login_must_ask_for_consent_private(LassoLogin *login)
473 {
474 char *nameIDPolicy, *consent;
475 LassoProfile *profile = LASSO_PROFILE(login);
476 LassoFederation *federation = NULL;
477
478 nameIDPolicy = LASSO_LIB_AUTHN_REQUEST(profile->request)->NameIDPolicy;
479
480 if (nameIDPolicy == NULL || strcmp(nameIDPolicy, LASSO_LIB_NAMEID_POLICY_TYPE_NONE) == 0)
481 return FALSE;
482
483 if (strcmp(nameIDPolicy, LASSO_LIB_NAMEID_POLICY_TYPE_ONE_TIME) == 0)
484 return FALSE;
485
486 if (strcmp(nameIDPolicy, LASSO_LIB_NAMEID_POLICY_TYPE_FEDERATED) != 0 &&
487 strcmp(nameIDPolicy, LASSO_LIB_NAMEID_POLICY_TYPE_ANY) != 0) {
488 message(G_LOG_LEVEL_CRITICAL, "Unknown NameIDPolicy: %s", nameIDPolicy);
489 /* NameIDPolicy is considered empty (None value) if its value is unknown/invalid */
490 return TRUE;
491 }
492
493 if (profile->identity != NULL) {
494 federation = g_hash_table_lookup(profile->identity->federations,
495 profile->remote_providerID);
496 if (federation)
497 return FALSE;
498 }
499
500 consent = LASSO_LIB_AUTHN_REQUEST(profile->request)->consent;
501 if (consent == NULL)
502 return TRUE;
503
504 if (strcmp(consent, LASSO_LIB_CONSENT_OBTAINED) == 0)
505 return FALSE;
506
507 if (strcmp(consent, LASSO_LIB_CONSENT_OBTAINED_PRIOR) == 0)
508 return FALSE;
509
510 if (strcmp(consent, LASSO_LIB_CONSENT_OBTAINED_CURRENT_IMPLICIT) == 0)
511 return FALSE;
512
513 if (strcmp(consent, LASSO_LIB_CONSENT_OBTAINED_CURRENT_EXPLICIT) == 0)
514 return FALSE;
515
516 if (strcmp(consent, LASSO_LIB_CONSENT_UNAVAILABLE) == 0)
517 return TRUE;
518
519 if (strcmp(consent, LASSO_LIB_CONSENT_INAPPLICABLE) == 0)
520 return TRUE;
521
522 message(G_LOG_LEVEL_CRITICAL, "Unknown consent value: %s", consent);
523 /* we consider consent as empty if its value is unknown/invalid */
524 return TRUE;
525 }
526
527 /**
528 * lasso_login_process_federation:
529 * @login: a #LassoLogin
530 * @is_consent_obtained: whether user consent has been obtained
531 *
532 * Return value: 0 on success; or a negative value otherwise.
533 **/
534 static gint
lasso_login_process_federation(LassoLogin * login,gboolean is_consent_obtained)535 lasso_login_process_federation(LassoLogin *login, gboolean is_consent_obtained)
536 {
537 LassoFederation *federation = NULL;
538 LassoProfile *profile;
539 char *nameIDPolicy;
540 gint ret = 0;
541
542 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
543
544 profile = LASSO_PROFILE(login);
545
546 /* verify if identity already exists else create it */
547 if (profile->identity == NULL) {
548 profile->identity = lasso_identity_new();
549 }
550
551 /* get nameIDPolicy in lib:AuthnRequest */
552 nameIDPolicy = LASSO_LIB_AUTHN_REQUEST(profile->request)->NameIDPolicy;
553 if (nameIDPolicy == NULL)
554 nameIDPolicy = LASSO_LIB_NAMEID_POLICY_TYPE_NONE;
555 lasso_assign_string(login->nameIDPolicy, nameIDPolicy);
556
557 /* if nameIDPolicy is 'onetime' => nothing to do */
558 if (strcmp(nameIDPolicy, LASSO_LIB_NAMEID_POLICY_TYPE_ONE_TIME) == 0) {
559 return 0;
560 }
561
562 /* search a federation in the identity */
563 federation = g_hash_table_lookup(profile->identity->federations,
564 profile->remote_providerID);
565
566 if (strcmp(nameIDPolicy, LASSO_LIB_NAMEID_POLICY_TYPE_NONE) == 0) {
567 /* a federation MUST exist */
568 if (federation == NULL) {
569 /* if protocolProfile is LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST
570 * set StatusCode to FederationDoesNotExist in lib:AuthnResponse
571 */
572 lasso_profile_set_response_status(LASSO_PROFILE(login),
573 LASSO_LIB_STATUS_CODE_FEDERATION_DOES_NOT_EXIST);
574 return LASSO_LOGIN_ERROR_FEDERATION_NOT_FOUND;
575 }
576
577 lasso_assign_gobject(LASSO_PROFILE(login)->nameIdentifier,
578 LASSO_SAML_NAME_IDENTIFIER(federation->local_nameIdentifier));
579 return 0;
580 }
581
582 if (strcmp(nameIDPolicy, LASSO_LIB_NAMEID_POLICY_TYPE_FEDERATED) != 0 &&
583 strcmp(nameIDPolicy, LASSO_LIB_NAMEID_POLICY_TYPE_ANY) != 0) {
584 return critical_error(LASSO_LOGIN_ERROR_INVALID_NAMEIDPOLICY);
585 }
586
587 /* consent is necessary, it should be obtained via consent attribute
588 * in lib:AuthnRequest or IDP should ask the Principal
589 */
590 if (lasso_login_must_ask_for_consent_private(login) && !is_consent_obtained) {
591 if (strcmp(nameIDPolicy, LASSO_LIB_NAMEID_POLICY_TYPE_ANY) == 0) {
592 /* if the NameIDPolicy element is 'any' and if the policy
593 * for the Principal forbids federation, then evaluation
594 * MAY proceed as if the value was 'onetime'.
595 */
596 lasso_assign_string(login->nameIDPolicy, LASSO_LIB_NAMEID_POLICY_TYPE_ONE_TIME);
597 return 0;
598 }
599
600 /* if protocolProfile is LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST
601 * set StatusCode to FederationDoesNotExist in lib:AuthnResponse
602 */
603 /* FIXME : is it the correct value for the StatusCode ? */
604 lasso_profile_set_response_status(LASSO_PROFILE(login),
605 LASSO_LIB_STATUS_CODE_FEDERATION_DOES_NOT_EXIST);
606 return LASSO_LOGIN_ERROR_CONSENT_NOT_OBTAINED;
607 }
608
609 if (federation == NULL) {
610 federation = lasso_federation_new(LASSO_PROFILE(login)->remote_providerID);
611 lasso_federation_build_local_name_identifier(federation,
612 LASSO_PROVIDER(LASSO_PROFILE(login)->server)->ProviderID,
613 LASSO_LIB_NAME_IDENTIFIER_FORMAT_FEDERATED,
614 NULL);
615 lasso_identity_add_federation(LASSO_PROFILE(login)->identity, federation);
616 }
617
618 lasso_assign_gobject(LASSO_PROFILE(login)->nameIdentifier,
619 LASSO_SAML_NAME_IDENTIFIER(federation->local_nameIdentifier));
620
621 return ret;
622 }
623
624 static gint
lasso_login_process_response_status_and_assertion(LassoLogin * login)625 lasso_login_process_response_status_and_assertion(LassoLogin *login)
626 {
627 LassoProvider *idp;
628 LassoSamlpResponse *response;
629 char *status_value;
630 LassoSamlSubjectStatementAbstract *sssa = NULL;
631 LassoSamlSubjectStatementAbstract *sas = NULL;
632 int rc = 0;
633
634 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
635
636 response = LASSO_SAMLP_RESPONSE(LASSO_PROFILE(login)->response);
637
638 if (response->Status == NULL || ! LASSO_IS_SAMLP_STATUS(response->Status) ||
639 response->Status->StatusCode == NULL ||
640 response->Status->StatusCode->Value == NULL) {
641 return LASSO_PROFILE_ERROR_MISSING_STATUS_CODE;
642 }
643
644 status_value = response->Status->StatusCode->Value;
645 if (status_value && strcmp(status_value, LASSO_SAML_STATUS_CODE_SUCCESS) != 0) {
646 if (strcmp(status_value, LASSO_SAML_STATUS_CODE_REQUEST_DENIED) == 0)
647 return LASSO_LOGIN_ERROR_REQUEST_DENIED;
648 if (strcmp(status_value, LASSO_SAML_STATUS_CODE_RESPONDER) == 0) {
649 /* samlp:Responder */
650 if (response->Status->StatusCode->StatusCode &&
651 response->Status->StatusCode->StatusCode->Value) {
652 status_value = response->Status->StatusCode->StatusCode->Value;
653 if (strcmp(status_value,
654 LASSO_LIB_STATUS_CODE_FEDERATION_DOES_NOT_EXIST) == 0) {
655 return LASSO_LOGIN_ERROR_FEDERATION_NOT_FOUND;
656 }
657 if (strcmp(status_value,
658 LASSO_LIB_STATUS_CODE_UNKNOWN_PRINCIPAL) == 0) {
659 return LASSO_LOGIN_ERROR_UNKNOWN_PRINCIPAL;
660 }
661 }
662 }
663 return LASSO_LOGIN_ERROR_STATUS_NOT_SUCCESS;
664 }
665
666 if (response->Assertion) {
667 LassoProfile *profile = LASSO_PROFILE(login);
668 LassoSamlAssertion *assertion = response->Assertion->data;
669 LassoLibAssertion *lib_assertion = NULL;
670
671 if (LASSO_IS_LIB_ASSERTION(assertion)) {
672 lib_assertion = LASSO_LIB_ASSERTION(assertion);
673 }
674
675 idp = lasso_server_get_provider(profile->server, profile->remote_providerID);
676 if (idp == NULL) {
677 return LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND;
678 }
679
680 /* Validate AuthnRequest RequestID and InResponseTo */
681 {
682 char *previous_reqid = login->private_data->request_id;
683 if (previous_reqid) {
684 if (lib_assertion == NULL ||
685 lib_assertion->InResponseTo == NULL ||
686 strcmp(lib_assertion->InResponseTo, previous_reqid) != 0) {
687 return critical_error(LASSO_LOGIN_ERROR_ASSERTION_DOES_NOT_MATCH_REQUEST_ID);
688 }
689 }
690 }
691
692 /* If the status of the signature verification process is not 0, we try to verify on
693 * the assertion */
694 if (profile->signature_status != 0) {
695 xmlNode *assertion_xmlnode;
696 gchar *assertion_issuer;
697
698 assertion_xmlnode = lasso_node_get_original_xmlnode(LASSO_NODE(assertion));
699 assertion_issuer = (gchar*)xmlGetProp(assertion_xmlnode, (xmlChar*)"Issuer");
700 goto_cleanup_if_fail_with_rc(assertion_issuer, LASSO_PROFILE_ERROR_MISSING_ISSUER);
701 goto_cleanup_if_fail_with_rc(strcmp(assertion_issuer, profile->remote_providerID) == 0,
702 LASSO_PROFILE_ERROR_INVALID_ISSUER);
703
704 if (assertion_xmlnode) {
705 profile->signature_status = lasso_provider_verify_saml_signature(idp, assertion_xmlnode, NULL);
706 goto_cleanup_if_fail_with_rc(profile->signature_status == 0, profile->signature_status);
707 }
708 }
709
710 lasso_release_gobject(profile->nameIdentifier);
711
712 /* Retrieve the name identifier from one of the statements */
713 if (assertion->AuthenticationStatement) {
714 sssa = LASSO_SAML_SUBJECT_STATEMENT_ABSTRACT(
715 assertion->AuthenticationStatement);
716 if (sssa->Subject && sssa->Subject->NameIdentifier) {
717 lasso_assign_gobject(profile->nameIdentifier,
718 LASSO_NODE(sssa->Subject->NameIdentifier));
719 }
720 }
721
722 if (profile->nameIdentifier == NULL && assertion->AttributeStatement) {
723 sas = LASSO_SAML_SUBJECT_STATEMENT_ABSTRACT(assertion->AttributeStatement);
724 if (sas->Subject && sas->Subject->NameIdentifier) {
725 lasso_assign_gobject(profile->nameIdentifier,
726 LASSO_NODE(sas->Subject->NameIdentifier));
727 }
728 }
729
730 if (profile->nameIdentifier == NULL) {
731 return LASSO_PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND;
732 }
733
734 }
735 cleanup:
736
737 return rc;
738 }
739
740 /*****************************************************************************/
741 /* public methods */
742 /*****************************************************************************/
743
744 /**
745 * lasso_login_accept_sso:
746 * @login: a #LassoLogin
747 *
748 * Gets the assertion of the response and adds it to the #LassoSession object.
749 * Builds a federation with the 2 name identifiers of the assertion
750 * and adds it into the identity.
751 * If the session or the identity are NULL, they are created.
752 *
753 * Return value: 0 on success; or
754 * <itemizedlist>
755 * <listitem><para>
756 * #LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin object,
757 * </para></listitem>
758 * <listitem><para>
759 * #LASSO_PROFILE_ERROR_MISSING_RESPONSE if no response is present in the login profile object;
760 * usually because no call to lasso_login_process_authn_response_msg was done;
761 * </para></listitem>
762 * <listitem><para>
763 * #LASSO_PROFILE_ERROR_MISSING_ASSERTION if the response does not contain an assertion,
764 * </para></listitem>
765 * <listitem><para>
766 * #LASSO_PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND if the assertion does not contain a NameID element,
767 * </para></listitem>
768 * <listitem><para>
769 * #LASSO_PROFILE_ERROR_MISSING_NAME_IDENTIFIER same as
770 * #LASSO_PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND,
771 * </para></listitem>
772 * <listitem><para>
773 * #LASSO_LOGIN_ERROR_ASSERTION_REPLAY if the assertion has already been used.
774 * </para></listitem>
775 * </itemizedlist>
776 **/
777 gint
lasso_login_accept_sso(LassoLogin * login)778 lasso_login_accept_sso(LassoLogin *login)
779 {
780 LassoProfile *profile;
781 LassoSamlAssertion *assertion;
782 LassoSamlNameIdentifier *ni, *idp_ni = NULL;
783 LassoFederation *federation;
784 LassoSamlSubjectStatementAbstract *authentication_statement;
785
786 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
787
788 profile = LASSO_PROFILE(login);
789
790 if (profile->identity == NULL)
791 profile->identity = lasso_identity_new();
792
793 if (profile->session == NULL)
794 profile->session = lasso_session_new();
795
796 if (profile->response == NULL)
797 return LASSO_PROFILE_ERROR_MISSING_RESPONSE;
798
799 IF_SAML2(profile) {
800 return lasso_saml20_login_accept_sso(login);
801 }
802
803 if (LASSO_SAMLP_RESPONSE(profile->response)->Assertion == NULL)
804 return LASSO_PROFILE_ERROR_MISSING_ASSERTION;
805
806 assertion = LASSO_SAMLP_RESPONSE(profile->response)->Assertion->data;
807 if (assertion == NULL)
808 return LASSO_PROFILE_ERROR_MISSING_ASSERTION;
809
810 lasso_session_add_assertion(profile->session, profile->remote_providerID,
811 LASSO_NODE(assertion));
812
813 authentication_statement = LASSO_SAML_SUBJECT_STATEMENT_ABSTRACT(
814 assertion->AuthenticationStatement);
815 if (authentication_statement->Subject == NULL)
816 return LASSO_PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND;
817
818 ni = authentication_statement->Subject->NameIdentifier;
819
820 if (ni == NULL)
821 return LASSO_PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND;
822
823 if (LASSO_IS_LIB_SUBJECT(authentication_statement->Subject)) {
824 idp_ni = LASSO_LIB_SUBJECT(
825 authentication_statement->Subject)->IDPProvidedNameIdentifier;
826 }
827
828 /* create federation, only if nameidentifier format is Federated */
829 if (ni->Format && strcmp(ni->Format, LASSO_LIB_NAME_IDENTIFIER_FORMAT_FEDERATED) == 0) {
830 federation = lasso_federation_new(LASSO_PROFILE(login)->remote_providerID);
831 if (ni != NULL && idp_ni != NULL) {
832 federation->local_nameIdentifier = LASSO_NODE(g_object_ref(ni));
833 federation->remote_nameIdentifier = LASSO_NODE(g_object_ref(idp_ni));
834 } else {
835 federation->remote_nameIdentifier = LASSO_NODE(g_object_ref(ni));
836 }
837 /* add federation in identity */
838 lasso_identity_add_federation(LASSO_PROFILE(login)->identity, federation);
839 }
840
841 return 0;
842 }
843
844 static void
lasso_login_build_assertion_artifact(LassoLogin * login)845 lasso_login_build_assertion_artifact(LassoLogin *login)
846 {
847 xmlSecByte samlArt[42], *b64_samlArt;
848 char *identityProviderSuccinctID;
849
850 identityProviderSuccinctID = lasso_sha1(
851 LASSO_PROVIDER(LASSO_PROFILE(login)->server)->ProviderID);
852
853 /* Artifact Format is described in "Binding Profiles", 3.2.2.2. */
854 memcpy(samlArt, "\000\003", 2); /* type code */
855 memcpy(samlArt+2, identityProviderSuccinctID, 20);
856 lasso_build_random_sequence((char*)samlArt+22, 20);
857
858 xmlFree(identityProviderSuccinctID);
859 b64_samlArt = xmlSecBase64Encode(samlArt, 42, 0);
860
861 lasso_assign_string(login->assertionArtifact, (char*)b64_samlArt);
862 lasso_assign_string(login->parent.private_data->artifact,
863 (char*)b64_samlArt);
864 lasso_release_xml_string(b64_samlArt);
865 }
866
867 /**
868 * lasso_login_build_artifact_msg:
869 * @login: a #LassoLogin
870 * @http_method: the HTTP method to send the artifact (REDIRECT or POST)
871 *
872 * Builds a SAML artifact. Depending of the HTTP method, the data for the sending of
873 * the artifact are stored in @msg_url (REDIRECT) or @msg_url, @msg_body and
874 * @msg_relayState (POST).
875 *
876 * Return value: 0 on success; or
877 * <itemizedlist>
878 * <listitem><para>
879 * LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin object,
880 * </para></listitem>
881 * <listitem><para>
882 * LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID if no remote provider ID was setup in the login
883 * profile object, it's usually done by lasso_login_process_authn_request_msg,
884 * </para></listitem>
885 * <listitem><para>
886 * LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD if the HTTP method is neither LASSO_HTTP_METHOD_REDIRECT
887 * or LASSO_HTTP_METHOD_POST (ID-FF 1.2 case) or neither LASSO_HTTP_METHOD_ARTIFACT_GET or
888 * LASSO_HTTP_METHOD_ARTIFACT_POST (SAML 2.0 case) for SAML 2.0),
889 * </para></listitem>
890 * <listitem><para>
891 * LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE if the current protocolProfile is not
892 * </para></listitem>
893 * <listitem><para>
894 * LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART (only for ID-FF 1.2),
895 * </para></listitem>
896 * <listitem><para>
897 * LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND if the remote provider is not known to our server object
898 * which impeach us to find a service endpoint,
899 * </para></listitem>
900 * <listitem><para>
901 * LASSO_PROFILE_ERROR_MISSING_RESPONSE if the response object is missing,
902 * </para></listitem>
903 * <listitem><para>
904 * LASSO_PROFILE_ERROR_MISSING_STATUS_CODE if the response object is missing a status code,
905 * </para></listitem>
906 *</itemizedlist>
907 *
908 **/
909 gint
lasso_login_build_artifact_msg(LassoLogin * login,LassoHttpMethod http_method)910 lasso_login_build_artifact_msg(LassoLogin *login, LassoHttpMethod http_method)
911 {
912 LassoProvider *remote_provider = NULL;
913 LassoProfile *profile = NULL;
914 gchar *url = NULL;
915 xmlChar *b64_samlArt = NULL;
916 xmlChar *relayState = NULL;
917 gint rc = 0;
918
919 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
920
921 profile = LASSO_PROFILE(login);
922 lasso_profile_clean_msg_info(profile);
923
924 if (profile->remote_providerID == NULL) {
925 /* this means lasso_login_init_request was not called before */
926 goto_cleanup_with_rc(LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID);
927 }
928
929 IF_SAML2(profile) {
930 return lasso_saml20_login_build_artifact_msg(login, http_method);
931 }
932
933 if (http_method != LASSO_HTTP_METHOD_REDIRECT && http_method != LASSO_HTTP_METHOD_POST) {
934 goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD);
935 }
936
937 /* ProtocolProfile must be BrwsArt */
938 if (login->protocolProfile != LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART) {
939 goto_cleanup_with_rc(LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE);
940 }
941
942 /* build artifact infos */
943 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
944 if (LASSO_IS_PROVIDER(remote_provider) == FALSE)
945 goto_cleanup_with_rc(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
946
947 url = lasso_provider_get_assertion_consumer_service_url(remote_provider,
948 LASSO_LIB_AUTHN_REQUEST(profile->request)->AssertionConsumerServiceID);
949 if (url == NULL) {
950 /* from draft-liberty-idff-protocols-schema-1.2-errata-v2.0.pdf
951 * paragraph starting line 768,
952 *
953 * If the <AssertionConsumerServiceID> element is provided,
954 * then the identity provider MUST search for the value among
955 * the id attributes in the <AssertionConsumerServiceURL>
956 * elements in the provider's metadata to determine the URL
957 * to use. If no match can be found, then the provider MUST
958 * return an error with a second-level <samlp:StatusCode> of
959 * lib:InvalidAssertionConsumerServiceIndex to the default URL
960 */
961 lasso_profile_set_response_status(profile,
962 LASSO_LIB_STATUS_CODE_INVALID_ASSERTION_CONSUMER_SERVICE_INDEX);
963 url = lasso_provider_get_assertion_consumer_service_url(
964 remote_provider, NULL);
965 }
966
967 /* it may have been created in lasso_login_build_assertion */
968 if (login->assertionArtifact == NULL)
969 lasso_login_build_assertion_artifact(login);
970
971 if (login->assertion) {
972 LassoSamlAssertion *assertion = login->assertion;
973 LassoSamlSubjectStatementAbstract *ss;
974
975 ss = LASSO_SAML_SUBJECT_STATEMENT_ABSTRACT(assertion->AuthenticationStatement);
976 /* Subject and SubjectConfirmation should never be NULL
977 * because they're built by Lasso
978 */
979 if (ss->Subject != NULL && ss->Subject->SubjectConfirmation != NULL) {
980 if (assertion->MajorVersion == 1 && assertion->MinorVersion == 0) {
981 lasso_list_add_string(ss->Subject->SubjectConfirmation->ConfirmationMethod,
982 LASSO_SAML_CONFIRMATION_METHOD_ARTIFACT01);
983 } else {
984 lasso_list_add_string(ss->Subject->SubjectConfirmation->ConfirmationMethod,
985 LASSO_SAML_CONFIRMATION_METHOD_ARTIFACT);
986 }
987 }
988 }
989
990 b64_samlArt = xmlStrdup((xmlChar*)login->assertionArtifact);
991 relayState = lasso_xmlURIEscapeStr(
992 (xmlChar*)LASSO_LIB_AUTHN_REQUEST(profile->request)->RelayState, NULL);
993
994 if (http_method == LASSO_HTTP_METHOD_REDIRECT) {
995 xmlChar *escaped_artifact = lasso_xmlURIEscapeStr(b64_samlArt, NULL);
996 gchar *query = NULL;
997
998 if (relayState == NULL) {
999 query = g_strdup_printf("SAMLart=%s", escaped_artifact);
1000 } else {
1001 query = g_strdup_printf("SAMLart=%s&RelayState=%s",
1002 escaped_artifact, relayState);
1003 }
1004 lasso_assign_new_string(profile->msg_url, lasso_concat_url_query(url, query));
1005 lasso_release_string(query);
1006 lasso_release_xml_string(escaped_artifact);
1007 }
1008
1009 if (http_method == LASSO_HTTP_METHOD_POST) {
1010 lasso_assign_string(profile->msg_url, url);
1011 lasso_assign_string(profile->msg_body, (char*)b64_samlArt);
1012 if (relayState != NULL) {
1013 lasso_assign_string(profile->msg_relayState, (char*)relayState);
1014 }
1015 }
1016
1017 if (strcmp(LASSO_SAMLP_RESPONSE(profile->response)->Status->StatusCode->Value,
1018 LASSO_SAML_STATUS_CODE_SUCCESS) != 0) {
1019 if (profile->session == NULL)
1020 profile->session = lasso_session_new();
1021
1022 lasso_session_add_status(profile->session, profile->remote_providerID,
1023 LASSO_NODE(g_object_ref(LASSO_SAMLP_RESPONSE(profile->response)->Status)));
1024 } else {
1025 lasso_session_remove_status(profile->session, profile->remote_providerID);
1026 }
1027
1028 /* store the response as the artifact message */
1029 lasso_check_good_rc(lasso_server_set_signature_for_provider_by_name(
1030 profile->server,
1031 profile->remote_providerID,
1032 profile->response));
1033 /* comply with the new way of storing artifacts */
1034 lasso_assign_string(profile->private_data->artifact,
1035 login->assertionArtifact);
1036 /* Artifact profile for ID-FF 1.2 is special, this is not the full message which is relayed
1037 * but only its assertion content, the Response container is changed from a
1038 * lib:AuthnResponse to a samlp:Response.
1039 */
1040 lasso_assign_new_string(profile->private_data->artifact_message,
1041 lasso_node_export_to_xml((LassoNode*)login->assertion));
1042 cleanup:
1043 lasso_release_string(url);
1044 lasso_release_xml_string(b64_samlArt);
1045 lasso_release_xml_string(relayState);
1046 return rc;
1047 }
1048
1049 /**
1050 * lasso_login_build_authn_request_msg:
1051 * @login: a #LassoLogin
1052 *
1053 * Converts profile authentication request (@request member) into a Liberty message, either an URL
1054 * in HTTP-Redirect profile or an URL and a field value in Browser-POST (form) profile.
1055 *
1056 * The URL is set into the @msg_url member and the eventual field value (LAREQ) is set into the
1057 * @msg_body member.
1058 *
1059 * Return value: 0 on success; or
1060 * <itemizedlist>
1061 * <listitem><para>
1062 * #LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin object,
1063 * </para></listitem>
1064 * <listitem><para>
1065 * #LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID if not remote provider ID was setup&160;- it usually
1066 * means that lasso_login_init_request() was not called before,
1067 * </para></listitem>
1068 * <listitem><para>
1069 * #LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND if the remote provider ID is not registered in the server
1070 * object,
1071 * </para></listitem>
1072 * <listitem><para>
1073 * #LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE if the SSO profile is not supported by the targeted
1074 * provider,
1075 * </para></listitem>
1076 * <listitem><para>
1077 * #LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED if the building of the query part of the redirect URL
1078 * or of the body of the POST content failed&160;- it only happens with the #LASSO_HTTP_METHOD_REDIRECT,
1079 * #LASSO_HTTP_METHOD_POST, #LASSO_HTTP_METHOD_ARTIFACT_GET and
1080 * #LASSO_HTTP_METHOD_ARTIFACT_POST bindings&160;-,
1081 * </para></listitem>
1082 * <listitem><para>
1083 * #LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL if the metadata of the remote provider does not contain
1084 * an url for the SSO profile,
1085 * </para></listitem>
1086 * <listitem><para>
1087 * #LASSO_PROFILE_ERROR_INVALID_REQUEST if the request object is not of the needed type, is usually
1088 * means that lasso_login_init_request() was not called before,
1089 * </para></listitem>
1090 * <listitem><para>
1091 * #LASSO_PROFILE_MISSING_REQUEST if the request object is missing,
1092 * </para></listitem>
1093 * <listitem><para>
1094 * #LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD if the current setted @http_method on the #LassoLogin
1095 * object is invalid.
1096 * </para></listitem>
1097 * </itemizedlist>
1098 **/
1099 lasso_error_t
lasso_login_build_authn_request_msg(LassoLogin * login)1100 lasso_login_build_authn_request_msg(LassoLogin *login)
1101 {
1102 LassoProvider *provider, *remote_provider;
1103 LassoProfile *profile;
1104 char *md_authnRequestsSigned, *url, *query = NULL, *lareq, *protocolProfile;
1105 LassoProviderRole role, remote_role;
1106 gboolean must_sign;
1107 gint rc = 0;
1108
1109 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1110 profile = LASSO_PROFILE(login);
1111 lasso_profile_clean_msg_info(profile);
1112
1113 /* With PAOS ECP there is no remote provider, don't check for it, go straight to saml2.0 */
1114 if (login->http_method == LASSO_HTTP_METHOD_PAOS) {
1115 return lasso_saml20_login_build_authn_request_msg(login);
1116 }
1117 if (profile->remote_providerID == NULL) {
1118 /* this means lasso_login_init_request was not called before */
1119 return critical_error(LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID);
1120 }
1121
1122 provider = LASSO_PROVIDER(profile->server);
1123 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
1124 if (LASSO_IS_PROVIDER(remote_provider) == FALSE) {
1125 return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
1126 }
1127
1128 IF_SAML2(profile) {
1129 return lasso_saml20_login_build_authn_request_msg(login);
1130 }
1131
1132 protocolProfile = LASSO_LIB_AUTHN_REQUEST(profile->request)->ProtocolProfile;
1133 if (protocolProfile == NULL)
1134 protocolProfile = LASSO_LIB_PROTOCOL_PROFILE_BRWS_ART;
1135
1136 role = provider->role;
1137 provider->role = LASSO_PROVIDER_ROLE_SP; /* we act as an SP for sure here */
1138 remote_role = remote_provider->role;
1139 remote_provider->role = LASSO_PROVIDER_ROLE_IDP; /* and remote is IdP */
1140
1141 if (lasso_provider_has_protocol_profile(remote_provider,
1142 LASSO_MD_PROTOCOL_TYPE_SINGLE_SIGN_ON, protocolProfile) == FALSE) {
1143 provider->role = role;
1144 remote_provider->role = remote_role;
1145 return LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE;
1146 }
1147
1148 /* check if authnRequest must be signed */
1149 md_authnRequestsSigned = lasso_provider_get_metadata_one(provider, "AuthnRequestsSigned");
1150 must_sign = (md_authnRequestsSigned && strcmp(md_authnRequestsSigned, "true") == 0);
1151 lasso_release_string(md_authnRequestsSigned);
1152
1153 /* restore original roles */
1154 provider->role = role;
1155 remote_provider->role = remote_role;
1156
1157 if (login->http_method == LASSO_HTTP_METHOD_REDIRECT) {
1158 /* REDIRECT -> query */
1159 if (must_sign) {
1160 lasso_check_good_rc(lasso_server_export_to_query_for_provider_by_name(profile->server,
1161 profile->remote_providerID,
1162 profile->request, &query));
1163 } else {
1164 query = lasso_node_build_query(LASSO_NODE(profile->request));
1165 }
1166 if (query == NULL) {
1167 return critical_error(LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED);
1168 }
1169
1170 /* get SingleSignOnServiceURL metadata */
1171 url = lasso_provider_get_metadata_one(remote_provider, "SingleSignOnServiceURL");
1172 if (url == NULL) {
1173 return critical_error(LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL);
1174 }
1175
1176 lasso_assign_new_string(profile->msg_url, lasso_concat_url_query(url, query));
1177 lasso_release_string(profile->msg_body);
1178 lasso_release_string(query);
1179 lasso_release_string(url);
1180 }
1181 if (login->http_method == LASSO_HTTP_METHOD_POST) {
1182 if (must_sign) {
1183 lasso_server_set_signature_for_provider_by_name(profile->server,
1184 profile->remote_providerID,
1185 profile->request);
1186 }
1187 lareq = lasso_node_export_to_base64(profile->request);
1188
1189 if (lareq == NULL) {
1190 return critical_error(LASSO_PROFILE_ERROR_BUILDING_QUERY_FAILED);
1191 }
1192
1193 lasso_assign_new_string(profile->msg_url, lasso_provider_get_metadata_one(
1194 remote_provider, "SingleSignOnServiceURL"));
1195 lasso_assign_new_string(profile->msg_body, lareq);
1196 }
1197
1198 cleanup:
1199 return rc;
1200 }
1201
1202 /**
1203 * lasso_login_build_authn_response_msg:
1204 * @login: a #LassoLogin
1205 *
1206 * Converts profile authentication response (@response member) into a Liberty
1207 * message.
1208 *
1209 * The URL is set into the @msg_url member and the field value (LARES) is set
1210 * into the @msg_body member.
1211 *
1212 * Return value: 0 on success; or
1213 * <itemizedlist>
1214 * <listitem><para>
1215 * LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin object,
1216 * </para></listitem>
1217 * <listitem><para>
1218 * LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE if the current protocol profile is not
1219 * </para></listitem>
1220 * <listitem><para>
1221 * LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST or LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP,
1222 * </para></listitem>
1223 * <listitem><para>
1224 * LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND if the remote provider ID is not registered in the server
1225 * object,
1226 * </para></listitem>
1227 * <listitem><para>
1228 * LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL if the metadata of the remote provider does not contain
1229 * an URL for the assertion consuming service,
1230 * </para></listitem>
1231 * <listitem><para>
1232 * LASSO_PROFILE_ERROR_MISSING_SERVER the server object is needed to sign a message and it is
1233 * missing,
1234 * </para></listitem>
1235 * <listitem><para>
1236 * LASSO_DS_ERROR_PRIVATE_KEY_LOAD_FAILED the private key for signing could not be found,
1237 * </para></listitem>
1238 * <listitem><para>
1239 * LASSO_PROFILE_ERROR_MISSING_RESPONSE if the response object is missing,
1240 * </para></listitem>
1241 * <listitem><para>
1242 * LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE if the SSO profile is not supported by the targeted
1243 * provider,
1244 * </para></listitem>
1245 * <listitem><para>
1246 * LASSO_PROFILE_BUILDING_QUERY_FAILED if using #LASSO_HTTP_METHOD_REDIRECT building of the redirect
1247 * URL failed,
1248 * </para></listitem>
1249 * <listitem><para>
1250 * LASSO_PROFILE_BUILDING_MSG_FAILED if using #LASSO_HTTP_METHOD_POST, #LASSO_HTTP_METHOD_SOAP or
1251 * #LASSO_HTTP_METHOD_PAOS and building the @msg_body failed.
1252 * </para></listitem>
1253 * </itemizedlist>
1254 *
1255 **/
1256 gint
lasso_login_build_authn_response_msg(LassoLogin * login)1257 lasso_login_build_authn_response_msg(LassoLogin *login)
1258 {
1259 LassoProvider *remote_provider = NULL;
1260 LassoProfile *profile = NULL;
1261 lasso_error_t rc = 0;
1262
1263 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1264
1265 profile = LASSO_PROFILE(login);
1266 lasso_profile_clean_msg_info(profile);
1267
1268 IF_SAML2(profile) {
1269 return lasso_saml20_login_build_authn_response_msg(login);
1270 }
1271
1272 /* ProtocolProfile must be BrwsPost */
1273 if (login->protocolProfile != LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST &&
1274 login->protocolProfile != LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP) {
1275 return critical_error(LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE);
1276 }
1277
1278 if (login->assertion) {
1279 LassoSamlAssertion *assertion = login->assertion;
1280 LassoSamlSubjectStatementAbstract *ss;
1281 ss = LASSO_SAML_SUBJECT_STATEMENT_ABSTRACT(assertion->AuthenticationStatement);
1282 if (ss->Subject && ss->Subject->SubjectConfirmation) {
1283 lasso_list_add_string(ss->Subject->SubjectConfirmation->ConfirmationMethod,
1284 LASSO_SAML_CONFIRMATION_METHOD_BEARER);
1285 }
1286 }
1287
1288 /* Countermeasure: The issuer should sign <lib:AuthnResponse> messages.
1289 * (binding and profiles (1.2errata2, page 65) */
1290 lasso_check_good_rc(lasso_server_set_signature_for_provider_by_name(
1291 profile->server,
1292 profile->remote_providerID,
1293 profile->response));
1294
1295 /* build an lib:AuthnResponse base64 encoded */
1296 lasso_assign_new_string(profile->msg_body,
1297 lasso_node_export_to_base64(LASSO_NODE(profile->response)));
1298
1299 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
1300 if (LASSO_IS_PROVIDER(remote_provider) == FALSE)
1301 return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
1302 lasso_assign_new_string(profile->msg_url, lasso_provider_get_assertion_consumer_service_url(remote_provider,
1303 LASSO_LIB_AUTHN_REQUEST(profile->request)->AssertionConsumerServiceID));
1304 if (profile->msg_url == NULL) {
1305 return LASSO_PROFILE_ERROR_UNKNOWN_PROFILE_URL;
1306 }
1307 cleanup:
1308 return rc;
1309 }
1310
1311 /**
1312 * lasso_login_build_request_msg:
1313 * @login: a #LassoLogin
1314 *
1315 * Produce a SOAP Artifact Resolve message. It must follows a call to
1316 * lasso_login_init_request() on the artifact message.
1317 * Converts artifact request into a Liberty SOAP message.
1318 *
1319 * The URL is set into the @msg_url member and the SOAP message is set into the
1320 * @msg_body member. You should POST the @msg_body to the @msg_url afterward.
1321 *
1322 * Return value: 0 on success; or
1323 * LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin object,
1324 * LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID if not remote provider ID was setup -- it usually
1325 * means that lasso_login_init_request was not called before,
1326 * LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND if the remote provider ID is not registered in the server
1327 * object.
1328 *
1329 **/
1330 gint
lasso_login_build_request_msg(LassoLogin * login)1331 lasso_login_build_request_msg(LassoLogin *login)
1332 {
1333 LassoProvider *remote_provider;
1334 LassoProfile *profile;
1335 lasso_error_t rc = 0;
1336
1337 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1338
1339 profile = LASSO_PROFILE(login);
1340 lasso_profile_clean_msg_info(profile);
1341
1342 IF_SAML2(profile) {
1343 return lasso_saml20_login_build_request_msg(login);
1344 }
1345
1346 if (profile->remote_providerID == NULL) {
1347 /* this means lasso_login_init_request was not called before */
1348 return critical_error(LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID);
1349 }
1350
1351 lasso_check_good_rc(lasso_server_set_signature_for_provider_by_name(
1352 profile->server,
1353 profile->remote_providerID,
1354 profile->request));
1355 lasso_assign_new_string(profile->msg_body, lasso_node_export_to_soap(profile->request));
1356
1357 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
1358 if (LASSO_IS_PROVIDER(remote_provider) == FALSE) {
1359 return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
1360 }
1361 lasso_assign_new_string(profile->msg_url, lasso_provider_get_metadata_one(remote_provider, "SoapEndpoint"));
1362 cleanup:
1363 return rc;
1364 }
1365
1366 /**
1367 * lasso_login_build_response_msg:
1368 * @login: a #LassoLogin
1369 * @remote_providerID: service provider ID
1370 *
1371 * Converts profile assertion response (@response member) into a Liberty SOAP
1372 * messageresponse message.
1373 *
1374 * The URL is set into the @msg_url member and the SOAP message is set into the
1375 * @msg_body member.
1376 *
1377 * Return value: 0 on success; or a negative value otherwise.
1378 * LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin object,
1379 * LASSO_PROFILE_ERROR_SESSION_NOT_FOUND if no session object was found in the login profile object
1380 * -- it should be created by lasso_login_build_assertion() if you did not set it manually before
1381 * calling lasso_login_build_assertion().
1382 *
1383 **/
1384 gint
lasso_login_build_response_msg(LassoLogin * login,gchar * remote_providerID)1385 lasso_login_build_response_msg(LassoLogin *login, gchar *remote_providerID)
1386 {
1387 LassoProvider *remote_provider = NULL;
1388 LassoProfile *profile = NULL;
1389 lasso_error_t rc = 0;
1390
1391 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1392 profile = LASSO_PROFILE(login);
1393 lasso_profile_clean_msg_info(profile);
1394
1395 IF_SAML2(profile) {
1396 return lasso_saml20_login_build_response_msg(login);
1397 }
1398
1399 lasso_assign_new_gobject(profile->response, lasso_samlp_response_new());
1400 lasso_assign_string(LASSO_SAMLP_RESPONSE_ABSTRACT(profile->response)->InResponseTo,
1401 LASSO_SAMLP_REQUEST_ABSTRACT(profile->request)->RequestID);
1402 if (LASSO_SAMLP_REQUEST_ABSTRACT(profile->request)->MajorVersion == 1 &&
1403 LASSO_SAMLP_REQUEST_ABSTRACT(profile->request)->MinorVersion == 0) {
1404 /* this is a SAML 1.0 request, must create SAML 1.0 response */
1405 LASSO_SAMLP_RESPONSE_ABSTRACT(profile->response)->MinorVersion = 0;
1406 }
1407
1408 if (remote_providerID != NULL) {
1409 lasso_assign_string(profile->remote_providerID, remote_providerID);
1410 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
1411 rc = lasso_provider_verify_signature(remote_provider,
1412 login->private_data->soap_request_msg,
1413 "RequestID", LASSO_MESSAGE_FORMAT_SOAP);
1414 lasso_release_string(login->private_data->soap_request_msg);
1415
1416 /* lasso_profile_set_session_from_dump has not been called */
1417 if (profile->session == NULL) {
1418 rc = LASSO_PROFILE_ERROR_SESSION_NOT_FOUND;
1419 }
1420
1421 /* change status code into RequestDenied if signature is
1422 * invalid or not found or if an error occurs during
1423 * verification */
1424 if (rc != 0) {
1425 lasso_profile_set_response_status(profile,
1426 LASSO_SAML_STATUS_CODE_REQUEST_DENIED);
1427 }
1428
1429 if (rc == 0) {
1430 /* get assertion in session and add it in response */
1431 LassoSamlAssertion *assertion;
1432 LassoSamlpStatus *status;
1433
1434 status = LASSO_SAMLP_STATUS(lasso_session_get_status(
1435 profile->session, remote_providerID));
1436 assertion = LASSO_SAML_ASSERTION(
1437 lasso_session_get_assertion(profile->session,
1438 profile->remote_providerID));
1439 if (status) {
1440 lasso_assign_gobject(LASSO_SAMLP_RESPONSE(profile->response)->Status,
1441 status);
1442 lasso_session_remove_status(profile->session,
1443 remote_providerID);
1444 } else if (assertion) {
1445 lasso_list_add_gobject(LASSO_SAMLP_RESPONSE(profile->response)->Assertion,
1446 assertion);
1447 lasso_profile_set_response_status(profile,
1448 LASSO_SAML_STATUS_CODE_SUCCESS);
1449 lasso_session_remove_status(profile->session, remote_providerID);
1450 } else if (profile->private_data->artifact_message) {
1451 xmlDoc *doc;
1452 char *artifact_message = profile->private_data->artifact_message;
1453 doc = lasso_xml_parse_memory(artifact_message,
1454 strlen(artifact_message));
1455 lasso_profile_set_response_status(profile,
1456 LASSO_SAML_STATUS_CODE_SUCCESS);
1457 lasso_list_add_new_gobject(((LassoSamlpResponse*)profile->response)->Assertion,
1458 lasso_misc_text_node_new_with_xml_node(xmlDocGetRootElement(doc)));
1459 lasso_release_doc(doc);
1460 }
1461 }
1462 } else {
1463 lasso_profile_set_response_status(profile, LASSO_SAML_STATUS_CODE_REQUEST_DENIED);
1464 }
1465
1466 lasso_check_good_rc(lasso_server_set_signature_for_provider_by_name(
1467 profile->server,
1468 profile->remote_providerID,
1469 profile->response));
1470 lasso_assign_new_string(profile->msg_body, lasso_node_export_to_soap(profile->response));
1471
1472 cleanup:
1473 return rc;
1474 }
1475
1476 /**
1477 * lasso_login_destroy:
1478 * @login: a #LassoLogin
1479 *
1480 * Destroys a #LassoLogin object.
1481 *
1482 * @Deprecated: Since #2.2.1, use g_object_unref() instead.
1483 **/
1484 void
lasso_login_destroy(LassoLogin * login)1485 lasso_login_destroy(LassoLogin *login)
1486 {
1487 lasso_release_gobject(login);
1488 }
1489
1490 /**
1491 * lasso_login_init_authn_request:
1492 * @login: a #LassoLogin
1493 * @remote_providerID:(allow-none): the providerID of the identity provider (may be NULL)
1494 * @http_method:(default LASSO_HTTP_METHOD_REDIRECT): HTTP method to use for request transmission
1495 *
1496 * <para>Initializes a new AuthnRequest from current service provider to remote
1497 * identity provider specified in @remote_providerID (if NULL the first known
1498 * identity provider is used).</para>
1499 *
1500 * <para>For ID-FF 1.2 the default NameIDPolicy in an AuthnRequest is None, which imply that a
1501 * federation must already exist on the IdP side.</para>
1502 *
1503 * <para>For SAML 2.0 the default NameIDPolicy is the first listed in the metadatas of the current
1504 * provider, or if none is specified, Transient, which ask the IdP to give a one-time
1505 * federation</para>
1506 *
1507 * Return value: 0 on success; or
1508 * <itemizedlist>
1509 * <listitem><para>LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin object,</para></listitem>
1510 * <listitem><para>LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID if @remote_providerID is NULL and no default remote
1511 * provider could be found from the server object -- usually the first one in the order of adding to
1512 * the server object --,</para></listitem>
1513 * <listitem><para>LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND if the @remote_providerID is not known to our server object.</para></listitem>
1514 * <listitem><para>LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD if the HTTP method is neither LASSO_HTTP_METHOD_REDIRECT
1515 * or LASSO_HTTP_METHOD_POST,</para></listitem>
1516 * <listitem><para>LASSO_PROFILE_ERROR_BUILDING_REQUEST_FAILED if creation of the request object failed.</para></listitem>
1517 * </itemizedlist>
1518 *
1519 **/
1520 gint
lasso_login_init_authn_request(LassoLogin * login,const gchar * remote_providerID,LassoHttpMethod http_method)1521 lasso_login_init_authn_request(LassoLogin *login, const gchar *remote_providerID,
1522 LassoHttpMethod http_method)
1523 {
1524 LassoProfile *profile;
1525 LassoProvider *remote_provider = NULL;
1526 LassoServer *server = NULL;
1527 LassoSamlpRequestAbstract *request;
1528 lasso_error_t rc = 0;
1529
1530 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1531
1532 profile = LASSO_PROFILE(login);
1533 lasso_extract_node_or_fail(server, profile->server, SERVER,
1534 LASSO_PROFILE_ERROR_MISSING_SERVER);
1535
1536 /* clean state */
1537 lasso_release_string (profile->remote_providerID);
1538 lasso_release_gobject (profile->request);
1539
1540 server->parent.role = LASSO_PROVIDER_ROLE_SP;
1541
1542 /* With PAOS ECP there is no remote provider, don't check for it, go straight to saml2.0 */
1543 if (http_method == LASSO_HTTP_METHOD_PAOS) {
1544 return lasso_saml20_login_init_authn_request(login, http_method);
1545 }
1546
1547 if (remote_providerID != NULL) {
1548 lasso_assign_string(profile->remote_providerID, remote_providerID);
1549 } else {
1550 lasso_assign_new_string(profile->remote_providerID, lasso_server_get_first_providerID_by_role(profile->server, LASSO_PROVIDER_ROLE_IDP));
1551 if (profile->remote_providerID == NULL) {
1552 return critical_error(LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID);
1553 }
1554 }
1555
1556 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
1557 if (LASSO_IS_PROVIDER(remote_provider) == FALSE)
1558 return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
1559
1560 remote_provider->role = LASSO_PROVIDER_ROLE_IDP;
1561
1562 IF_SAML2(profile) {
1563 return lasso_saml20_login_init_authn_request(login, http_method);
1564 }
1565
1566 if (http_method != LASSO_HTTP_METHOD_REDIRECT && http_method != LASSO_HTTP_METHOD_POST) {
1567 return critical_error(LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD);
1568 }
1569
1570 login->http_method = http_method;
1571
1572 lasso_assign_new_gobject(profile->request, LASSO_NODE(lasso_lib_authn_request_new()));
1573 if (profile->request == NULL) {
1574 return critical_error(LASSO_PROFILE_ERROR_BUILDING_REQUEST_FAILED);
1575 }
1576
1577 request = LASSO_SAMLP_REQUEST_ABSTRACT(profile->request);
1578 request->RequestID = lasso_build_unique_id(32);
1579 lasso_assign_string(login->private_data->request_id, request->RequestID);
1580 request->MajorVersion = LASSO_LIB_MAJOR_VERSION_N;
1581 request->MinorVersion = LASSO_LIB_MINOR_VERSION_N;
1582 if (remote_provider &&
1583 lasso_provider_get_protocol_conformance(remote_provider) < LASSO_PROTOCOL_LIBERTY_1_2) {
1584 request->MajorVersion = 1;
1585 request->MinorVersion = 0;
1586 }
1587 lasso_assign_new_string(request->IssueInstant, lasso_get_current_time());
1588 lasso_assign_string(LASSO_LIB_AUTHN_REQUEST(profile->request)->ProviderID,
1589 LASSO_PROVIDER(profile->server)->ProviderID);
1590 lasso_assign_string(LASSO_LIB_AUTHN_REQUEST(profile->request)->RelayState,
1591 profile->msg_relayState);
1592
1593 cleanup:
1594
1595 return rc;
1596 }
1597
1598
1599 /**
1600 * lasso_login_init_request:
1601 * @login: a #LassoLogin
1602 * @response_msg: the authentication response received
1603 * @response_http_method: the method used to receive the authentication
1604 * response
1605 *
1606 * Initializes an artifact request. @response_msg is either the query string
1607 * (in redirect mode) or the form LAREQ field (in browser-post mode).
1608 * It should only be used if you received an artifact message, @response_msg must be content of the
1609 * artifact field for the POST artifact binding of the query string for the REDIRECT artifact
1610 * binding. You must set the @response_http_method argument according to the way you received the
1611 * artifact message.
1612 *
1613 * Return value: 0 on success; or
1614 * <itemizedlist>
1615 * <listitem>
1616 * <para>
1617 * LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin object,
1618 * </para>
1619 * </listitem>
1620 * <listitem>
1621 * <para>
1622 * LASSO_PARAM_ERROR_INVALID_VALUE if @response_msg is NULL,
1623 * </para>
1624 * </listitem>
1625 * <listitem>
1626 * <para>
1627 * LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD if the HTTP method is neither LASSO_HTTP_METHOD_REDIRECT
1628 * or LASSO_HTTP_METHOD_POST (in the ID-FF 1.2 case) or neither LASSO_HTTP_METHOD_ARTIFACT_GET or
1629 * LASSO_HTTP_METHOD_ARTIFACT_POST (in the SAML 2.0 case),
1630 * </para>
1631 * </listitem>
1632 * <listitem>
1633 * <para>
1634 * LASSO_PROFILE_ERROR_MISSING_ARTIFACT if no artifact field was found in the query string (only
1635 * possible for the LASSO_HTTP_METHOD_REDIRECT case),
1636 * </para>
1637 * </listitem>
1638 * <listitem>
1639 * <para>
1640 * LASSO_PROFILE_ERROR_INVALID_ARTIFACT if decoding of the artifact failed -- whether because
1641 * the base64 encoding is invalid or because the type code is wrong --,
1642 * </para>
1643 * </listitem>
1644 * <listitem>
1645 * <para>
1646 * LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID if no provider ID could be found corresponding to
1647 * the hash contained in the artifact.
1648 * </para>
1649 * </listitem>
1650 * </itemizedlist>
1651 *
1652 **/
1653 gint
lasso_login_init_request(LassoLogin * login,gchar * response_msg,LassoHttpMethod response_http_method)1654 lasso_login_init_request(LassoLogin *login, gchar *response_msg,
1655 LassoHttpMethod response_http_method)
1656 {
1657 xmlChar **query_fields;
1658 gint ret = 0;
1659 int i;
1660 char *artifact_b64 = NULL, *provider_succinct_id_b64;
1661 char provider_succinct_id[21];
1662 char artifact[43];
1663 LassoSamlpRequestAbstract *request;
1664 LassoProfile *profile;
1665
1666 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1667 g_return_val_if_fail(response_msg != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
1668
1669 profile = LASSO_PROFILE(login);
1670 IF_SAML2(profile) {
1671 return lasso_saml20_login_init_request(login, response_msg,
1672 response_http_method);
1673 }
1674 if (response_http_method != LASSO_HTTP_METHOD_REDIRECT &&
1675 response_http_method != LASSO_HTTP_METHOD_POST) {
1676 return critical_error(LASSO_PROFILE_ERROR_INVALID_HTTP_METHOD);
1677 }
1678
1679 /* rebuild response (artifact) */
1680 if (response_http_method == LASSO_HTTP_METHOD_REDIRECT) {
1681 query_fields = lasso_urlencoded_to_strings(response_msg);
1682 for (i=0; query_fields[i]; i++) {
1683 if (strncmp((char*)query_fields[i], "SAMLart=", 8) == 0) {
1684 lasso_assign_string(artifact_b64, (char*)query_fields[i]+8);
1685 }
1686 if (strncmp((char*)query_fields[i], "RelayState=", 11) == 0) {
1687 lasso_assign_string(profile->msg_relayState, (char*)query_fields[i]+11);
1688 }
1689 }
1690 lasso_release_array_of_xml_strings(query_fields);
1691 if (artifact_b64 == NULL) {
1692 return LASSO_PROFILE_ERROR_MISSING_ARTIFACT;
1693 }
1694 }
1695 if (response_http_method == LASSO_HTTP_METHOD_POST) {
1696 lasso_assign_string(artifact_b64, response_msg);
1697 }
1698
1699 i = xmlSecBase64Decode((xmlChar*)artifact_b64, (xmlChar*)artifact, 43);
1700 if (i < 0 || i > 42) {
1701 lasso_release_string(artifact_b64);
1702 return LASSO_PROFILE_ERROR_INVALID_ARTIFACT;
1703 }
1704
1705 if (artifact[0] != 0 || artifact[1] != 3) { /* wrong type code */
1706 lasso_release_string(artifact_b64);
1707 return LASSO_PROFILE_ERROR_INVALID_ARTIFACT;
1708 }
1709
1710 memcpy(provider_succinct_id, artifact+2, 20);
1711 provider_succinct_id[20] = 0;
1712
1713 provider_succinct_id_b64 = (char*)xmlSecBase64Encode((xmlChar*)provider_succinct_id, 20, 0);
1714
1715 lasso_assign_new_string(profile->remote_providerID, lasso_server_get_providerID_from_hash(
1716 profile->server, provider_succinct_id_b64));
1717 xmlFree(provider_succinct_id_b64);
1718 if (profile->remote_providerID == NULL) {
1719 return critical_error(LASSO_PROFILE_ERROR_MISSING_REMOTE_PROVIDERID);
1720 }
1721
1722 request = LASSO_SAMLP_REQUEST_ABSTRACT(lasso_samlp_request_new());
1723 request->RequestID = lasso_build_unique_id(32);
1724 request->MajorVersion = LASSO_SAML_MAJOR_VERSION_N;
1725 request->MinorVersion = LASSO_SAML_MINOR_VERSION_N;
1726 lasso_assign_new_string(request->IssueInstant, lasso_get_current_time());
1727 LASSO_SAMLP_REQUEST(request)->AssertionArtifact = artifact_b64;
1728 lasso_assign_new_gobject(profile->request, LASSO_NODE(request));
1729
1730 return ret;
1731 }
1732
1733 /**
1734 * lasso_login_init_idp_initiated_authn_request:
1735 * @login: a #LassoLogin.
1736 * @remote_providerID: the providerID of the remote service provider (may be
1737 * NULL)
1738 *
1739 * <para>Generates an authentication response without matching authentication
1740 * request.</para>
1741 *
1742 * <para>The choice of NameIDFormat is the same as for lasso_login_init_authn_request() but with the
1743 * target @remote_providerID as the current provider</para>
1744 *
1745 * <para>If @remote_providerID is NULL, the first known provider is used.</para>
1746 *
1747 * Return value: 0 on success; or a negative value otherwise. Error codes are the same as
1748 * lasso_login_init_authn_request().
1749 **/
1750 gint
lasso_login_init_idp_initiated_authn_request(LassoLogin * login,const gchar * remote_providerID)1751 lasso_login_init_idp_initiated_authn_request(LassoLogin *login,
1752 const gchar *remote_providerID)
1753 {
1754 int rc = 0;
1755 LassoProfile *profile;
1756
1757 profile = LASSO_PROFILE(login);
1758
1759 IF_SAML2(profile) {
1760 return lasso_saml20_login_init_idp_initiated_authn_request(login,
1761 remote_providerID);
1762 }
1763
1764 rc = lasso_login_init_authn_request(login, remote_providerID, LASSO_HTTP_METHOD_POST);
1765 if (rc)
1766 return rc;
1767
1768 /* no RequestID attribute or it would be used in response assertion */
1769 lasso_release_string(LASSO_SAMLP_REQUEST_ABSTRACT(profile->request)->RequestID);
1770 lasso_assign_string(LASSO_LIB_AUTHN_REQUEST(profile->request)->NameIDPolicy,
1771 LASSO_LIB_NAMEID_POLICY_TYPE_ANY);
1772
1773 return 0;
1774 }
1775
1776 /**
1777 * lasso_login_must_ask_for_consent:
1778 * @login: a #LassoLogin
1779 *
1780 * Evaluates if consent must be asked to the Principal to federate him.
1781 *
1782 * Return value: %TRUE if consent must be asked
1783 **/
1784 gboolean
lasso_login_must_ask_for_consent(LassoLogin * login)1785 lasso_login_must_ask_for_consent(LassoLogin *login)
1786 {
1787 LassoProfile *profile = LASSO_PROFILE(login);
1788
1789 IF_SAML2(profile) {
1790 return lasso_saml20_login_must_ask_for_consent(login);
1791 }
1792
1793 if (LASSO_LIB_AUTHN_REQUEST(LASSO_PROFILE(login)->request)->IsPassive) {
1794 return FALSE;
1795 }
1796
1797 return lasso_login_must_ask_for_consent_private(login);
1798 }
1799
1800
1801 /**
1802 * lasso_login_must_authenticate:
1803 * @login: a #LassoLogin
1804 *
1805 * Evaluates if user must be authenticated.
1806 *
1807 * Return value: %TRUE if user must be authenticated
1808 **/
1809 gboolean
lasso_login_must_authenticate(LassoLogin * login)1810 lasso_login_must_authenticate(LassoLogin *login)
1811 {
1812 LassoLibAuthnRequest *request;
1813 LassoProfile *profile;
1814 gboolean matched = TRUE;
1815 GList *assertions = NULL;
1816
1817 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
1818 profile = LASSO_PROFILE(login);
1819
1820 IF_SAML2(profile) {
1821 return lasso_saml20_login_must_authenticate(login);
1822 }
1823
1824 request = LASSO_LIB_AUTHN_REQUEST(LASSO_PROFILE(login)->request);
1825 if (request == NULL) {
1826 return critical_error(LASSO_PROFILE_ERROR_MISSING_REQUEST);
1827 }
1828
1829 if (request->ForceAuthn == TRUE && request->IsPassive == FALSE)
1830 return TRUE;
1831
1832 assertions = lasso_session_get_assertions(profile->session, NULL);
1833 if (request->RequestAuthnContext) {
1834 char *comparison = request->RequestAuthnContext->AuthnContextComparison;
1835 char *class_ref;
1836 GList *class_refs = request->RequestAuthnContext->AuthnContextClassRef;
1837 GList *t1, *t2;
1838 int compa = -1;
1839
1840 if (comparison == NULL || strcmp(comparison, "exact") == 0) {
1841 compa = 0;
1842 } else if (strcmp(comparison, "minimum") == 0) {
1843 message(G_LOG_LEVEL_CRITICAL, "'minimum' comparison is not implemented");
1844 compa = 1;
1845 } else if (strcmp(comparison, "better") == 0) {
1846 message(G_LOG_LEVEL_CRITICAL, "'better' comparison is not implemented");
1847 compa = 2;
1848 }
1849
1850 if (class_refs) {
1851 matched = FALSE;
1852 }
1853
1854 for (t1 = class_refs; t1 && !matched; t1 = g_list_next(t1)) {
1855 class_ref = t1->data;
1856 for (t2 = assertions; t2 && !matched; t2 = g_list_next(t2)) {
1857 LassoSamlAssertion *assertion;
1858 LassoSamlAuthenticationStatement *as;
1859 char *method;
1860
1861 if (LASSO_IS_SAML_ASSERTION(t2->data) == FALSE) {
1862 continue;
1863 }
1864
1865 assertion = t2->data;
1866
1867 as = LASSO_SAML_AUTHENTICATION_STATEMENT(
1868 assertion->AuthenticationStatement);
1869 method = as->AuthenticationMethod;
1870
1871 if (strcmp(method, LASSO_SAML_AUTHENTICATION_METHOD_PASSWORD) == 0)
1872 {
1873 /* mapping between SAML authentication
1874 * methods and Liberty authentication
1875 * context is not possible (excepted on
1876 * that one)
1877 */
1878 method = LASSO_LIB_AUTHN_CONTEXT_CLASS_REF_PASSWORD;
1879 }
1880
1881 switch (compa) {
1882 case 1: /* minimum */
1883 /* XXX: implement 'minimum' comparison */
1884 case 2: /* better */
1885 /* XXX: implement 'better' comparison */
1886 case 0: /* exact */
1887 if (strcmp(method, class_ref) == 0) {
1888 matched = TRUE;
1889 }
1890 break;
1891 default: /* inever reached */
1892 break;
1893 }
1894 if (matched == TRUE) {
1895 break;
1896 }
1897 }
1898 }
1899
1900 } else {
1901 /* if nothing specific was asked; don't look for any
1902 * particular assertions, one is enough
1903 */
1904 matched = (profile->session != NULL && \
1905 lasso_session_count_assertions(profile->session) > 0);
1906 }
1907 lasso_release_list(assertions);
1908
1909 if (matched == FALSE && request->IsPassive == FALSE)
1910 return TRUE;
1911
1912 if (LASSO_PROFILE(login)->identity == NULL && request->IsPassive &&
1913 login->protocolProfile == LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST) {
1914 lasso_profile_set_response_status(LASSO_PROFILE(login),
1915 LASSO_LIB_STATUS_CODE_NO_PASSIVE);
1916 return FALSE;
1917 }
1918
1919 return FALSE;
1920 }
1921
1922 /**
1923 * lasso_login_process_authn_request_msg:
1924 * @login: a #LassoLogin
1925 * @authn_request_msg: the authentication request received
1926 *
1927 * Processes received authentication request, checks it is signed correctly,
1928 * checks if requested protocol profile is supported, etc.
1929 *
1930 * Return value: 0 on success; or
1931 * <itemizedlist>
1932 * <listitem>
1933 * <para>
1934 * #LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is no a #LassoLogin object,
1935 * </para>
1936 * </listitem>
1937 * <listitem>
1938 * <para>
1939 * #LASSO_PROFILE_ERROR_MISSING_REQUEST if @authn_request_msg is #NULL and no request as actually
1940 * been processed or initialized — see lasso_login_init_idp_initiated_authn_request(),
1941 *
1942 * </para>
1943 * </listitem>
1944 * <listitem>
1945 * <para>
1946 * #LASSO_PROFILE_ERROR_INVALID_MSG if the content of @authn_request_msg cannot be parsed to as a
1947 * valid lib:AuthnRequest messages for any support binding (mainly HTTP-Redirect, HTTP-Post and
1948 * SOAP),
1949 * </para>
1950 * </listitem>
1951 * <listitem>
1952 * <para>
1953 *
1954 * #LASSO_PROFILE_ERROR_MISSING_ISSUER if the parsed samlp2:AuthnRequest does not have a proper Issuer element,
1955 * </para>
1956 * </listitem>
1957 * <listitem>
1958 * <para>
1959 *
1960 * #LASSO_PROFILE_ERROR_INVALID_REQUEST if the parsed message does not validate as a valid
1961 * samlp2:AuthnRequest (SAMLv2) i.e. if there is no Issuer, or mutually exclusive attributes are
1962 * used (ProtocolBinding and AssertionConsumerServiceIndex),
1963 * </para>
1964 * </listitem>
1965 * <listitem>
1966 * <para>
1967 *
1968 * #LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE if the protocolProfile (ID-FFv1.2) or the
1969 * protocolBinding (SAMLv2) is unsupported by Lasso,
1970 * </para>
1971 * </listitem>
1972 * <listitem>
1973 * <para>
1974 *
1975 * #LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE if the protocolProfile (ID-FFv1.2) or the protocolBinding
1976 * (SAMLv2) for the AssertionConsumer is unsupported by this provider implementation as indicated by
1977 * its metadata file,
1978 * </para>
1979 * </listitem>
1980 * <listitem>
1981 * <para>
1982 *
1983 * #LASSO_PROFILE_ERROR_UNKNOWN_PROVIDER, or
1984 * #LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND if the metadata for the issuer of the request are absent
1985 * from the #LassoServer object of this profile,
1986 * </para>
1987 * </listitem>
1988 * <listitem>
1989 * <para>
1990 *
1991 * #LASSO_DS_ERROR_SIGNATURE_NOT_FOUND if no signature could be found and signature validation is
1992 * forced — by the service provider metadata with the AuthnRequestsSigned attribute
1993 * (ID-FFv1.2&SAMLv2), the attribute WantAuthnRequestsSigned in the identity provider metadata file
1994 * (SAMLv2) or as advised by the lasso_profile_set_signature_verify_hint() method),
1995 * </para>
1996 * </listitem>
1997 * <listitem>
1998 * <para>
1999 *
2000 * #LASSO_DS_ERROR_SIGNATURE_VERIFICATION_FAILED if the signature validation failed on a present
2001 * signature,
2002 * </para>
2003 * </listitem>
2004 * <listitem>
2005 * <para>
2006 * #LASSO_DS_ERROR_INVALID_SIGNATURE if the signature was malformed and a signature was present,
2007 * </para>
2008 * </listitem>
2009 * </itemizedlist>
2010 *
2011 **/
2012 gint
lasso_login_process_authn_request_msg(LassoLogin * login,const char * authn_request_msg)2013 lasso_login_process_authn_request_msg(LassoLogin *login, const char *authn_request_msg)
2014 {
2015 LassoProvider *remote_provider;
2016 gchar *protocolProfile;
2017 gchar *authnRequestSigned;
2018 gboolean must_verify_signature = FALSE;
2019 gint ret = 0;
2020 LassoLibAuthnRequest *request;
2021 LassoMessageFormat format;
2022 LassoProfile *profile;
2023
2024 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
2025
2026 profile = LASSO_PROFILE(login);
2027
2028 IF_SAML2(profile) {
2029 return lasso_saml20_login_process_authn_request_msg(login, authn_request_msg);
2030 }
2031
2032 if (authn_request_msg == NULL) {
2033 format = 0;
2034 if (profile->request == NULL) {
2035 return critical_error(LASSO_PROFILE_ERROR_MISSING_REQUEST);
2036 }
2037
2038 /* LibAuthnRequest already set by lasso_login_init_idp_initiated_authn_request() */
2039 request = LASSO_LIB_AUTHN_REQUEST(profile->request);
2040 } else {
2041 request = lasso_lib_authn_request_new();
2042 format = lasso_node_init_from_message(LASSO_NODE(request), authn_request_msg);
2043 if (format == LASSO_MESSAGE_FORMAT_UNKNOWN ||
2044 format == LASSO_MESSAGE_FORMAT_ERROR) {
2045 return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
2046 }
2047
2048 lasso_assign_new_gobject(profile->request, request);
2049 if (! LASSO_IS_LIB_AUTHN_REQUEST(profile->request)) {
2050 lasso_release_gobject(profile->request);
2051 return LASSO_PROFILE_ERROR_INVALID_MSG;
2052 }
2053
2054 /* get remote ProviderID */
2055 lasso_assign_string(profile->remote_providerID,
2056 LASSO_LIB_AUTHN_REQUEST(profile->request)->ProviderID);
2057
2058 /* get RelayState */
2059 lasso_assign_string(profile->msg_relayState, request->RelayState);
2060 }
2061
2062
2063 /* get ProtocolProfile in lib:AuthnRequest */
2064 protocolProfile = LASSO_LIB_AUTHN_REQUEST(profile->request)->ProtocolProfile;
2065 if (protocolProfile == NULL ||
2066 strcmp(protocolProfile, LASSO_LIB_PROTOCOL_PROFILE_BRWS_ART) == 0) {
2067 protocolProfile = LASSO_LIB_PROTOCOL_PROFILE_BRWS_ART;
2068 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
2069 } else if (strcmp(protocolProfile, LASSO_LIB_PROTOCOL_PROFILE_BRWS_POST) == 0) {
2070 protocolProfile = LASSO_LIB_PROTOCOL_PROFILE_BRWS_POST;
2071 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST;
2072 } else if (strcmp(protocolProfile, LASSO_LIB_PROTOCOL_PROFILE_BRWS_LECP) == 0) {
2073 protocolProfile = LASSO_LIB_PROTOCOL_PROFILE_BRWS_LECP;
2074 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_LECP;
2075 } else {
2076 return critical_error(LASSO_PROFILE_ERROR_INVALID_PROTOCOLPROFILE);
2077 }
2078
2079 /* check if requested single sign on protocol profile is supported */
2080 LASSO_PROVIDER(profile->server)->role = LASSO_PROVIDER_ROLE_IDP;
2081 if (lasso_provider_has_protocol_profile(
2082 LASSO_PROVIDER(profile->server),
2083 LASSO_MD_PROTOCOL_TYPE_SINGLE_SIGN_ON,
2084 protocolProfile) == FALSE) {
2085 return critical_error(LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE);
2086 }
2087
2088 /* Check authnRequest signature. */
2089 if (authn_request_msg != NULL) {
2090 LassoProfileSignatureVerifyHint sig_verify_hint;
2091
2092 sig_verify_hint = lasso_profile_get_signature_verify_hint(profile);
2093 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
2094 if (remote_provider == NULL) {
2095 return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
2096 }
2097 /* Is authnRequest signed ? */
2098 must_verify_signature = TRUE;
2099 authnRequestSigned = lasso_provider_get_metadata_one(
2100 remote_provider, "AuthnRequestsSigned");
2101 if (authnRequestSigned != NULL) {
2102 must_verify_signature = strcmp(authnRequestSigned, "true") == 0;
2103 lasso_release_string(authnRequestSigned);
2104 }
2105 if (sig_verify_hint == LASSO_PROFILE_SIGNATURE_VERIFY_HINT_FORCE) {
2106 must_verify_signature = TRUE;
2107 }
2108 if (sig_verify_hint == LASSO_PROFILE_SIGNATURE_VERIFY_HINT_IGNORE) {
2109 must_verify_signature = FALSE;
2110 }
2111 /* reset the signature_status, and if signature validation was not really needed
2112 * just choke on the presence of an invalid signature, if no signature just goes on
2113 * */
2114 profile->signature_status = 0;
2115 if (must_verify_signature) {
2116 ret = lasso_provider_verify_signature(remote_provider,
2117 authn_request_msg, "RequestID", format);
2118 if (profile == LASSO_PROFILE_SIGNATURE_VERIFY_HINT_MAYBE && ret !=
2119 LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) {
2120 profile->signature_status = ret;
2121 }
2122 }
2123 }
2124
2125 /* create LibAuthnResponse */
2126 lasso_assign_new_gobject(profile->response, lasso_lib_authn_response_new(
2127 LASSO_PROVIDER(profile->server)->ProviderID,
2128 LASSO_LIB_AUTHN_REQUEST(profile->request)));
2129 if (LASSO_SAMLP_REQUEST_ABSTRACT(profile->request)->MajorVersion == 1 &&
2130 LASSO_SAMLP_REQUEST_ABSTRACT(profile->request)->MinorVersion < 2) {
2131 /* pre-id-ff 1.2, move accordingly */
2132 LASSO_SAMLP_RESPONSE_ABSTRACT(profile->response)->MajorVersion = 1;
2133 LASSO_SAMLP_RESPONSE_ABSTRACT(profile->response)->MinorVersion = 0;
2134 }
2135
2136
2137 return ret;
2138 }
2139
2140 /**
2141 * lasso_login_process_authn_response_msg:
2142 * @login: a #LassoLogin
2143 * @authn_response_msg: the authentication response received
2144 *
2145 * Processes received authentication response.
2146 *
2147 * Return value: 0 on success; or
2148 * <itemizedlist>
2149 * <listitem><para>#LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin
2150 * object,</para></listitem>
2151 * <listitem><para>#LASSO_PARAM_ERROR_INVALID_VALUE if authn_response_msg is NULL,</para></listitem>
2152 * <listitem><para>#LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND, if the issuing
2153 * provider of the assertion is not registered in the #LassoServer object,</para></listitem>
2154 * <listitem><para>#LASSO_PROFILE_ERROR_MISSING_ISSUER if the parsed samlp2:AuthnRequest does not
2155 * have a proper Issuer element, </para></listitem>
2156 * <listitem><para>#LASSO_PROFILE_ERROR_MISSING_STATUS_CODE if the reponse is missing a
2157 * <literal>StatusCode</literal> element,</para></listitem>
2158 * <listitem><para>#LASSO_PROFILE_STATUS_NOT_SUCCESS_ERROR if the identity provider returned a
2159 * failure response,</para></listitem>
2160 * <listitem><para>#LASSO_PROFILE_ERROR_REQUEST_DENIED</para> if the identity provider returned the
2161 * specific status code <literal>RequestDenied</literal>,</listitem>
2162 * <listitem><para>#LASSO_PROFILE_ERROR_INVALID_MSG if the message is not a #LassoSamlpResponse
2163 * (ID-FF 1.2) or a #LassoSamlp2ResponseMsg (SAML 2.0),</para></listitem>
2164 * <listitem><para>#LASSO_PROFILE_ERROR_UNSUPPORTED_PROFILE, if the received message format does not
2165 * correspond to a binding supported by this function, the only supported binding by this function
2166 * is HTTP POST,</para></listitem>
2167 * <listitem><para>#LASSO_PROFILE_ERROR_MISSING_SERVER the server object is needed to sign a message
2168 * and it is missing,</para></listitem>
2169 * <listitem><para>#LASSO_PROFILE_ERROR_CANNOT_VERIFY_SIGNATURE if the validation of the signature
2170 * of the message failed, a specific error code is available in
2171 * <literal>login->parent.signature_status</literal></para></listitem>
2172 * <listitem><para>#LASSO_LOGIN_ERROR_ASSERTION_DOES_NOT_MATCH_REQUEST_ID if the received response
2173 * does not match the saved AuthenticationRequest ID,</para></listitem>
2174 * <listitem><para>#LASSO_PROFILE_ERROR_INVALID_ISSUER if the assertion issuer does not match the
2175 * AuthenticationResponse issuer,</para></listitem>
2176 * <listitem><para>#LASSO_PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND if not NameID could be found or
2177 * decoded,</para></listitem>
2178 * </itemizedlist>
2179 **/
2180 gint
lasso_login_process_authn_response_msg(LassoLogin * login,gchar * authn_response_msg)2181 lasso_login_process_authn_response_msg(LassoLogin *login, gchar *authn_response_msg)
2182 {
2183 LassoMessageFormat format;
2184 LassoProvider *remote_provider;
2185 LassoProfile *profile;
2186
2187 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
2188 g_return_val_if_fail(authn_response_msg != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
2189
2190 profile = LASSO_PROFILE(login);
2191
2192 IF_SAML2(profile) {
2193 return lasso_saml20_login_process_authn_response_msg(login, authn_response_msg);
2194 }
2195
2196 /* clean state */
2197 lasso_release_string (profile->remote_providerID);
2198 lasso_release_gobject(profile->response);
2199
2200 lasso_assign_new_gobject(profile->response, lasso_lib_authn_response_new(NULL, NULL));
2201 format = lasso_node_init_from_message(
2202 LASSO_NODE(profile->response), authn_response_msg);
2203 if (format == LASSO_MESSAGE_FORMAT_UNKNOWN || format == LASSO_MESSAGE_FORMAT_ERROR) {
2204 return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
2205 }
2206
2207 lasso_assign_string(profile->remote_providerID,
2208 LASSO_LIB_AUTHN_RESPONSE(profile->response)->ProviderID);
2209
2210 if (profile->remote_providerID == NULL) {
2211 return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
2212 }
2213
2214 remote_provider = lasso_server_get_provider(profile->server, profile->remote_providerID);
2215 if (LASSO_IS_PROVIDER(remote_provider) == FALSE)
2216 return critical_error(LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND);
2217
2218 lasso_assign_string(profile->msg_relayState, LASSO_LIB_AUTHN_RESPONSE(
2219 profile->response)->RelayState);
2220
2221 profile->signature_status = lasso_provider_verify_signature(
2222 remote_provider, authn_response_msg, "ResponseID", format);
2223
2224 if (profile->signature_status) {
2225 return profile->signature_status;
2226 }
2227 return lasso_login_process_response_status_and_assertion(login);
2228 }
2229
2230
2231 /**
2232 * lasso_login_process_request_msg:
2233 * @login: a #LassoLogin
2234 * @request_msg: the artifact request received
2235 *
2236 * Processes received artifact request.
2237 *
2238 * Return value: 0 on success; or a negative value otherwise.
2239 **/
2240 gint
lasso_login_process_request_msg(LassoLogin * login,gchar * request_msg)2241 lasso_login_process_request_msg(LassoLogin *login, gchar *request_msg)
2242 {
2243 gint ret = 0;
2244 LassoProfile *profile = LASSO_PROFILE(login);
2245
2246 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
2247 g_return_val_if_fail(request_msg != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
2248
2249 IF_SAML2(profile) {
2250 return lasso_saml20_login_process_request_msg(login, request_msg);
2251 }
2252
2253 /* rebuild samlp:Request with request_msg */
2254 lasso_assign_new_gobject(profile->request, lasso_node_new_from_soap(request_msg));
2255 if (profile->request == NULL) {
2256 return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
2257 }
2258 /* get AssertionArtifact */
2259 lasso_assign_string(login->assertionArtifact,
2260 LASSO_SAMLP_REQUEST(profile->request)->AssertionArtifact);
2261 lasso_assign_string(login->parent.private_data->artifact,
2262 login->assertionArtifact);
2263
2264 /* Keep a copy of request msg so signature can be verified when we get
2265 * the providerId in lasso_login_build_response_msg()
2266 */
2267 lasso_assign_string(login->private_data->soap_request_msg, request_msg);
2268
2269 return ret;
2270 }
2271
2272
2273 /**
2274 * lasso_login_process_response_msg:
2275 * @login: a #LassoLogin
2276 * @response_msg: the assertion response received
2277 *
2278 * Processes received assertion response.
2279 *
2280 * Return value: 0 on success; or
2281 * <itemizedlist>
2282 * <listitem><para>#LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin object,</para></listitem>
2283 * <listitem><para>#LASSO_PARAM_ERROR_INVALID_VALUE if response_msg is NULL,</para></listitem>
2284 * <listitem><para>#LASSO_PROFILE_ERROR_INVALID_MSG if the message is not a #LassoSamlpResponse (ID-FF 1.2) or a #LassoSamlp2ResponseMsg (SAML 2.0),</para></listitem>
2285 * <listitem><para>#LASSO_PROFILE_ERROR_RESPONSE_DOES_NOT_MATCH_REQUEST if the response does not refer to the request or if the response refer to an unknown request and <link linkend="strict-checking"><literal>strict-checking</literal></link> is activated ,</para></listitem>
2286 * <listitem><para>#LASSO_LOGIN_ERROR_REQUEST_DENIED the identity provided
2287 * returned a failure status of "RequestDenied"</para></listitem>
2288 * <listitem><para>#LASSO_LOGIN_ERROR_FEDERATION_NOT_FOUND if creation of a new
2289 * federation was not allowed and none existed,</para></listitem>
2290 * <listitem><para>#LASSO_LOGIN_ERROR_UNKNOWN_PRINCIPAL if authentication failed
2291 * or/and if the user cancelled the authentication,</para></listitem>
2292 * <listitem><para>#LASSO_LOGIN_ERROR_STATUS_NOT_SUCCESS, if the response status
2293 * is a failure but we have no more precise error code to report it, you must
2294 * look at the second level status in the response,</para></listitem>
2295 * <listitem><para>#LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND, if the issuing
2296 * provider of the assertion is unknown,</para></listitem>
2297 * <listitem><para>#LASSO_PROFILE_ERROR_INVALID_ISSUER the issuer of the
2298 * assertion received, is not the expected one</para></listitem>
2299 * <listitem><para>#LASSO_PROFILE_ERROR_NAME_IDENTIFIER_NOT_FOUND no statement was fournd, or none statement contains a subject with a name identifier,</para></listitem>
2300 * <listitem><para>#LASSO_PROFILE_ERROR_MISSING_STATUS_CODE if the reponse is
2301 * missing a <literal>StatusCode</literal> element,</para></listitem>
2302 * <listitem><para>#LASSO_PROFILE_ERROR_MISSING_ASSERTION if the message does
2303 * not contain any assertion.</para></listitem>
2304 * </itemizedlist>
2305 **/
2306 gint
lasso_login_process_response_msg(LassoLogin * login,gchar * response_msg)2307 lasso_login_process_response_msg(LassoLogin *login, gchar *response_msg)
2308 {
2309 LassoProfile *profile;
2310
2311 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
2312 g_return_val_if_fail(response_msg != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
2313
2314 profile = LASSO_PROFILE(login);
2315
2316 IF_SAML2(profile) {
2317 return lasso_saml20_login_process_response_msg(login, response_msg);
2318 }
2319
2320
2321 /* rebuild samlp:Response with response_msg */
2322 lasso_assign_new_gobject(profile->response, lasso_node_new_from_soap(response_msg));
2323 if (! LASSO_IS_SAMLP_RESPONSE(profile->response) ) {
2324 lasso_release_gobject(profile->response);
2325 return critical_error(LASSO_PROFILE_ERROR_INVALID_MSG);
2326 }
2327
2328 /* Validate RequestID and InResponseTo */
2329 if (profile->request || lasso_flag_strict_checking) {
2330 char *request_id = NULL;
2331 char *response_to = NULL;
2332
2333 if (LASSO_IS_SAMLP_REQUEST(profile->request)) {
2334 request_id = LASSO_SAMLP_REQUEST_ABSTRACT(profile->request)->RequestID;
2335 }
2336 response_to = LASSO_SAMLP_RESPONSE_ABSTRACT(profile->response)->InResponseTo;
2337
2338 if ((! request_id && response_to) || /* response to an unknown request, only with
2339 strict checking */
2340 (profile->request && ! response_to) || /* not a response to our request, because
2341 no ref */
2342 /* not a response to our request because of mismatch */
2343 (request_id && response_to && strcmp(request_id, response_to) != 0)) {
2344 return critical_error(LASSO_PROFILE_ERROR_RESPONSE_DOES_NOT_MATCH_REQUEST);
2345 } /* else no request and no inResponseTo, IDP initiated response, ok */
2346 }
2347
2348 /* In the artifact profile we cannot verify the signature on the message, we must wait the
2349 * verification on the assertion, so for the moment the signature verification failed. */
2350 profile->signature_status = LASSO_DS_ERROR_SIGNATURE_VERIFICATION_FAILED;
2351
2352 xmlNode *signed_response;
2353 signed_response = lasso_node_get_original_xmlnode(LASSO_NODE(profile->response));
2354 if (signed_response && profile->remote_providerID) {
2355 LassoProvider *idp;
2356
2357 idp = LASSO_PROVIDER(lasso_server_get_provider(profile->server,
2358 profile->remote_providerID));
2359 profile->signature_status = lasso_provider_verify_saml_signature(idp,
2360 signed_response, NULL);
2361 }
2362
2363 return lasso_login_process_response_status_and_assertion(login);
2364 }
2365
2366
2367
2368 /*****************************************************************************/
2369 /* private methods */
2370 /*****************************************************************************/
2371
2372 static struct XmlSnippet schema_snippets[] = {
2373 { "AssertionArtifact", SNIPPET_CONTENT, G_STRUCT_OFFSET(LassoLogin, assertionArtifact), NULL, NULL, NULL},
2374 { "NameIDPolicy", SNIPPET_CONTENT, G_STRUCT_OFFSET(LassoLogin, nameIDPolicy), NULL, NULL, NULL},
2375 { "Assertion", SNIPPET_NODE_IN_CHILD, G_STRUCT_OFFSET(LassoLogin, assertion), NULL, NULL, NULL},
2376 { "RequestID", SNIPPET_CONTENT | SNIPPET_PRIVATE,
2377 G_STRUCT_OFFSET(LassoLoginPrivate, request_id), NULL, NULL, NULL},
2378 { "LoginDumpVersion", SNIPPET_ATTRIBUTE, 0, NULL, NULL, NULL},
2379 { "ProtocolProfile", SNIPPET_CONTENT, 0, NULL, NULL, NULL},
2380 {NULL, 0, 0, NULL, NULL, NULL}
2381 };
2382
2383 static LassoNodeClass *parent_class = NULL;
2384
2385 static xmlNode*
get_xmlNode(LassoNode * node,gboolean lasso_dump)2386 get_xmlNode(LassoNode *node, gboolean lasso_dump)
2387 {
2388 xmlNode *xmlnode;
2389 LassoLogin *login = LASSO_LOGIN(node);
2390
2391 xmlnode = parent_class->get_xmlNode(node, lasso_dump);
2392 xmlSetProp(xmlnode, (xmlChar*)"LoginDumpVersion", (xmlChar*)"2");
2393
2394 if (login->protocolProfile == LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART)
2395 xmlNewTextChild(xmlnode, NULL, (xmlChar*)"ProtocolProfile", (xmlChar*)"Artifact");
2396 else if (login->protocolProfile == LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST)
2397 xmlNewTextChild(xmlnode, NULL, (xmlChar*)"ProtocolProfile", (xmlChar*)"POST");
2398 else if (login->protocolProfile == LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT)
2399 xmlNewTextChild(xmlnode, NULL, (xmlChar*)"ProtocolProfile", (xmlChar*)"Redirect");
2400
2401 return xmlnode;
2402 }
2403
2404 static int
init_from_xml(LassoNode * node,xmlNode * xmlnode)2405 init_from_xml(LassoNode *node, xmlNode *xmlnode)
2406 {
2407 LassoLogin *login = LASSO_LOGIN(node);
2408 xmlNode *t;
2409 int rc = 0;
2410
2411 rc = parent_class->init_from_xml(node, xmlnode);
2412 if (rc) return rc;
2413
2414 t = xmlnode->children;
2415 while (t) {
2416 if (t->type != XML_ELEMENT_NODE) {
2417 t = t->next;
2418 continue;
2419 }
2420 if (strcmp((char*)t->name, "ProtocolProfile") == 0) {
2421 char *s;
2422 s = (char*)xmlNodeGetContent(t);
2423 if (strcmp(s, "Artifact") == 0)
2424 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART;
2425 else if (strcmp(s, "POST") == 0)
2426 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_POST;
2427 else if (strcmp(s, "Redirect") == 0)
2428 login->protocolProfile = LASSO_LOGIN_PROTOCOL_PROFILE_REDIRECT;
2429 xmlFree(s);
2430 }
2431 t = t->next;
2432 }
2433 return 0;
2434 }
2435
2436
2437 /*****************************************************************************/
2438 /* overridden parent class methods */
2439 /*****************************************************************************/
2440
2441 static void
dispose(GObject * object)2442 dispose(GObject *object)
2443 {
2444 LassoLogin *login = LASSO_LOGIN(object);
2445
2446 lasso_release_string(login->private_data->soap_request_msg);
2447 lasso_release_gobject(login->private_data->saml2_assertion);
2448
2449 #ifdef LASSO_WSF_ENABLED
2450 lasso_release_gobject(login->private_data->resourceId);
2451 lasso_release_gobject(login->private_data->encryptedResourceId);
2452 #endif
2453 lasso_release_string(login->private_data->request_id);
2454 G_OBJECT_CLASS(parent_class)->dispose(object);
2455 }
2456
2457 /*****************************************************************************/
2458 /* instance and class init functions */
2459 /*****************************************************************************/
2460
2461 static void
instance_init(LassoLogin * login)2462 instance_init(LassoLogin *login)
2463 {
2464 login->private_data = LASSO_LOGIN_GET_PRIVATE(login);
2465 login->protocolProfile = 0;
2466 login->assertionArtifact = NULL;
2467 login->nameIDPolicy = NULL;
2468 login->http_method = 0;
2469 }
2470
2471 static void
class_init(LassoLoginClass * klass,void * unused G_GNUC_UNUSED)2472 class_init(LassoLoginClass *klass, void *unused G_GNUC_UNUSED)
2473 {
2474 LassoNodeClass *nclass = LASSO_NODE_CLASS(klass);
2475
2476 parent_class = g_type_class_peek_parent(klass);
2477 nclass->get_xmlNode = get_xmlNode;
2478 nclass->init_from_xml = init_from_xml;
2479 nclass->node_data = g_new0(LassoNodeClassData, 1);
2480 lasso_node_class_set_nodename(nclass, "Login");
2481 lasso_node_class_set_ns(nclass, LASSO_LASSO_HREF, LASSO_LASSO_PREFIX);
2482 lasso_node_class_add_snippets(nclass, schema_snippets);
2483 g_type_class_add_private(klass, sizeof(LassoLoginPrivate));
2484
2485 G_OBJECT_CLASS(klass)->dispose = dispose;
2486 }
2487
2488 GType
lasso_login_get_type()2489 lasso_login_get_type()
2490 {
2491 static GType this_type = 0;
2492
2493 if (!this_type) {
2494 static const GTypeInfo this_info = {
2495 sizeof(LassoLoginClass),
2496 NULL,
2497 NULL,
2498 (GClassInitFunc) class_init,
2499 NULL,
2500 NULL,
2501 sizeof(LassoLogin),
2502 0,
2503 (GInstanceInitFunc) instance_init,
2504 NULL
2505 };
2506
2507 this_type = g_type_register_static(LASSO_TYPE_PROFILE,
2508 "LassoLogin", &this_info, 0);
2509 }
2510 return this_type;
2511 }
2512
2513 /**
2514 * lasso_login_new
2515 * @server: the #LassoServer
2516 *
2517 * Creates a new #LassoLogin.
2518 *
2519 * Return value: a newly created #LassoLogin object; or NULL if an error
2520 * occured
2521 **/
2522 LassoLogin*
lasso_login_new(LassoServer * server)2523 lasso_login_new(LassoServer *server)
2524 {
2525 LassoLogin *login = NULL;
2526
2527 g_return_val_if_fail(LASSO_IS_SERVER(server), NULL);
2528
2529 login = g_object_new(LASSO_TYPE_LOGIN, NULL);
2530 lasso_assign_gobject(LASSO_PROFILE(login)->server, server);
2531
2532 return login;
2533 }
2534
2535 /**
2536 * lasso_login_new_from_dump:
2537 * @server: the #LassoServer
2538 * @dump: XML login dump
2539 *
2540 * Restores the @dump to a new #LassoLogin.
2541 *
2542 * Return value: a newly created #LassoLogin; or NULL if an error occured.
2543 **/
2544 LassoLogin*
lasso_login_new_from_dump(LassoServer * server,const gchar * dump)2545 lasso_login_new_from_dump(LassoServer *server, const gchar *dump)
2546 {
2547 LassoLogin *login;
2548
2549 login = (LassoLogin*)lasso_node_new_from_dump(dump);
2550 if (! LASSO_IS_LOGIN(login)) {
2551 lasso_release_gobject(login);
2552 } else {
2553 lasso_assign_gobject(login->parent.server, server);
2554 }
2555 return login;
2556 }
2557
2558 /**
2559 * lasso_login_dump:
2560 * @login: a #LassoLogin
2561 *
2562 * Dumps @login content to an XML string.
2563 *
2564 * Return value:(transfer full): the dump string. It must be freed by the caller.
2565 **/
2566 gchar*
lasso_login_dump(LassoLogin * login)2567 lasso_login_dump(LassoLogin *login)
2568 {
2569 return lasso_node_dump(LASSO_NODE(login));
2570 }
2571
2572
2573 /**
2574 * lasso_login_validate_request_msg:
2575 * @login: a #LassoLogin
2576 * @authentication_result: whether user has authenticated succesfully
2577 * @is_consent_obtained: whether user consent has been obtained
2578 *
2579 * Initializes a response to the authentication request received.
2580 *
2581 * Return value: 0 on success; or
2582 * <itemizedlist>
2583 * <listitem><para>#LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ if login is not a #LassoLogin object,</para></listitem>
2584 * <listitem><para>#LASSO_LOGIN_ERROR_REQUEST_DENIED</para> if @authentication_result if FALSE,</listitem>
2585 * <listitem><para>#LASSO_LOGIN_ERROR_INVALID_SIGNATURE if signature validation of the request
2586 * failed,</para></listitem>
2587 * <listitem><para>#LASSO_LOGIN_ERROR_UNSIGNED_AUTHN_REQUEST if no signature was present on the
2588 * request,</para></listitem>
2589 * <listitem><para>#LASSO_LOGIN_ERROR_FEDERATION_NOT_FOUND if federation policy is
2590 * #LASSO_LIB_NAMEID_POLICY_TYPE_NONE and no federation was found in the #LassoIdentity object
2591 * (ID-FF 1.2 case)</para></listitem>
2592 * <listitem><para>#LASSO_LOGIN_ERROR_INVALID_NAMEIDPOLICY if request policy is not one of
2593 * #LASSO_LIB_NAMEID_POLICY_TYPE_FEDERATED or #LASSO_LIB_NAMEID_POLICY_TYPE_ANY (ID-FF 1.2 case) or if no NameID policy was defined or the AllowCreate request flag is FALSE (SAML 2.0 case),</para></listitem>
2594 * <listitem><para>#LASSO_LOGIN_ERROR_CONSENT_NOT_OBTAINED if @is_consent_obtained is FALSE and
2595 * conssent was necessary (for example if the request does not communicate that consent was already
2596 * obtained from the user),</para></listitem>
2597 * <listitem><para>#LASSO_SERVER_ERROR_PROVIDER_NOT_FOUND if the requesting provider is unknown,</para></listitem>
2598 * </itemizedlist>
2599 **/
2600 int
lasso_login_validate_request_msg(LassoLogin * login,gboolean authentication_result,gboolean is_consent_obtained)2601 lasso_login_validate_request_msg(LassoLogin *login, gboolean authentication_result,
2602 gboolean is_consent_obtained)
2603 {
2604 LassoProfile *profile;
2605 gint ret = 0;
2606
2607 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
2608
2609 profile = LASSO_PROFILE(login);
2610
2611 IF_SAML2(profile) {
2612 return lasso_saml20_login_validate_request_msg(login,
2613 authentication_result, is_consent_obtained);
2614 }
2615
2616 /* modify AuthnResponse StatusCode if user authentication is not OK */
2617 if (authentication_result == FALSE) {
2618 lasso_profile_set_response_status(profile,
2619 LASSO_LIB_STATUS_CODE_UNKNOWN_PRINCIPAL);
2620 return LASSO_LOGIN_ERROR_REQUEST_DENIED;
2621 }
2622
2623 /* if signature is not OK => modify AuthnResponse StatusCode */
2624 if (profile->signature_status == LASSO_DS_ERROR_INVALID_SIGNATURE) {
2625 lasso_profile_set_response_status(profile,
2626 LASSO_LIB_STATUS_CODE_INVALID_SIGNATURE);
2627 return LASSO_LOGIN_ERROR_INVALID_SIGNATURE;
2628 }
2629
2630 if (profile->signature_status == LASSO_DS_ERROR_SIGNATURE_NOT_FOUND) {
2631 /* Unsigned AuthnRequest */
2632 lasso_profile_set_response_status(profile,
2633 LASSO_LIB_STATUS_CODE_UNSIGNED_AUTHN_REQUEST);
2634 return LASSO_LOGIN_ERROR_UNSIGNED_AUTHN_REQUEST;
2635 }
2636
2637 if (profile->signature_status == 0 && authentication_result == TRUE) {
2638 /* process federation */
2639 ret = lasso_login_process_federation(login, is_consent_obtained);
2640 if (ret != 0)
2641 return ret;
2642 }
2643
2644 lasso_profile_set_response_status(profile, LASSO_SAML_STATUS_CODE_SUCCESS);
2645
2646 return ret;
2647 }
2648
2649 int
lasso_login_process_paos_response_msg(LassoLogin * login,gchar * msg)2650 lasso_login_process_paos_response_msg(LassoLogin *login, gchar *msg)
2651 {
2652 LassoProfile *profile;
2653
2654 g_return_val_if_fail(LASSO_IS_LOGIN(login), LASSO_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ);
2655 g_return_val_if_fail(msg != NULL, LASSO_PARAM_ERROR_INVALID_VALUE);
2656
2657 profile = LASSO_PROFILE(login);
2658
2659 IF_SAML2(profile) {
2660 return lasso_saml20_login_process_paos_response_msg(login, msg);
2661 }
2662
2663 return 0;
2664 }
2665
2666 /**
2667 * lasso_login_get_assertion:
2668 * @login: a #LassoLogin object
2669 *
2670 * Return the last build assertion.
2671 *
2672 * Return value: a #LassoNode representing the build assertion (generally a #LassoSamlAssertion when
2673 * using ID-FF 1.2 or a #LassoSaml2Assertion when using SAML 2.0)
2674 */
2675 LassoNode*
lasso_login_get_assertion(LassoLogin * login)2676 lasso_login_get_assertion(LassoLogin *login)
2677 {
2678 g_return_val_if_fail (LASSO_IS_LOGIN (login), NULL);
2679
2680 if (login->private_data && login->private_data->saml2_assertion)
2681 return (LassoNode*)g_object_ref(login->private_data->saml2_assertion);
2682
2683 return (LassoNode*)g_object_ref(login->assertion);
2684 }
2685