forked from Telodendria/Telodendria
Implement flow handling in Uia API.
This commit should fix user interactive authentication for dummy flows, but I still have to implement a few more flows, including passwords and refresh token. I also have to fix the cleanup logic: when do we purge UIA sessions?
This commit is contained in:
parent
7703405c70
commit
6ce6cb4525
3 changed files with 153 additions and 25 deletions
36
src/Db.c
36
src/Db.c
|
@ -32,6 +32,9 @@
|
|||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
struct Db
|
||||
{
|
||||
char *dir;
|
||||
|
@ -403,6 +406,38 @@ DbLockFromArr(Db * db, Array * args)
|
|||
fp = fopen(file, "r+");
|
||||
if (!fp)
|
||||
{
|
||||
if (ref)
|
||||
{
|
||||
pthread_mutex_lock(&ref->lock);
|
||||
|
||||
HashMapDelete(db->cache, hash);
|
||||
JsonFree(ref->json);
|
||||
StringArrayFree(ref->name);
|
||||
|
||||
db->cacheSize -= ref->size;
|
||||
|
||||
if (ref->next)
|
||||
{
|
||||
ref->next->prev = ref->prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
db->mostRecent = ref->prev;
|
||||
}
|
||||
|
||||
if (ref->prev)
|
||||
{
|
||||
ref->prev->next = ref->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
db->leastRecent = ref->next;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&ref->lock);
|
||||
pthread_mutex_destroy(&ref->lock);
|
||||
Free(ref);
|
||||
}
|
||||
ref = NULL;
|
||||
goto finish;
|
||||
}
|
||||
|
@ -415,6 +450,7 @@ DbLockFromArr(Db * db, Array * args)
|
|||
/* Lock the file on the disk */
|
||||
if (fcntl(fileno(fp), F_SETLK, &lock) < 0)
|
||||
{
|
||||
printf("fcntl() failed on %s (%s)\n", file, strerror(errno));
|
||||
fclose(fp);
|
||||
ref = NULL;
|
||||
goto finish;
|
||||
|
|
140
src/Uia.c
140
src/Uia.c
|
@ -101,9 +101,8 @@ BuildFlows(Array * flows)
|
|||
}
|
||||
|
||||
static int
|
||||
BuildResponse(Array * flows, char *session, Db * db, HashMap ** response)
|
||||
BuildResponse(Array * flows, Db * db, HashMap ** response, char *session, DbRef * ref)
|
||||
{
|
||||
DbRef *ref;
|
||||
HashMap *json;
|
||||
|
||||
*response = BuildFlows(flows);
|
||||
|
@ -135,8 +134,6 @@ BuildResponse(Array * flows, char *session, Db * db, HashMap ** response)
|
|||
DbUnlock(db, ref);
|
||||
|
||||
HashMapSet(*response, "completed", JsonValueArray(ArrayCreate()));
|
||||
HashMapSet(*response, "session", JsonValueString(session));
|
||||
Free(session);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -150,14 +147,6 @@ BuildResponse(Array * flows, char *session, Db * db, HashMap ** response)
|
|||
return -1;
|
||||
}
|
||||
|
||||
ref = DbLock(db, 2, "user_interactive", session);
|
||||
if (!ref)
|
||||
{
|
||||
JsonFree(*response);
|
||||
ArrayFree(completed);
|
||||
return -1;
|
||||
}
|
||||
|
||||
json = DbJson(ref);
|
||||
dbCompleted = JsonValueAsArray(HashMapGet(json, "completed"));
|
||||
|
||||
|
@ -169,11 +158,13 @@ BuildResponse(Array * flows, char *session, Db * db, HashMap ** response)
|
|||
}
|
||||
|
||||
HashMapSet(*response, "completed", JsonValueArray(completed));
|
||||
HashMapSet(*response, "session", JsonValueString(session));
|
||||
|
||||
DbUnlock(db, ref);
|
||||
session = StrDuplicate(session);
|
||||
}
|
||||
|
||||
HashMapSet(*response, "session", JsonValueString(session));
|
||||
Free(session);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -216,9 +207,13 @@ UiaComplete(Array * flows, HttpServerContext * context, Db * db,
|
|||
HashMap *auth;
|
||||
char *session;
|
||||
char *authType;
|
||||
Array *completed;
|
||||
Array *possibleNext;
|
||||
size_t i;
|
||||
|
||||
DbRef *dbRef;
|
||||
HashMap *dbJson;
|
||||
int ret;
|
||||
|
||||
if (!flows)
|
||||
{
|
||||
|
@ -235,7 +230,7 @@ UiaComplete(Array * flows, HttpServerContext * context, Db * db,
|
|||
if (!val)
|
||||
{
|
||||
HttpResponseStatus(context, HTTP_UNAUTHORIZED);
|
||||
return BuildResponse(flows, NULL, db, response);
|
||||
return BuildResponse(flows, db, response, NULL, NULL);
|
||||
}
|
||||
|
||||
if (JsonValueType(val) != JSON_OBJECT)
|
||||
|
@ -256,33 +251,130 @@ UiaComplete(Array * flows, HttpServerContext * context, Db * db,
|
|||
}
|
||||
|
||||
session = JsonValueAsString(val);
|
||||
|
||||
dbRef = DbLock(db, 2, "user_interactive", session);
|
||||
if (!dbRef)
|
||||
{
|
||||
HttpResponseStatus(context, HTTP_UNAUTHORIZED);
|
||||
return BuildResponse(flows, db, response, NULL, NULL);
|
||||
}
|
||||
|
||||
dbJson = DbJson(dbRef);
|
||||
|
||||
completed = JsonValueAsArray(HashMapGet(dbJson, "completed"));
|
||||
possibleNext = ArrayCreate();
|
||||
|
||||
for (i = 0; i < ArraySize(flows); i++)
|
||||
{
|
||||
size_t j;
|
||||
|
||||
Array *stages = ArrayGet(flows, i);
|
||||
|
||||
if (ArraySize(stages) > ArraySize(completed))
|
||||
{
|
||||
UiaStage *stage = ArrayGet(stages, ArraySize(completed));
|
||||
|
||||
ArrayAdd(possibleNext, stage->type);
|
||||
}
|
||||
else if (ArraySize(stages) == ArraySize(completed))
|
||||
{
|
||||
for (j = 0; j < ArraySize(stages); j++)
|
||||
{
|
||||
UiaStage *stage = ArrayGet(stages, j);
|
||||
char *flowStage = stage->type;
|
||||
char *completedStage = JsonValueAsString(ArrayGet(completed, j));
|
||||
|
||||
if (strcmp(flowStage, completedStage) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == ArraySize(stages))
|
||||
{
|
||||
/* Success: completed matches a stage perfectly */
|
||||
ret = 1;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val = HashMapGet(auth, "type");
|
||||
|
||||
if (!val || JsonValueType(val) != JSON_STRING)
|
||||
{
|
||||
HttpResponseStatus(context, HTTP_BAD_REQUEST);
|
||||
*response = MatrixErrorCreate(M_BAD_JSON);
|
||||
return 0;
|
||||
ret = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
authType = JsonValueAsString(val);
|
||||
|
||||
dbRef = DbLock(db, 2, "user_interactive", session);
|
||||
if (!dbRef)
|
||||
for (i = 0; i < ArraySize(possibleNext); i++)
|
||||
{
|
||||
HttpResponseStatus(context, HTTP_UNAUTHORIZED);
|
||||
return BuildResponse(flows, StrDuplicate(session), db, response);
|
||||
char *possible = ArrayGet(possibleNext, i);
|
||||
|
||||
if (strcmp(authType, possible) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dbJson = DbJson(dbRef);
|
||||
if (i == ArraySize(possibleNext))
|
||||
{
|
||||
HttpResponseStatus(context, HTTP_UNAUTHORIZED);
|
||||
ret = BuildResponse(flows, db, response, session, dbRef);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (strcmp(authType, "m.login.dummy") == 0)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
else if (strcmp(authType, "m.login.password") == 0)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
else if (strcmp(authType, "m.login.registration_token") == 0)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
else if (strcmp(authType, "m.login.recaptcha") == 0)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
else if (strcmp(authType, "m.login.sso") == 0)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
else if (strcmp(authType, "m.login.email.identity") == 0)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
else if (strcmp(authType, "m.login.msisdn") == 0)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpResponseStatus(context, HTTP_UNAUTHORIZED);
|
||||
ret = BuildResponse(flows, db, response, session, dbRef);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ArrayAdd(completed, JsonValueString(authType));
|
||||
|
||||
ret = 1;
|
||||
|
||||
finish:
|
||||
ArrayFree(possibleNext);
|
||||
DbUnlock(db, dbRef);
|
||||
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
UiaFlowsFree(Array *flows)
|
||||
UiaFlowsFree(Array * flows)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
|
|
|
@ -44,6 +44,6 @@ extern int
|
|||
UiaComplete(Array *, HttpServerContext *, Db *, HashMap *, HashMap **);
|
||||
|
||||
extern void
|
||||
UiaFlowsFree(Array *);
|
||||
UiaFlowsFree(Array *);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue