============================= Single Sign-On and Federation ============================= Profile Overview ================ The service provider has four things to do: - creating an authentication request - sending it to the identity provider - receiving an authentication response or an artifact - (eventually) checking it against the identity provider The first two steps are handled with an HTTP redirection or an HTML form; typically the user would click on a button, the service provider would then create the authentication request and send an HTTP Redirect to the browser. No URL is defined in the specifications for this first step. The last two steps are handled in the *AssertionConsumerServiceURL*; the user will arrive there through an HTTP Redirect or an HTTP POST carrying a piece of information from the identity provider. In case of a redirect, this information, called *artifact*, won't be large and will be exchanged with the identity provider for a *AuthnResponse*. An HTTP POST will be able to carry much more information and will therefore be able to provide either the *artifact* or directly the *AuthnResponse*. An appropriate metadata snippet would be:: https://service-provider.example.com/liberty-alliance/assertionConsumer The identity provider has more things to do: - receiving an authentication request - authenticating the user if necessary - sending a response to the service provider - (eventually) answering a SOAP request with an other response All but the last one is handled in the *SingleSignOnServiceURL*; the user has been redirected there from the service provider with an authentication request as URL parameter. This authentication request is used to decide several things (allowed authentication methods for example) and the authentication is done. This step is not part of the Liberty protocols, this can be as simple as straight HTTP authentication with a username and a password or as complex as a Java applet checking a certificate on the client. Anyway, once the user has been authenticated, an answer must be sent to the service provider. It is actually not a direct communication, the answer bounces on the user agent with an HTTP Redirect or by an HTML form pointing to the service provider. The answer may be an *artifact* (available in the query string in case of a redirect or in a ``LAREQ`` form field in case of a POST); the user is then simply redirected to this URL. The service provider will then make a SOAP request to the *SoapEndpoint* asking for the authentication response matching the artifact. The answer may also be an *authentication response*; since it will be a large piece of data it must be passed in an HTML page; an HTML form embedding the authentication response. The user will then submit this form to the service provider *AssertionConsumerURL*. Metadata would be:: https://identity-provider.example.com/soapEndpoint https://identity-provider.example.com/singleSignOn Implementing the service provider parts ======================================= .. warning:: The source code presented in the "implementing" section has for sole purpose to explain the different steps necessary to implement the profiles; they notably lack proper error checking. See XXX for details on error checking. Sending the user to the identity provider ----------------------------------------- ``server`` is a *LassoServer* object as seen earlier (`LassoServer`_) and ``idpProviderId`` is a string with the identity provider Id (the string must match a providerID defined in the metadata file). :: LassoLogin *login; /* create login object */ login = lasso_login_new(server); Select profile to use, HTTP Redirect:: lasso_login_init_authn_request(login, idpProviderId, LASSO_HTTP_METHOD_REDIRECT); or HTTP POST:: lasso_login_init_authn_request(login, idpProviderId, LASSO_HTTP_METHOD_POST); Parametrize request:: /* will force authentication on the identity provider */ LASSO_LIB_AUTHN_REQUEST(LASSO_PROFILE(login)->request)->ForceAuthn = TRUE; /* ask for identity federation */ LASSO_LIB_AUTHN_REQUEST(LASSO_PROFILE(login)->request)->NameIDPolicy = strdup(LASSO_LIB_NAME_ID_POLICY_TYPE_FEDERATED); /* the user consents with the idea of identity federation */ LASSO_LIB_AUTHN_REQUEST(LASSO_PROFILE(login)->request)->consent = strdup(LASSO_LIB_CONSENT_OBTAINED); (see API reference for other possible values) Create the authentication request:: lasso_login_build_authn_request_msg(login); An URL is then defined in ``LASSO_PROFILE(login)->msg_url``; the user must be redirected to it; for example, in a CGI:: printf("Location: %s\n", LASSO_PROFILE(login)->msg_url); Receiving an answer from the identity provider ---------------------------------------------- This part is handled on the *AssertionConsumerURL*. Receiving an assertion ...................... The user has been directed to this URL. If it was a redirect the query string (the part of the URL after the question mark) will hold the artifact and may be used to initialize the *LassoLogin* object. :: LassoLogin *login; login = lasso_login_new(server); lasso_login_init_request(login, query_string, LASSO_HTTP_METHOD_REDIRECT); lasso_login_build_request_msg(login); If it was a form post it will have a ``LAREQ`` field. :: LassoLogin *login; login = lasso_login_new(server); lasso_login_init_request(login, lareq_field, LASSO_HTTP_METHOD_POST); lasso_login_build_request_msg(login); The service provider must then check this artifact using a SOAP request to the identity provider. The URL is ``LASSO_PROFILE(login)->msg_url`` while the request is ``LASSO_PROFILE(login)->msg_body``. The request must succeed with an HTTP 200 status code. The SOAP answer body must then be passed to:: lasso_login_process_response_msg(login, answer); Receiving an authentication response .................................... A form with a ``LARES`` field has been posted; this element holds the authentication response. :: LassoLogin *login; login = lasso_login_new(server); lasso_login_process_authn_response_msg(lares_field); Federating identities ..................... There is then a ``nameIdentifier`` (accessible through ``LASSO_PROFILE(login)->nameIdentifier``) for the user identifying. If this name identifier is already known by the service provider the corresponding identity and session must be restored. :: if (session_dump != NULL) { lasso_profile_set_session_from_dump(LASSO_PROFILE(login), session_dump); } if (identity_dump != NULL) { lasso_profile_set_identity_from_dump(LASSO_PROFILE(login), identity_dump); } Process the authentication request, this will update (or create) the identity and session. :: lasso_login_accept_sso(login); Identity and session must then be saved and finally the ``login`` object can be destroyed:: lasso_login_destroy(login); And a success web page may then be displayed. Implementing the identity provider parts ======================================== XXX