db-oauth2.c revision 5e48e30039369053adfc16b93bca0cc9a7ec9f1d
/* Copyright (c) 2017 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "var-expand.h"
#include "env-util.h"
#include "var-expand.h"
#include "settings.h"
#include "oauth2.h"
#include "http-client.h"
#include "iostream-ssl.h"
#include "auth-request.h"
#include "passdb.h"
#include "passdb-template.h"
#include "llist.h"
#include "db-oauth2.h"
#include <stddef.h>
struct passdb_oauth2_settings {
/* tokeninfo endpoint, format https://endpoint/somewhere?token= */
const char *tokeninfo_url;
/* introspection endpoint, format https://endpoint/somewhere */
const char *introspection_url;
/* expected scope, optional */
const char *scope;
/* mode of introspection, one of get, get-auth, post
- get: append token to url
- get-auth: send token with header Authorization: Bearer token
- post: send token=<token> as POST request
*/
const char *introspection_mode;
/* normalization var-expand template for username, defaults to %Lu */
const char *username_format;
/* name of username attribute to lookup, mandatory */
const char *username_attribute;
/* name of account is active attribute, optional */
const char *active_attribute;
/* expected active value for active attribute, optional */
const char *active_value;
/* template to expand into passdb */
const char *pass_attrs;
/* TLS options */
const char *tls_ca_cert_file;
const char *tls_ca_cert_dir;
const char *tls_cert_file;
const char *tls_key_file;
const char *tls_cipher_suite;
/* HTTP rawlog directory */
const char *rawlog_dir;
/* HTTP client options */
unsigned int timeout_msecs;
unsigned int max_idle_time_msecs;
unsigned int max_parallel_connections;
unsigned int max_pipelined_requests;
bool tls_allow_invalid_cert;
bool debug;
/* Should introspection be done even if not necessary */
bool force_introspection;
bool send_auth_headers;
};
struct db_oauth2 {
const char *config_path;
struct passdb_oauth2_settings set;
struct http_client *client;
struct passdb_template *tmpl;
struct oauth2_settings oauth2_set;
struct db_oauth2_request *head;
unsigned int refcount;
};
static struct setting_def setting_defs[] = {
{ 0, NULL, 0 }
};
static struct passdb_oauth2_settings default_oauth2_settings = {
.tokeninfo_url = "",
.introspection_url = "",
.scope = "",
.introspection_mode = "",
.username_format = "%Lu",
.username_attribute = "email",
.active_attribute = "",
.active_value = "",
.pass_attrs = "",
.rawlog_dir = "",
.timeout_msecs = 0,
.max_idle_time_msecs = 60000,
.max_parallel_connections = 1,
.max_pipelined_requests = 1,
.tls_ca_cert_file = NULL,
.tls_ca_cert_dir = NULL,
.tls_cert_file = NULL,
.tls_key_file = NULL,
.tls_cipher_suite = "HIGH:!SSLv2",
};
{
}
{
const char *error;
struct ssl_iostream_settings ssl_set;
struct http_client_settings http_set;
return db;
}
}
}
i_fatal("oauth2: Tokeninfo or introspection URL must be given");
} else {
i_fatal("Invalid value '%s' for introspection mode, must be on auth, get or post",
}
return db;
}
{
}
{
break;
}
}
/* make sure all requests are aborted */
}
static bool
{
unsigned int n,i;
return FALSE;
for(i=1;i<n;i+=2) {
const char *field;
ptr++;
return FALSE;
}
}
}
return FALSE;
if (*req->db->set.active_attribute != '\0' && !auth_fields_exists(req->fields, req->db->set.active_attribute))
return FALSE;
return TRUE;
}
static const char *field_get_default(const char *data)
{
const char *p;
if (p == NULL)
return "";
else {
/* default value given */
return p+1;
}
}
const char **value_r,
const char **error_r ATTR_UNUSED)
{
return 1;
}
{
return value;
}
static const struct var_expand_table *
const char *oauth2_value)
{
struct var_expand_table *table;
unsigned int count = 1;
&count);
return table;
}
static bool
{
/* var=$ expands into var=${oauth2:var} */
const struct var_expand_func_table funcs_table[] = {
{ "oauth2", db_oauth2_var_expand_func_oauth2 },
};
unsigned int i, count;
if (passdb_template_is_empty(tmpl))
return TRUE;
for (i = 0; i < count; i += 2) {
value = "";
else {
str_truncate(dest, 0);
const struct var_expand_table *
return FALSE;
}
}
}
return TRUE;
}
{
const struct oauth2_field *field;
}
}
const char *error)
{
}
}
static bool
{
const char *error;
struct var_expand_table table[] = {
};
const char *username_value =
if (username_value == NULL) {
*error_r = "No username returned";
return FALSE;
}
if (auth_request_var_expand(username_req, req->db->set.username_format, req->auth_request, escape_none, &error) < 0 ||
}
}
static bool
{
if (active_value == NULL ||
*error_r = "User account is not active";
}
}
}
static bool
{
}
if (!found) {
}
}
}
{
enum passdb_result result;
} else {
}
}
static void
struct db_oauth2_request *req)
{
/* fail here */
return;
}
}
{
struct oauth2_request_input input;
}
static void
struct db_oauth2_request *req)
{
/* no point going forward */
db_oauth2_callback(req, passdb_result, FALSE, result->error == NULL ? "Invalid token" : result->error);
return;
}
!db_oauth2_have_all_fields(req))) {
} else {
}
}
{
struct oauth2_request_input input;
} else {
}
}