/*! \Copyright Sertainty Corporation, 2018. All Rights Reserved. \File 6-id_session.c \Brief This sample demonstrates how to authenticate into an ID session and use it to auto-authenticate, also known as, Single Sign-On, into a UXP Object. \Details A UXP Object requires authentication of the prospective user (process or person). ßAccess will only be granted after a successful authentication. Having to individually authenticate into multiple UXP Objects is time-consuming. Also time-consuming is authenticating into a single UXP Object multiple times. As a convenience, a UXP Identity can be used for a Single Sign-On session. A Single Sign-On session allows automatic authentication into UXP Objects that were created using that same UXP Identity. For authentication, there are two approaches to programatically seeking authorization. The first approach is to declare a function callback that is called when the system presents challenges. The callback function is given the list of challenges that it must process and return. The callback function is called until resolution is reached. The second uses a looping process to allow the program to handle the challenge list manually. Responses are then given back to the system and the authentication loop continues until a resolution is reached. \Author Greg Smith \Date 10/30/2019 \Editor Karim Lalani \Date 06/11/2020 \Note Application expects to find the necessary source files in the current working folder. */ #include "uxpfile_c.h" #include "uxpfile_common.h" #include "uxplist_c.h" #include "uxlbytearray_c.h" #include "uxpvfile_c.h" #include "uxpcredential_c.h" #include "uxpid_c.h" #include "uxpsys_c.h" #include #include #include /** * @brief Checks for an error and logs message. * @param handle Handle to check. * @param msg Message to display. */ static void checkError(void *handle, const char *msg) { if (uxpsys_hasError(handle)) { const char *errMsg = uxpsys_getErrorMessage(handle); printf("%s error: %s\n", msg, errMsg); exit(1); } } /** * Get challenge from the user. * @param ch Challenge handle. * @return True if accepted. False if cancelled. */ static int getResponse(uxpChallengeHandle ch); /** * @brief Main entry point * @param argc Number of arguments * @param argv Array of argument tokens * @return 0 - success, 1 - error */ int main(int argc, char *argv[]) { uxpFileHandle appHandle; uxpIdHandle idHandle; long long len; uxlByteArray *buffer; uxpCallStatusHandle callstatus = uxpsys_newCallStatusHandle(); const char *idXmlSpec = "sampleid.xml"; const char *idFileSpec = "sampleid.iic"; const char *uxpFileSpec = "sample.uxp"; const char *dataPdfSpec = "data.pdf"; const char *dataPdf2Spec = "data2.pdf"; const char *copy1Spec = "copy1.pdf"; const char *copy2Spec = "copy2.pdf"; int status = StatusChallenged; int cnt, i; printf("\n\nSample SSO using C\n\n"); /* Allocate a new buffer. Automatically zeros it. */ buffer = uxpba_newHandle(); /* Set up log file and initialize library. Must do this before any active calls. */ uxpsys_initLibrary(buffer, argc, argv, "sertainty.lic", "SertintyONE", "SampleSsoC", "Sample SSO 2.0.0"); if (uxpba_getSize(buffer)) { printf("Error initializing environment: %s\n", uxpba_getData(buffer)); return 1; } /* Create new UXP Object using new UXP Identity */ appHandle = uxpfile_newHandle(); uxpfile_openNewFile(appHandle, uxpFileSpec, idFileSpec, IdFile, ModifierReplace, 0); checkError(appHandle, "Creating UXP"); /* Create a new virtual file inside the Data */ uxpfile_addVirtualFromFile(appHandle, "data.pdf", dataPdfSpec, -1, -1, ModifierCompress); checkError(appHandle, "Adding data to UXP"); uxpfile_addVirtualFromFile(appHandle, "data2.pdf", dataPdf2Spec, -1, -1, 0); checkError(appHandle, "Adding data to UXP"); /* Now, open the first virtual file and write it out to a temporary file. */ uxpOpenVFHandle fileHandle = uxpfile_openVirtualFile(appHandle, "data.pdf", ModeRead); checkError(appHandle, "Opening virtual file"); printf("Reading data.pdf in loop ... "); FILE *fp = fopen(copy1Spec, "wb"); while (uxpfile_readVirtualFile(appHandle, fileHandle, buffer, 100000)) { len = uxpba_getSize(buffer); fwrite(uxpba_getData(buffer), len, 1, fp); } fclose(fp); uxpfile_closeVirtualFile(appHandle, fileHandle); printf("finished reading data.pdf\n"); /* Compare the extracted file with the copy inside the Data */ if (uxpfile_compareExternalFile(appHandle, "data.pdf", copy1Spec)) printf("Comparison of data.pdf to copy1.pdf: successful\n"); else printf("Comparison of data.pdf to copy1.pdf: failed\n"); /* Close the UXP Object. This will delete the handle as well. */ uxpfile_close(appHandle); printf("Opening ID for SSO session\n\n"); printf("Credentials necessary to initiate SSO session:\n"); printf(" Username = SampleUser@myemail.com\n"); printf(" Challenge 1 = Response 1\n"); printf(" Challenge 2 = Response 2\n"); printf(" ... \n"); printf(" Challenge 10 = Response 10\n\n"); idHandle = uxpid_newHandle(); uxpid_openSessionFromFile(idHandle, idFileSpec, 0, 0); checkError(idHandle, "Opening ID session"); while (status != StatusAuthorized) { status = uxpid_authenticate(idHandle); switch (status) { case StatusAuthorized: printf("\nSSO session authorized\n"); break; case StatusChallenged: cnt = uxpid_getChallengeCount(idHandle); for (i = 0; i < cnt; i++) { uxpChallengeHandle ch = uxpid_getChallenge(idHandle, i); if (!getResponse(ch)) { printf("\nSSO session not authorized\n"); exit(1); } uxpid_addResponse(idHandle, ch); uxpch_freeHandle(ch); } break; case StatusCanceled: printf("SSO session authorization canceled\n"); exit(1); default: printf("\nSSO session not authorized\n"); exit(1); } } /* Reopen the UXP Object ... includes authentication. */ printf("Opening new Data using SSO\n"); uxpid_openUxpFromFile(idHandle, appHandle, uxpFileSpec, ShareReadOnly); checkError(idHandle, "Opening UXP from session"); printf("\nExtracting data.pdf to copy2.pdf\n"); uxpfile_exportVirtualFile(appHandle, "data.pdf", "copy2.pdf", ModifierReplace); checkError(appHandle, "Exporting virtual file"); if (uxpfile_compareExternalFile(appHandle, "data.pdf", copy2Spec)) printf("Comparison of data.pdf to copy2.pdf: successful\n"); else printf("Comparison of data.pdf to copy2.pdf: failed\n"); /* Close up again and free handle */ uxpfile_close(appHandle); checkError(appHandle, "Closing UXP"); /* Close the SSO session */ printf("\nSample SSO session closing\n"); uxpid_closeSession(idHandle); checkError(idHandle, "Closing ID session"); /* Free library and work buffer */ uxpba_freeHandle(buffer); uxpfile_freeHandle(appHandle); uxpid_freeHandle(idHandle); uxpsys_freeCallStatusHandle(callstatus); printf("You successfully authenticated into an Id Session and used it to auto-authenticate into a UXP.\n"); printf("You may try out other advanced samples now.\n"); printf("\nSample finished running\n"); return 0; } /** * Get challenge from the user. * @param ch Challenge handle * @return True if accepted. False if cancelled. */ static int getResponse(uxpChallengeHandle ch) { char value[1000]; char c, *ptr; uxlByteArray *prompt = uxpba_newHandle(); uxpch_getPrompt(ch, prompt); uxpch_startTimer(ch); for (;;) { printf("%s> ", uxpba_getData(prompt)); ptr = value; for (;;) { c = getchar(); if (c == '\n' || c == '\r') break; *ptr++ = c; } *ptr = '\0'; if (!strcmp(value, "Q") || !strcmp(value, "q")) return 0; if (strlen(value) > 0) break; } uxpch_endTimer(ch); uxpch_setValueString(ch, value); uxpba_freeHandle(prompt); return 1; }