From 3a7173ad3be58f6518eda5abb3a754012b2cb1b4 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Fri, 17 Oct 2014 22:54:10 +0200 Subject: [PATCH] Add simple example of a CGI service provider script written in C --- examples/sp-cgi/README | 26 ++ examples/sp-cgi/cert.pem | 21 ++ examples/sp-cgi/key.pem | 27 ++ examples/sp-cgi/main.c | 526 ++++++++++++++++++++++++++++++++++++ examples/sp-cgi/openidp.xml | 27 ++ examples/sp-cgi/test.cgi | 2 + 6 files changed, 629 insertions(+) create mode 100644 examples/sp-cgi/README create mode 100644 examples/sp-cgi/cert.pem create mode 100644 examples/sp-cgi/key.pem create mode 100644 examples/sp-cgi/main.c create mode 100644 examples/sp-cgi/openidp.xml create mode 100755 examples/sp-cgi/test.cgi diff --git a/examples/sp-cgi/README b/examples/sp-cgi/README new file mode 100644 index 00000000..feb8b6ee --- /dev/null +++ b/examples/sp-cgi/README @@ -0,0 +1,26 @@ +Starting +======== + +To run this CGI SAML 2.0 SP, you must: + +- configure Apache (or any other web-service handling CGI scripts) for + running CGI scripts +- compile this script by doing: + + make + +- put all projects files in a directory readable and *writable* (for session + files) by Apache2. The script test.cgi should be accessible through the URL + http://yourdomain.com/.../test.cgi. +- retrieve the metadata content on http://yourdomain.com/.../test.cgi/metadata and put them + in a file named metadata.xml +- register on https://openidp.feide.no/ and upload the `metadata.xml` file on + https://openidp.feide.no/simplesaml/module.php/metaedit/index.php +- go on http://yourdomain.com/.../test.cgi/login and see that SAML 2.0 login is working + +Details +======= + +Retrieved attributes are stored in a session file, session id are stored in a +cookie named `session_id`, session file is named `session_` and it +contains attributes formatted following RFC822 (format of mail or HTTP headers). diff --git a/examples/sp-cgi/cert.pem b/examples/sp-cgi/cert.pem new file mode 100644 index 00000000..6e273d28 --- /dev/null +++ b/examples/sp-cgi/cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAKvk3IHm+0djMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTQxMDE3MjAwNTQzWhcNNDIwMzA0MjAwNTQzWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA4ZUG25RBw2XCSlFXjeOm/2WoKb2Isqb5cE/v0sWfJEG8UAUEslDGA9JS +fHTuWvFVYtdyQydJ+/LLoG3ARMcGyUyY0TAXDXKuUIev/n67b+JPg9thOw2adGPJ +dnsmes3UNkXi/+Gt0oN3tXQsDJjUMA3M8DVT1fVuXefOY/kZk7hj+WzlNMTQJ1OV +xWnBl5HGrT3Fm5smue3d/tP9hcdUHh9XVW32CcCaWAnVJCsFzQvehpfJOAJIxxY+ +0iGBCzb/X21JcbFST7S1Hpckf45ehoziVFcVJ6BvYZnq74JDNzCquvIfOHcmeebN +vx9gP1ANaxV3ThK18miiXEMGsIpHcQIDAQABo1AwTjAdBgNVHQ4EFgQURs0UVS5M +M/XcmhG8uhfX61R8jd4wHwYDVR0jBBgwFoAURs0UVS5MM/XcmhG8uhfX61R8jd4w +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAAXh+BwvuThKnXBgnoTOB +vjAhx8/CyM+Od3g5aZQssL4W6tdJayUHyhigQyWlKaBWlQ5NDeY3TMU/fcg5+3Jg +vvkxaryKkYpJEPh1Ay9rPe2LMSit1CSD9O6yZ4AqZMyx3KSoMm3f/ziW8zEqudus +voJjCumHlF5MQa6oqgFQy2lJcF9rEssIIpkZ4ZblIoelKaP8B6KPcGa5CCtPUoVu +R2u+TbNr0skVtYdcAInF+peFGyJjyMAgy5MqtTid+PG1r+PWVQbuWOvv6Jk1fyQd +fWssgyDZkXJLcHi0AU8XypYzr7gkPOSgkoSNFbkz4jYiPlvRfhDNk5FKcW+bWhCY +LA== +-----END CERTIFICATE----- diff --git a/examples/sp-cgi/key.pem b/examples/sp-cgi/key.pem new file mode 100644 index 00000000..22ce6c0e --- /dev/null +++ b/examples/sp-cgi/key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA4ZUG25RBw2XCSlFXjeOm/2WoKb2Isqb5cE/v0sWfJEG8UAUE +slDGA9JSfHTuWvFVYtdyQydJ+/LLoG3ARMcGyUyY0TAXDXKuUIev/n67b+JPg9th +Ow2adGPJdnsmes3UNkXi/+Gt0oN3tXQsDJjUMA3M8DVT1fVuXefOY/kZk7hj+Wzl +NMTQJ1OVxWnBl5HGrT3Fm5smue3d/tP9hcdUHh9XVW32CcCaWAnVJCsFzQvehpfJ +OAJIxxY+0iGBCzb/X21JcbFST7S1Hpckf45ehoziVFcVJ6BvYZnq74JDNzCquvIf +OHcmeebNvx9gP1ANaxV3ThK18miiXEMGsIpHcQIDAQABAoIBAQCGuqE76BJXB6HB +DVADmKIXC7oiI+dO/FciczvDYPCpkPFNwZGKhp+djLJjTttFSbo7rH28Ce0wI1Tm +3mXlLhGpjKwA1H4QNBxUUJYWo86DBmGDWTV7Naa4ORkMQIU89031lEv9k+ZjQs3u +fBIK/ARPJw7tsIv/z/Q49cfZAd/6zxki/naN17mgIf38uK29BuENnaGY9UNcH33l +ZMGY7X/yuF/CDK53ZVAgqyn4WKloiWYbltOA2p13jglZPI3vszl9NqMMHmp7qooP +XNVvezt/tbDdLyFx6otsONKKTUTQzitTHf441u9xpPOdYxXO5DrLkJqmJ6S022+3 +e6WDFTY5AoGBAPNSFdVy2DeZU+890qO08QKc592WYQ8Uhj7f+bSHU9+aIHVBW00o +9d/QpSQVI5OEY5oXwSn6bi5kECU3upG9xgNbnK2ybC/gccJOebmrqXmDvY0iSMQt +Fa5LkYYDeuW8UabiH7yBuwbZzpipOHWtbfjpjYcdXEPXkewhLQZDFnmzAoGBAO1W +TvsP4fOpbl0d5RZJkW9WcWgnZp3YAgmkmOo9hLPjuvPaJjLdVw9oq/NQpnSeDhvF +pece00e5FY4rPnSu+cKgpnKuqUaF/Sb99Ny+kYM245PpQzXG/dQS9Q5fn4LZxwLl +kRd4CDYew6jLTIS2J8MsGw3aIWMLus6lb2n7qOBLAoGBAJO0BYr/3x7JFbmJ9t7n +jNIAO4Q4sAx+cgui3Kro51I59nAXT3wkXDUUK9sede0rlWbJ+rkny1Cf72kYTkoA +QD5zk0WhpKjff07rYlsCSKt5/Eu7Px7PG3UlbF5EqIri6VH7vDYrLkQ3XYEwYBSX +RcWuyPn3KbYJGwyTCwjdGryfAoGAJwrksT5aoDfGFQFe9zyg9RzWSRj6M4seQrHW +CeqW0vTqg0TmtcVdlgZVCxDAYTzC+2SXNx8GCK10009f1dgW9CJzXzhGVniiPXDX +gBzFWT2FUIa17LnQdbusnnGyjtb+ewaCyMaRKz4CV9khvE8u2Vd/F9dDWMTMNURX +wKqKjGMCgYEAiGEIBH7mGjf6kZOb4nVA/ZJI4CkB4Ch++LhIHjDKK6mPz5j7kRHU +AgjBtTIMogRBnEgfcDEAKkJ4K25mjV7V3kWgqcWG7W7i+xz080RuZdbS4149oFu2 +t7EIHpzNcKNYRmPXUvROxAYWly2IevulbDJf3mHidQasrcYI8fh/W+Q= +-----END RSA PRIVATE KEY----- diff --git a/examples/sp-cgi/main.c b/examples/sp-cgi/main.c new file mode 100644 index 00000000..5e7dbc76 --- /dev/null +++ b/examples/sp-cgi/main.c @@ -0,0 +1,526 @@ +/** + * Simple Lasso CGI + * + * take its own metadata file as first argument, the private key as second argument, then IdP metadata files. + * URL, HOST and HTTP scheme are extracted from environment, metadata file is generated. + * + * + * The assertion consumer only support the POST binding. + * + * Entr'ouvert © 2014 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +LassoServer *server = NULL; + +/* CGI Env */ +static char *query_string = NULL; +static char *path_info = NULL; +static char *host = NULL; +static char *script_name = NULL; +static char *scheme = NULL; +static char *content_type = NULL; +static char* content_length = NULL; + +/* SP metadatas and keys */ +static char *private_key = NULL; +static size_t private_key_length = 0; +static char *certificate = NULL; +static size_t certificate_length = 0; +static char *metadata = NULL; +static size_t metadata_length = 0; + +char* +get_cookie(const char *cookie_name) +{ + char *cookies = getenv("HTTP_COOKIE"); + size_t l = strlen(cookie_name); + char *value = NULL; + + if (! cookies) { + return NULL; + } + while (*cookies) { + if (*cookies == ' ') { + cookies++; + } else { + char *next_semicolon = strchr(cookies, ';'); + + if (startswith(cookies, cookie_name) && cookies[l] == '=') { + size_t size = 0; + + cookies += l + 1; + if (next_semicolon) { + size = cookies - next_semicolon; + } else { + size = strlen(cookies); + } + value = malloc(size+1); + value[size] = '\0'; + strncpy(value, cookies, size); + break; + } + if (next_semicolon) { + cookies = next_semicolon + 1; + } else { + break; + } + } + } + return value; +} + +char* +get_parameter2(const char *name, const char *qs) { + const size_t l = strlen(name); + char *value = NULL; + + if (! qs) { + return NULL; + } + + while (qs) { + const char *next_amp = strchr(qs, '&'); + + if (startswith(qs, name) && (qs[l] == '=' || qs[l] == '&' || qs[l] == '\0')) { + char *copy = NULL; + size_t size = 0; + + qs += l; + if (*qs) { + qs++; + } + if (next_amp) { + size = next_amp - qs; + } else { + size = strlen(qs); + } + copy = alloca(size+1); + copy[size] = '\0'; + strncpy(copy, qs, size); + value = g_uri_unescape_string(copy, NULL); + break; + } + if (next_amp) { + qs = next_amp + 1; + } else { + break; + } + } + return value; +} + +char* +get_parameter(const char *name) { + const char *qs = getenv("QUERY_STRING"); + + return get_parameter2(name, qs); +} + +gboolean +startswith(const char *s, const char *needle) { + if (! needle) { + return TRUE; + } + if (! s) { + return FALSE; + } + return strncmp(s, needle, strlen(needle)) == 0; +} + +#define OR(a,b) ((a) ? (a) : (b)) + +int +main(int argc, char **argv) { + int i = 0; + char *pair = NULL; + struct stat buf; + char *end; + int ret, fd; + GError *err; + + if (argc < 2) { + g_error("You must give your private key file as first argument"); + } + + if (argc < 3) { + g_error("You must give your certificate file as second argument"); + } + + if (! g_file_get_contents(argv[1], &private_key, &private_key_length, &err)) { + g_error("Failed to read %s: %s", argv[1], err->message); + } + if (! g_file_get_contents(argv[1], &certificate, &certificate_length, &err)) { + g_error("Failed to read %s: %s", argv[2], err->message); + } + + /* remove PEM prefix and suffix */ + while (*certificate != '\n' && *certificate != '\0') { + certificate++; + } + certificate++; + end = certificate; + while (*end != '-' && *end != '\0') { + end++; + } + end--; + *end = '\0'; + + /* read CGI env */ + path_info = OR(getenv("PATH_INFO"), ""); + query_string = OR(getenv("QUERY_STRING"), ""); + host = OR(getenv("HTTP_HOST"), ""); + script_name = OR(getenv("SCRIPT_NAME"), ""); + content_type = OR(getenv("CONTENT_TYPE"), ""); + content_length = OR(getenv("CONTENT_LENGTH"), ""); + if (getenv("HTTPS")) { + scheme = "https"; + } else { + scheme = "http"; + } + + /* generate metadata */ + metadata_length = snprintf_metadata(NULL, 0); + metadata = g_malloc(metadata_length+1); + snprintf_metadata(metadata, metadata_length+1); + metadata[metadata_length] = '\0'; + + + /* create Lasso objects */ + lasso_init(); + server = lasso_server_new_from_buffers(metadata, private_key, NULL, NULL); + g_message("Server created with private key %s and certificate %s", argv[1], argv[2]); + for (i = 3; i < argc; i++) { + lasso_error_t rc = 0; + g_message("Loading idp metadata %s", argv[i]); + rc = lasso_server_add_provider(server, LASSO_PROVIDER_ROLE_IDP, argv[i], NULL, NULL); + if (rc != 0) { + g_error("Failed to load IdP metadata %s: %s", argv[i], lasso_strerror(rc)); + } + } + + if (strcmp(path_info, "/metadata") == 0) { + return show_metadata(); + } else if (strcmp(path_info, "/login") == 0) { + return emit_authn_request(); + } else if (strcmp(path_info, "/assertionConsumerPost") == 0) { + return assertion_consumer(); + } else if (strcmp(path_info, "/logout") == 0) { + return logout(); + } else if (strcmp(path_info, "/") == 0) { + return homepage(); + } else { + printf("Location: %s/\n\n", script_name); + } +} + +int +homepage() +{ + char *session_id = get_cookie("session_id"); + + printf("Content-type: text/html\n\n"); + printf("\n"); + printf("\n"); + if (session_id) { + char *session_path = g_strdup_printf("session_%s", session_id); + char *content; + size_t length; + GError *error; + + if (g_file_get_contents(session_path, &content, &length, &error)) { + g_message("session_path %sx", session_path); + printf("

Session ID: %s

", g_markup_escape_text(session_id, strlen(session_id))); + printf("
\n");
+			fwrite(content, length, 1, stdout);
+			printf("
\n"); + g_free(content); + } else { + g_error("Unable to read %s %s", session_path, error->message); + } + } + + return 0; +} + +int +show_metadata() +{ + printf("Content-Type: text/xml\n\n%s", metadata); + return 0; +} + +int +snprintf_metadata(char *output, size_t length) { + size_t l = 0; + + l += snprintf(output+l, length, "\n"); + l += snprintf(output+l, length, "\n", scheme, host, script_name); + l += snprintf(output+l, length, "\n"); + l += snprintf(output+l, length, "\n\ +\n\ +\n\ +%s\n\ +\n\ +\n\ +\n", certificate); + l += snprintf(output+l, length, "\n", scheme, host, script_name); + l += snprintf(output+l, length, "\n"); + return l; +} + +int +emit_authn_request() { + gboolean is_passive = FALSE; + char *entity_id = NULL; + char *relay_state = NULL; + LassoLogin *login = NULL; + LassoHttpMethod http_method = LASSO_HTTP_METHOD_ANY; + + is_passive = get_parameter("isPassive") != NULL; + entity_id = get_parameter("entityID"); + relay_state = get_parameter("ReturnURL"); + + login = lasso_login_new(server); + if (! login) { + g_error("Unable to create a login object"); + } + { + lasso_error_t rc = lasso_login_init_authn_request(login, entity_id, http_method); + if (rc != 0) { + g_error("lasso_login_init_authn_request returned an error: %s", lasso_strerror(rc)); + } + } + ((LassoSamlp2AuthnRequest*)login->parent.request)->IsPassive = is_passive; + login->parent.msg_relayState = relay_state; + { + lasso_error_t rc = lasso_login_build_authn_request_msg(login); + if (rc != 0) { + g_error("lasso_login_build_authn_reques_msg returned an error: %s", lasso_strerror(rc)); + } + } + if (login->parent.msg_body) { // POST binding case + printf("Content-type: text/html\n\n"); + printf("\n\ +\n\ +
\n\ +\n", login->parent.msg_url, login->parent.msg_body); + if (relay_state) { + printf("\n", + g_markup_escape_text(relay_state, -1)); + } + printf("
\n\ +\n\ +"); + } else { // redirect binding case + printf("Status: 303 See other\n"); + printf("Location: %s\n", login->parent.msg_url); + printf("\n"); + } +} + +void +write_rfc822_field_value(FILE *file, char *value) +{ + char *p = NULL; + + p = strchr(value, '\n'); + while (p) { + p += 1; + fwrite(value, p-value, 1, file); + value = p; + // add continuation whitespace + fprintf(file, " "); + p = strchr(value, '\n'); + } + fprintf(file, "%s\n", value); + +} + +void +write_attributes(LassoLogin *login, FILE *session_file) +{ + LassoSamlp2Response *response = (LassoSamlp2Response*)login->parent.response; + LassoSaml2Assertion *assertion = (LassoSaml2Assertion*)response->Assertion->data; + LassoSaml2NameID *issuer = response->parent.Issuer; + LassoSaml2Subject *subject = assertion->Subject; + LassoSaml2NameID *name_id= subject->NameID; + GList *ats_list, *at_list, *atv_list; + + fprintf(session_file, "Issuer: "); + write_rfc822_field_value(session_file, issuer->content); + fprintf(session_file, "NameID: "); + write_rfc822_field_value(session_file, name_id->content); + fprintf(session_file, "NameIDFormat: "); + write_rfc822_field_value(session_file, name_id->Format); + ats_list = assertion->AttributeStatement; + while (ats_list) { + LassoSaml2AttributeStatement *ats = ats_list->data; + at_list = ats->Attribute; + while(at_list) { + LassoSaml2Attribute *at = at_list->data; + atv_list = at->AttributeValue; + while (atv_list) { + LassoSaml2AttributeValue *atv = atv_list->data; + if (atv->any && atv->any->data && LASSO_IS_MISC_TEXT_NODE(atv->any->data)) { + LassoMiscTextNode *mtn = atv->any->data; + fprintf(session_file, "%s: ", at->Name); + write_rfc822_field_value(session_file, mtn->content); + } + atv_list = atv_list->next; + } + at_list = at_list->next; + } + ats_list = ats_list->next; + } + +} + +int +assertion_consumer() { + size_t content_length_s = 0; + char *buffer = NULL; + int l = 0; + int ret = 0; + char *saml_response = NULL; + char *relay_state = NULL; + LassoLogin *login = NULL; + + if (! content_type || strcmp(content_type, "application/x-www-form-urlencoded") != 0) { + g_error("Content-type is not application/x-www-form-urlencoded"); + } + if (! content_length) { + g_error("Missing CONTENT_LENGTH environment variable"); + } + content_length_s = atoi(content_length); + if (content_length_s > 100000 || content_length_s < 0) { + g_error("Invalid CONTENT_LENGTH"); + } + buffer = malloc(content_length_s+1); + buffer[content_length_s] = '\0'; + while (ret = read(0, buffer+l, content_length_s-l)) { + if (ret == -1) { + if (errno == EINTR) { + continue; + } + g_error("Error while reading POST data %s", strerror(errno)); + } + l += ret; + } + + saml_response = get_parameter2("SAMLResponse", buffer); + relay_state = get_parameter2("RelayState", buffer); + + if (! saml_response) { + printf("Status: 401 Invalid request\n"); + printf("Content-type: text/lain\n\n"); + printf("Missing SAMLResponse"); + } + + login = lasso_login_new(server); + if (! login) { + g_error("Unable to create a login object"); + } + g_message("SAMLRequest %s", saml_response); + { + lasso_error_t rc = 0; + rc = lasso_login_process_authn_response_msg(login, saml_response); + if (rc == LASSO_PROFILE_ERROR_STATUS_NOT_SUCCESS) { + LassoSamlp2Response *response = (LassoSamlp2Response*)login->parent.response; + printf("Content-type: text/html\n\n"); + printf("

Authentication request was denied

"); + printf("
");
+			printf("Status message: %s\n", response->parent.Status->StatusMessage);
+			if (response->parent.Status->StatusCode->Value)
+				printf("First level status code: %s\n", response->parent.Status->StatusCode->Value);
+			if (response->parent.Status->StatusCode->StatusCode->Value)
+				printf("Second level status code: %s\n", response->parent.Status->StatusCode->StatusCode->Value);
+			printf("
"); + printf("Back", script_name); + return 0; + } else if (rc != 0) { + g_error("lasso_login_process_authn_response_msg returned an error: %s", lasso_strerror(rc)); + } + } + // Allocate new session + { + long unsigned int session_id = (long unsigned int)random(); + char *session_file_path = NULL; + FILE *session_file = NULL; + int l = snprintf(NULL, 0, "session_%lu", session_id); + session_file_path = malloc(l+1); + session_file_path[l] = '\0'; + sprintf(session_file_path, "session_%lu", session_id); + + session_file = fopen(session_file_path, "w+"); + if (! session_file) { + g_error("Cannot open session_file %s: %s", session_file_path, strerror(errno)); + } + write_attributes(login, session_file); + fclose(session_file); + + printf("Status: 303 See other\n"); + printf("Set-Cookie: session_id=%lu;path=/\n", session_id); + if (relay_state) { + printf("Location: %s\n", relay_state); + } else { + printf("Location: %s/\n", script_name); + } + printf("\n"); + } + return 0; +} + +int +logout() +{ + char *session_id = get_cookie("session_id"); + char *return_url = NULL; + + return_url = get_parameter("ReturnURL"); + if (session_id) { + char *path = NULL; + size_t size = snprintf(NULL, 0, "session_%s", session_id); + int rc; + path = malloc(size+1); + sprintf(path, "session_%s", session_id); + rc = unlink(path); + if (rc == -1 && errno != ENOENT) { + g_error("logout: unlink of %s failed", path); + } + free(path); + } + printf("Status: 303 See other\n"); + if (return_url) { + printf("Location: %s\n", return_url); + } else { + printf("Location: %s/\n", script_name); + } + // Delete the session cookie + printf("Set-Cookie: session_id=;path=/;Expires=Thu, 01-Jan-1970 00:00:01 GMT\n"); + printf("\n"); + return 0; +} diff --git a/examples/sp-cgi/openidp.xml b/examples/sp-cgi/openidp.xml new file mode 100644 index 00000000..54801df0 --- /dev/null +++ b/examples/sp-cgi/openidp.xml @@ -0,0 +1,27 @@ + + + + + + + MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w== + + + + + + + MIICizCCAfQCCQCY8tKaMc0BMjANBgkqhkiG9w0BAQUFADCBiTELMAkGA1UEBhMCTk8xEjAQBgNVBAgTCVRyb25kaGVpbTEQMA4GA1UEChMHVU5JTkVUVDEOMAwGA1UECxMFRmVpZGUxGTAXBgNVBAMTEG9wZW5pZHAuZmVpZGUubm8xKTAnBgkqhkiG9w0BCQEWGmFuZHJlYXMuc29sYmVyZ0B1bmluZXR0Lm5vMB4XDTA4MDUwODA5MjI0OFoXDTM1MDkyMzA5MjI0OFowgYkxCzAJBgNVBAYTAk5PMRIwEAYDVQQIEwlUcm9uZGhlaW0xEDAOBgNVBAoTB1VOSU5FVFQxDjAMBgNVBAsTBUZlaWRlMRkwFwYDVQQDExBvcGVuaWRwLmZlaWRlLm5vMSkwJwYJKoZIhvcNAQkBFhphbmRyZWFzLnNvbGJlcmdAdW5pbmV0dC5ubzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt8jLoqI1VTlxAZ2axiDIThWcAOXdu8KkVUWaN/SooO9O0QQ7KRUjSGKN9JK65AFRDXQkWPAu4HlnO4noYlFSLnYyDxI66LCr71x4lgFJjqLeAvB/GqBqFfIZ3YK/NrhnUqFwZu63nLrZjcUZxNaPjOOSRSDaXpv1kb5k3jOiSGECAwEAATANBgkqhkiG9w0BAQUFAAOBgQBQYj4cAafWaYfjBU2zi1ElwStIaJ5nyp/s/8B8SAPK2T79McMyccP3wSW13LHkmM1jwKe3ACFXBvqGQN0IbcH49hu0FKhYFM/GPDJcIHFBsiyMBXChpye9vBaTNEBCtU3KjjyG0hRT2mAQ9h+bkPmOvlEo/aH0xR68Z9hw4PF13w== + + + + + urn:oasis:names:tc:SAML:2.0:nameid-format:transient + + + + Feide + support + support@feide.no + + diff --git a/examples/sp-cgi/test.cgi b/examples/sp-cgi/test.cgi new file mode 100755 index 00000000..dc859f11 --- /dev/null +++ b/examples/sp-cgi/test.cgi @@ -0,0 +1,2 @@ +#!/bin/sh +exec ./main key.pem cert.pem openidp.xml