This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
idpc/src/single_sign_on.c

357 lines
9.5 KiB
C

/*
* idpc - IDP as a C CGI program
* Copyright (C) 2004-2005 Entr'ouvert
*
* Authors: See AUTHORS file in top-level directory.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "idpc.h"
/* the Single Sign On service URL handles several profiles:
* 1. Liberty Artifact (fig2, page20)
* 2. Browser POST (fig3, page26)
* 3. Liberty-Enabled Client and Proxy (fig5, page30) (SOAP request)
*/
int lecp_profile(LassoServer *server)
{
char *soap_msg;
int clen = 0;
int req_type;
LassoLecp *lecp;
char *identity_dump, *session_dump;
int rc;
struct authentication *auth;
char *user_id;
char *reauth_time;
clen = atoi(getenv("CONTENT_LENGTH"));
soap_msg = malloc(clen+1);
soap_msg[clen] = 0;
fgets(soap_msg, clen+1, stdin);
req_type = lasso_profile_get_request_type_from_soap_msg(soap_msg);
if (req_type != LASSO_REQUEST_TYPE_LECP) {
return error_page("soap but req type not LECP");
}
auth = get_authentication(
get_config_string("//idpc:authenticationMethod"));
if (auth == NULL) {
return error_page("Wrong authentication");
}
user_id = auth->auth_function();
if (user_id == NULL) {
/* anyway */
return error_page("Error authenticating");
}
/* retrieve identity_dump and session_dump */
rc = db_get_dumps(user_id, &identity_dump, &session_dump);
if (rc) {
return error_page("Error getting dumps from db");
}
lecp = lasso_lecp_new(server);
rc = set_profile_from_dumps(LASSO_PROFILE(lecp),
identity_dump, session_dump);
free(identity_dump);
free(session_dump);
if (rc) {
lasso_lecp_destroy(lecp);
return error_page("Failed to set profile from dumps");
}
rc = lasso_lecp_process_authn_request_msg(lecp, soap_msg);
if (!rc) {
lasso_lecp_destroy(lecp);
return error_page("lecp init failed");
}
reauth_time = strtime(time(NULL) +
(get_config_string("//idpc:reauthenticationDelay") ?
atoi(get_config_string("//idpc:reauthenticationDelay")) : 7200));
rc = lasso_lecp_build_authn_response_envelope_msg(lecp);
free(reauth_time);
if (!rc) {
lasso_lecp_destroy(lecp);
return error_page("build authn resp failed");
}
printf("Content-Type: application/vnd.liberty-response+xml\n");
printf("Liberty-Enabled: urn:liberty:iff:2003-08 http://projectliberty.org/specs/v1\n");
printf("Cache-Control: no-cache\n");
printf("Pragma: no-cache\n");
printf("\n");
printf(LASSO_PROFILE(lecp)->msg_body);
lasso_lecp_destroy(lecp);
return 0;
}
int single_sign_on()
{
LassoServer *server;
LassoLogin *login;
char *http_verb, *ct;
char *authn_request_msg = NULL;
int rc;
char *user_id;
char *identity_dump, *session_dump;
struct authentication *auth;
int i = 0, authentication_result, reauthentication_delay = 7200;
char *reauth_time, *auth_time, *val;
/* get request method and content type */
http_verb = getenv("REQUEST_METHOD");
if (http_verb == NULL) {
return error_page("No HTTP verb");
}
ct = getenv("CONTENT_TYPE");
if (strcmp(http_verb, "GET") == 0) {
char *query;
query = getenv("QUERY_STRING");
if (query == NULL)
return error_page("No authnRequest as query string");
if (! lasso_profile_is_liberty_query(query))
return error_page("Improper query string; not a AuthnRequest");
authn_request_msg = strdup(query);
}
if (strcmp(http_verb, "POST") == 0) {
if (strcmp(ct, "multipart/form-data") == 0) {
/* example in the spec use x-www-form-urlencoded;
* don't know if multipart/form-data must be supported
*/
return error_page("multipart not supported");
}
if (strcmp(ct, "application/x-www-form-urlencoded") == 0) {
int clen;
char *msg;
char **res;
clen = atoi(getenv("CONTENT_LENGTH"));
msg = malloc(clen+1);
msg[clen] = 0;
fgets(msg, clen+1, stdin);
res = urlencoded_to_strings(msg);
for (i=0; res[i]; i++) {
if (strncmp(res[i], "LAREQ=", 6) == 0) {
authn_request_msg = strdup(res[i]+6);
}
free(res[i]);
}
free(res);
free(msg);
}
}
if (authn_request_msg == NULL)
return error_page("Failed to get authn_request_msg");
server = get_config_server();
if (server == NULL)
return error_page("Failed to get server configuration");
if (strcmp(http_verb, "POST") == 0 && strcmp(ct, "text/xml") == 0) {
rc = lecp_profile(server);
lasso_server_destroy(server);
return rc;
}
/* get user_id; it is the key to retrieve previous identity_dump and
* session_dump */
auth = get_authentication(
get_config_string("//idpc:authenticationMethod"));
if (auth == NULL) {
lasso_server_destroy(server);
return error_page("Wrong authentication");
}
user_id = auth->auth_function();
login = lasso_login_new(server);
rc = lasso_login_process_authn_request_msg(login, authn_request_msg);
if (rc) {
char msg[100];
sprintf(msg, "Lasso login error, %d", rc);
lasso_login_destroy(login);
lasso_server_destroy(server);
return error_page(msg);
}
if (user_id == NULL) {
authentication_result = 0;
} else {
authentication_result = 1;
/* retrieve identity_dump and session_dump */
rc = db_get_dumps(user_id, &identity_dump, &session_dump);
if (rc) {
lasso_server_destroy(server);
return error_page("Error getting dumps from db");
}
rc = set_profile_from_dumps(LASSO_PROFILE(login),
identity_dump, session_dump);
free(identity_dump);
free(session_dump);
if (rc) {
lasso_server_destroy(server);
lasso_login_destroy(login);
return error_page("Failed to set profile from dumps");
}
}
rc = lasso_login_must_authenticate(login);
if (rc == 1 && user_id == NULL) {
/* must authenticate and user_id was NULL; bad (an
* authentication scheme not handled by Apache could be
* inserted here)
*/
}
/* validate request message */
rc = lasso_login_validate_request_msg(login, authentication_result, 1);
if (rc) {
lasso_server_destroy(server);
lasso_login_destroy(login);
return error_page("validate_request_msg failed");
}
/* build assertion */
val = get_config_string("//idpc:reauthenticationDelay");
if (val != NULL) {
reauthentication_delay = atoi(val);
free(val);
}
auth_time = strtime(time(NULL));
reauth_time = strtime(time(NULL) + reauthentication_delay);
rc = lasso_login_build_assertion(login,
auth->lasso_name,
auth_time, /* authenticationInstant */
reauth_time, /* reauthenticateOnOrAfter */
NULL, /* notBefore */
NULL); /* notOnOrAfter */
free(auth_time);
free(reauth_time);
if (rc) {
lasso_login_destroy(login);
lasso_server_destroy(server);
return error_page("Failed to build assertion");
}
if (login->protocolProfile == LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART) {
/* build artifact */
rc = lasso_login_build_artifact_msg(login,
LASSO_HTTP_METHOD_REDIRECT);
if (rc) {
lasso_login_destroy(login);
lasso_server_destroy(server);
return error_page("build_artifact_msg failed");
}
rc = db_save_artifact(login->assertionArtifact,
user_id,
LASSO_PROFILE(login)->remote_providerID);
if (rc) {
lasso_login_destroy(login);
lasso_server_destroy(server);
return error_page("Failed to save assertion");
}
} else {
/* POST profile (lassoLoginProtocolProfileBrwsPost) */
rc = lasso_login_build_authn_response_msg(login);
if (rc) {
lasso_login_destroy(login);
lasso_server_destroy(server);
return error_page("build_authn_response_msg failed");
}
}
rc = db_save_name_identifier(
LASSO_PROFILE(login)->nameIdentifier->content, user_id);
if (rc) {
lasso_login_destroy(login);
lasso_server_destroy(server);
return error_page("Failed to save name identifier");
}
rc = save_profile_dumps(LASSO_PROFILE(login));
if (rc) {
lasso_login_destroy(login);
lasso_server_destroy(server);
return error_page("Failed to save dumps");
}
if (login->protocolProfile == LASSO_LOGIN_PROTOCOL_PROFILE_BRWS_ART) {
printf("Location: %s\n\nRedirected", LASSO_PROFILE(login)->msg_url);
} else {
/* POST profile (lassoLoginProtocolProfileBrwsPost) */
/* XXX: invalid and unqualified html */
printf("Content-type: text/html\n\n");
printf("<html><head><title>Authentication Response</title></head>\n"
"<body onload=\"document.forms[0].submit()\">\n"
" <form action=\"%s\" method=\"post\">\n"
" <p>You should be automaticaly redirected to your"
" service provider.</p>\n"
" <p>If this page is still visible after a few seconds,\n"
" press the <em>Send</em> button below.</p>\n"
" <input type=\"hidden\" name=\"LARES\" value=\"%s\"/>\n"
" <input type=\"submit\" />\n"
" </form>\n"
"</body></html>",
LASSO_PROFILE(login)->msg_url,
LASSO_PROFILE(login)->msg_body);
}
lasso_login_destroy(login);
lasso_server_destroy(server);
return rc;
}
int main(int argc, char *argv[])
{
int rc;
if (argc > 1 && handle_args(argc, argv)) {
return 0;
}
rc = init_config();
if (rc != 0) {
return error_page("Failed to init configuration");
}
lasso_init();
rc = db_init();
if (rc != 0) {
error_page("Failed to init database access");
goto shutdown;
}
rc = single_sign_on();
shutdown:
db_finish();
lasso_shutdown();
return rc;
}