Skip to content

Commit

Permalink
auth: oauth2 - remove db_oauth2_request.result
Browse files Browse the repository at this point in the history
It's not a persistent state. When it's set, the callback needs to be called.
This way it's more difficult to forget to set it.
  • Loading branch information
sirainen committed Mar 15, 2017
1 parent 01484d2 commit 5e48e30
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 32 deletions.
54 changes: 29 additions & 25 deletions src/auth/db-oauth2.c
Expand Up @@ -356,7 +356,7 @@ db_oauth2_value_get_var_expand_table(struct auth_request *auth_request,

static bool
db_oauth2_template_export(struct db_oauth2_request *req,
const char **error_r)
enum passdb_result *result_r, const char **error_r)
{
/* var=$ expands into var=${oauth2:var} */
const struct var_expand_func_table funcs_table[] = {
Expand Down Expand Up @@ -384,7 +384,7 @@ db_oauth2_template_export(struct db_oauth2_request *req,
auth_fields_find(req->fields, args[i]));
if (var_expand_with_funcs(dest, args[i+1], table, funcs_table,
req, error_r) < 0) {
req->result = PASSDB_RESULT_INTERNAL_FAILURE;
*result_r = PASSDB_RESULT_INTERNAL_FAILURE;
req->failed = TRUE;
return FALSE;
}
Expand All @@ -410,22 +410,24 @@ static void db_oauth2_fields_merge(struct db_oauth2_request *req,
}
}

static void db_oauth2_callback(struct db_oauth2_request *req, bool success,
static void db_oauth2_callback(struct db_oauth2_request *req,
enum passdb_result result, bool success,
const char *error)
{
db_oauth2_lookup_callback_t *callback = req->callback;
req->callback = NULL;

i_assert(req->result == PASSDB_RESULT_OK || (!success && error != NULL));
i_assert(result == PASSDB_RESULT_OK || (!success && error != NULL));

if (callback != NULL) {
DLLIST_REMOVE(&req->db->head, req);
callback(req->db, success, req, error, req->context);
callback(req->db, result, success, req, error, req->context);
}
}

static bool
db_oauth2_validate_username(struct db_oauth2_request *req, const char **error_r)
db_oauth2_validate_username(struct db_oauth2_request *req,
enum passdb_result *result_r, const char **error_r)
{
const char *error;
struct var_expand_table table[] = {
Expand All @@ -438,7 +440,7 @@ db_oauth2_validate_username(struct db_oauth2_request *req, const char **error_r)
auth_fields_find(req->fields, req->db->set.username_attribute);

if (username_value == NULL) {
req->result = PASSDB_RESULT_INTERNAL_FAILURE;
*result_r = PASSDB_RESULT_INTERNAL_FAILURE;
req->failed = TRUE;
*error_r = "No username returned";
return FALSE;
Expand All @@ -455,36 +457,38 @@ db_oauth2_validate_username(struct db_oauth2_request *req, const char **error_r)
var_expand(username_val, req->db->set.username_format, table, &error) < 0) {
*error_r = t_strdup_printf("var_expand(%s) failed: %s",
req->db->set.username_format, error);
req->result = PASSDB_RESULT_INTERNAL_FAILURE;
*result_r = PASSDB_RESULT_INTERNAL_FAILURE;
req->failed = TRUE;
} else if (!str_equals(username_req, username_val)) {
*error_r = t_strdup_printf("Username '%s' did not match '%s'",
str_c(username_req), str_c(username_val));
req->result = PASSDB_RESULT_USER_UNKNOWN;
*result_r = PASSDB_RESULT_USER_UNKNOWN;
req->failed = TRUE;
}

return !req->failed;
}

static bool
db_oauth2_user_is_enabled(struct db_oauth2_request *req, const char **error_r)
db_oauth2_user_is_enabled(struct db_oauth2_request *req,
enum passdb_result *result_r, const char **error_r)
{
if (*req->db->set.active_attribute != '\0') {
const char *active_value = auth_fields_find(req->fields, req->db->set.active_attribute);
if (active_value == NULL ||
(*req->db->set.active_value != '\0' &&
strcmp(req->db->set.active_value, active_value) != 0)) {
*error_r = "User account is not active";
req->result = PASSDB_RESULT_USER_DISABLED;
*result_r = PASSDB_RESULT_USER_DISABLED;
req->failed = TRUE;
}
}
return !req->failed;
}

static bool
db_oauth2_token_in_scope(struct db_oauth2_request *req, const char **error_r)
db_oauth2_token_in_scope(struct db_oauth2_request *req,
enum passdb_result *result_r, const char **error_r)
{
if (*req->db->set.scope != '\0') {
bool found = FALSE;
Expand All @@ -496,7 +500,7 @@ db_oauth2_token_in_scope(struct db_oauth2_request *req, const char **error_r)
if (!found) {
*error_r = t_strdup_printf("Token is not valid for scope '%s'",
req->db->set.scope);
req->result = PASSDB_RESULT_USER_DISABLED;
*result_r = PASSDB_RESULT_USER_DISABLED;
req->failed = TRUE;
}
}
Expand All @@ -505,18 +509,19 @@ db_oauth2_token_in_scope(struct db_oauth2_request *req, const char **error_r)

static void db_oauth2_process_fields(struct db_oauth2_request *req)
{
enum passdb_result result;
const char *error = NULL;
if (db_oauth2_validate_username(req, &error) &&
db_oauth2_user_is_enabled(req, &error) &&
db_oauth2_token_in_scope(req, &error) &&
db_oauth2_template_export(req, &error) &&
if (db_oauth2_validate_username(req, &result, &error) &&
db_oauth2_user_is_enabled(req, &result, &error) &&
db_oauth2_token_in_scope(req, &result, &error) &&
db_oauth2_template_export(req, &result, &error) &&
!req->failed) {
req->result = PASSDB_RESULT_OK;
result = PASSDB_RESULT_OK;
} else {
i_assert(req->result != PASSDB_RESULT_OK && error != NULL);
i_assert(result != PASSDB_RESULT_OK && error != NULL);
}

db_oauth2_callback(req, !req->failed, error);
db_oauth2_callback(req, result, !req->failed, error);
}

static void
Expand All @@ -527,9 +532,8 @@ db_oauth2_introspect_continue(struct oauth2_introspection_result *result,

if (!result->success) {
/* fail here */
req->result = PASSDB_RESULT_INTERNAL_FAILURE;
req->failed = TRUE;
db_oauth2_callback(req, FALSE, result->error);
db_oauth2_callback(req, PASSDB_RESULT_INTERNAL_FAILURE, FALSE, result->error);
return;
}
db_oauth2_fields_merge(req, result->fields);
Expand Down Expand Up @@ -564,11 +568,11 @@ db_oauth2_lookup_continue(struct oauth2_token_validation_result *result,

if (!result->success || !result->valid) {
/* no point going forward */
req->result = result->success ?
enum passdb_result passdb_result = result->success ?
PASSDB_RESULT_PASSWORD_MISMATCH :
PASSDB_RESULT_INTERNAL_FAILURE,
PASSDB_RESULT_INTERNAL_FAILURE;
req->failed = TRUE;
db_oauth2_callback(req, FALSE, result->error == NULL ? "Invalid token" : result->error);
db_oauth2_callback(req, passdb_result, FALSE, result->error == NULL ? "Invalid token" : result->error);
return;
}

Expand Down
7 changes: 4 additions & 3 deletions src/auth/db-oauth2.h
Expand Up @@ -5,7 +5,9 @@ struct db_oauth2;
struct oauth2_request;
struct db_oauth2_request;

typedef void db_oauth2_lookup_callback_t(struct db_oauth2 *db, bool success,
typedef void db_oauth2_lookup_callback_t(struct db_oauth2 *db,
enum passdb_result result,
bool success,
struct db_oauth2_request *request,
const char *error,
void *context);
Expand All @@ -28,7 +30,6 @@ struct db_oauth2_request {
void *context;
verify_plain_callback_t *verify_callback;

enum passdb_result result;
bool failed:1;
};

Expand All @@ -41,7 +42,7 @@ void db_oauth2_unref(struct db_oauth2 **);
void db_oauth2_lookup(struct db_oauth2 *db, struct db_oauth2_request *req, const char *token, struct auth_request *request, db_oauth2_lookup_callback_t *callback, void *context);
#define db_oauth2_lookup(db, req, token, request, callback, context) \
db_oauth2_lookup(db, req, token + \
CALLBACK_TYPECHECK(callback, void(*)(struct db_oauth2*, bool, struct db_oauth2_request *req, const char*, typeof(context))), \
CALLBACK_TYPECHECK(callback, void(*)(struct db_oauth2*, enum passdb_result, bool, struct db_oauth2_request *req, const char*, typeof(context))), \
request, (db_oauth2_lookup_callback_t*)callback, (void*)context)

#endif
9 changes: 5 additions & 4 deletions src/auth/passdb-oauth2.c
Expand Up @@ -10,18 +10,19 @@ struct oauth2_passdb_module {
};

static void
oauth2_verify_plain_continue(struct db_oauth2 *db ATTR_UNUSED, bool success,
oauth2_verify_plain_continue(struct db_oauth2 *db ATTR_UNUSED,
enum passdb_result result, bool success,
struct db_oauth2_request *req, const char *error,
struct auth_request *request)
{
i_assert(success || req->result != PASSDB_RESULT_OK);
if (!success && req->result == PASSDB_RESULT_INTERNAL_FAILURE)
i_assert(success || result != PASSDB_RESULT_OK);
if (!success && result == PASSDB_RESULT_INTERNAL_FAILURE)
auth_request_log_error(request, AUTH_SUBSYS_DB, "oauth2 failed: %s",
error);
else if (!success)
auth_request_log_info(request, AUTH_SUBSYS_DB, "oauth2 failed: %s",
error);
req->verify_callback(req->result, request);
req->verify_callback(result, request);
auth_request_unref(&request);
}

Expand Down

0 comments on commit 5e48e30

Please sign in to comment.