mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 00:37:00 +08:00
added new authentication mode optional-certificate
That mode allows having only specific group of users that are required to present a certificate.
This commit is contained in:
@@ -389,6 +389,8 @@ unsigned force_cert_auth;
|
||||
config->auth_types |= AUTH_TYPE_PLAIN;
|
||||
} else if (c_strcasecmp(auth[j], "certificate") == 0) {
|
||||
config->auth_types |= AUTH_TYPE_CERTIFICATE;
|
||||
} else if (c_strcasecmp(auth[j], "optional-certificate") == 0) {
|
||||
config->auth_types |= AUTH_TYPE_CERTIFICATE_OPT;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown auth method: %s\n", auth[j]);
|
||||
exit(1);
|
||||
@@ -652,7 +654,7 @@ static void check_cfg(struct cfg_st *config)
|
||||
}
|
||||
|
||||
if (config->auth_types & AUTH_TYPE_CERTIFICATE) {
|
||||
if (config->cisco_client_compat == 0)
|
||||
if (config->cisco_client_compat == 0 && ((config->auth_types & AUTH_TYPE_CERTIFICATE_OPT) != AUTH_TYPE_CERTIFICATE_OPT))
|
||||
config->cert_req = GNUTLS_CERT_REQUIRE;
|
||||
else
|
||||
config->cert_req = GNUTLS_CERT_REQUEST;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* main worker
|
||||
* <------ AUTH_COOKIE_REQ
|
||||
* AUTH_REP(OK/FAILED) ------>
|
||||
* +user config
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -17,7 +18,6 @@ enum AUTH_REP {
|
||||
message auth_cookie_request_msg
|
||||
{
|
||||
required bytes cookie = 1;
|
||||
required bool tls_auth_ok = 2 [default = false];
|
||||
}
|
||||
|
||||
/* AUTH_REP */
|
||||
@@ -127,7 +127,6 @@ message session_info_msg
|
||||
/* SEC_AUTH_INIT */
|
||||
message sec_auth_init_msg
|
||||
{
|
||||
required bool user_present = 1;
|
||||
required bool tls_auth_ok = 2 [default = false];
|
||||
required string user_name = 3;
|
||||
optional string group_name = 4; /* selected group name */
|
||||
@@ -174,6 +173,7 @@ message cookie
|
||||
required uint32 expiration = 6;
|
||||
required uint32 ipv4_seed = 7;
|
||||
required bytes sid = 8;
|
||||
required bool tls_auth_ok = 9;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -265,6 +265,12 @@ struct cookie_entry_st *old;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (proc->config.require_cert != 0 && cmsg->tls_auth_ok == 0) {
|
||||
mslog(s, proc, LOG_ERR,
|
||||
"certificate is required for user '%s'", proc->username);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cmsg->groupname)
|
||||
snprintf(proc->groupname, sizeof(proc->groupname), "%s", cmsg->groupname);
|
||||
|
||||
|
||||
@@ -75,8 +75,10 @@ An example configuration file follows.
|
||||
|
||||
# User authentication method. Could be set multiple times and in
|
||||
# that case all should succeed. To enable multiple methods use
|
||||
# multiple auth directives. Available options: certificate, plain, pam.
|
||||
# multiple auth directives. Available options: certificate, optional-certificate,
|
||||
# plain, pam.
|
||||
#auth = "certificate"
|
||||
#auth = "optional-certificate"
|
||||
#auth = "pam"
|
||||
|
||||
# The gid-min option is used by auto-select-group option, in order to
|
||||
@@ -397,7 +399,7 @@ route = 192.168.5.0/255.255.255.0
|
||||
# or the groupname.
|
||||
# The options allowed in the configuration files are dns, nbns,
|
||||
# ipv?-network, ipv4-netmask, ipv6-prefix, rx/tx-per-sec, iroute, route,
|
||||
# net-priority, deny-roaming, no-udp, user-profile, and cgroup.
|
||||
# net-priority, deny-roaming, no-udp, user-profile, require-cert, and cgroup.
|
||||
#
|
||||
# Note that the 'iroute' option allows to add routes on the server
|
||||
# based on a user or group. The syntax depends on the input accepted
|
||||
@@ -413,6 +415,11 @@ route = 192.168.5.0/255.255.255.0
|
||||
#default-user-config = /etc/ocserv/defaults/user.conf
|
||||
#default-group-config = /etc/ocserv/defaults/group.conf
|
||||
|
||||
# This option is only valid in a user/group configuration file. If the
|
||||
# auth mode is optional-certificate, it requires a certificate for this
|
||||
# particular user or group.
|
||||
#require-cert = true
|
||||
|
||||
# The system command to use to setup a route. %{R} will be replaced with the
|
||||
# route/mask and %{D} with the (tun) device.
|
||||
#
|
||||
|
||||
@@ -83,6 +83,7 @@ static int generate_cookie(sec_mod_st * sec, client_entry_st * entry)
|
||||
msg.groupname = entry->groupname;
|
||||
msg.hostname = entry->hostname;
|
||||
msg.ip = entry->ip;
|
||||
msg.tls_auth_ok = entry->tls_auth_ok;
|
||||
|
||||
/* Fixme: possibly we should allow for completely random seeds */
|
||||
if (sec->config->predictable_ips != 0) {
|
||||
@@ -200,14 +201,21 @@ static int check_user_group_status(sec_mod_st * sec, client_entry_st * e,
|
||||
unsigned cert_groups_size)
|
||||
{
|
||||
unsigned found, i;
|
||||
unsigned need_cert = 1;
|
||||
|
||||
|
||||
if (sec->config->auth_types & AUTH_TYPE_CERTIFICATE) {
|
||||
if (tls_auth_ok == 0) {
|
||||
if ((sec->config->auth_types & AUTH_TYPE_CERTIFICATE_OPT) == AUTH_TYPE_CERTIFICATE_OPT) {
|
||||
need_cert = 0;
|
||||
}
|
||||
|
||||
if (tls_auth_ok == 0 && need_cert != 0) {
|
||||
seclog(LOG_INFO, "user '%s' presented no certificate",
|
||||
e->username);
|
||||
return -1;
|
||||
}
|
||||
|
||||
e->tls_auth_ok = tls_auth_ok;
|
||||
if (tls_auth_ok != 0) {
|
||||
if (e->username[0] == 0 && sec->config->cert_user_oid != NULL) {
|
||||
if (cert_user == NULL) {
|
||||
|
||||
@@ -46,6 +46,7 @@ typedef struct client_entry_st {
|
||||
uint8_t sid[SID_SIZE];
|
||||
void * auth_ctx; /* the context of authentication */
|
||||
unsigned have_session; /* whether an auth session is initialized */
|
||||
unsigned tls_auth_ok;
|
||||
|
||||
unsigned status; /* PS_AUTH_ */
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ struct cfg_options {
|
||||
static struct cfg_options available_options[] = {
|
||||
{ .name = "no-udp", .type = OPTION_BOOLEAN },
|
||||
{ .name = "deny-roaming", .type = OPTION_BOOLEAN },
|
||||
{ .name = "require-cert", .type = OPTION_BOOLEAN },
|
||||
{ .name = "route", .type = OPTION_MULTI_LINE },
|
||||
{ .name = "iroute", .type = OPTION_MULTI_LINE },
|
||||
{ .name = "dns", .type = OPTION_MULTI_LINE },
|
||||
@@ -172,6 +173,7 @@ struct group_cfg_st *sconfig = &proc->config;
|
||||
|
||||
READ_TF("no-udp", sconfig->no_udp, (global_config->udp_port!=0)?0:1);
|
||||
READ_TF("deny-roaming", sconfig->deny_roaming, global_config->deny_roaming);
|
||||
READ_TF("require-cert", sconfig->require_cert, 0);
|
||||
|
||||
READ_RAW_MULTI_LINE("route", sconfig->routes, sconfig->routes_size);
|
||||
READ_RAW_MULTI_LINE("iroute", sconfig->iroutes, sconfig->iroutes_size);
|
||||
|
||||
@@ -73,8 +73,9 @@ extern int syslog_open;
|
||||
/* the first is generic, for the methods that require a username password */
|
||||
#define AUTH_TYPE_USERNAME_PASS (1<<0)
|
||||
#define AUTH_TYPE_PAM (1<<1 | AUTH_TYPE_USERNAME_PASS)
|
||||
#define AUTH_TYPE_CERTIFICATE (1<<2)
|
||||
#define AUTH_TYPE_PLAIN (1<<3 | AUTH_TYPE_USERNAME_PASS)
|
||||
#define AUTH_TYPE_PLAIN (1<<2 | AUTH_TYPE_USERNAME_PASS)
|
||||
#define AUTH_TYPE_CERTIFICATE (1<<3)
|
||||
#define AUTH_TYPE_CERTIFICATE_OPT (1<<4|AUTH_TYPE_CERTIFICATE)
|
||||
|
||||
#define ERR_SUCCESS 0
|
||||
#define ERR_BAD_COMMAND -2
|
||||
@@ -157,6 +158,7 @@ struct group_cfg_st {
|
||||
unsigned deny_roaming; /* whether the user is allowed to re-use cookies from another IP */
|
||||
unsigned net_priority;
|
||||
unsigned no_udp; /* whether to disable UDP for this user */
|
||||
unsigned require_cert; /* when optional certificate auth is selected require a certificate */
|
||||
};
|
||||
|
||||
struct vpn_st {
|
||||
|
||||
@@ -805,19 +805,19 @@ int auth_cookie(worker_st * ws, void *cookie, size_t cookie_size)
|
||||
|
||||
if ((ws->config->auth_types & AUTH_TYPE_CERTIFICATE)
|
||||
&& ws->config->cisco_client_compat == 0) {
|
||||
if (ws->cert_auth_ok == 0) {
|
||||
if (((ws->config->auth_types & AUTH_TYPE_CERTIFICATE_OPT) != AUTH_TYPE_CERTIFICATE_OPT && ws->cert_auth_ok == 0)) {
|
||||
oclog(ws, LOG_INFO,
|
||||
"no certificate provided for cookie authentication");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = get_cert_info(ws);
|
||||
if (ret < 0) {
|
||||
oclog(ws, LOG_INFO, "cannot obtain certificate info");
|
||||
return -1;
|
||||
if (ws->cert_auth_ok != 0) {
|
||||
ret = get_cert_info(ws);
|
||||
if (ret < 0) {
|
||||
oclog(ws, LOG_INFO, "cannot obtain certificate info");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
msg.tls_auth_ok = 1;
|
||||
}
|
||||
|
||||
msg.cookie.data = cookie;
|
||||
@@ -1128,19 +1128,21 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
|
||||
}
|
||||
|
||||
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE) {
|
||||
if (ws->cert_auth_ok == 0) {
|
||||
if ((ws->config->auth_types & AUTH_TYPE_CERTIFICATE_OPT) != AUTH_TYPE_CERTIFICATE_OPT && ws->cert_auth_ok == 0) {
|
||||
reason = MSG_NO_CERT_ERROR;
|
||||
oclog(ws, LOG_INFO,
|
||||
"no certificate provided for authentication");
|
||||
goto auth_fail;
|
||||
}
|
||||
|
||||
ret = get_cert_info(ws);
|
||||
if (ret < 0) {
|
||||
reason = MSG_CERT_READ_ERROR;
|
||||
oclog(ws, LOG_ERR,
|
||||
"failed reading certificate info");
|
||||
goto auth_fail;
|
||||
if (ws->cert_auth_ok != 0) {
|
||||
ret = get_cert_info(ws);
|
||||
if (ret < 0) {
|
||||
reason = MSG_CERT_READ_ERROR;
|
||||
oclog(ws, LOG_ERR,
|
||||
"failed reading certificate info");
|
||||
goto auth_fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (def_group == 0 && ws->cert_groups_size > 0 && ws->groupname[0] == 0) {
|
||||
@@ -1148,7 +1150,7 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
|
||||
return get_auth_handler2(ws, http_ver, "Please select your group");
|
||||
}
|
||||
|
||||
ireq.tls_auth_ok = 1;
|
||||
ireq.tls_auth_ok = ws->cert_auth_ok;
|
||||
ireq.cert_user_name = ws->cert_username;
|
||||
ireq.cert_group_names = ws->cert_groups;
|
||||
ireq.n_cert_group_names = ws->cert_groups_size;
|
||||
|
||||
@@ -197,7 +197,6 @@ typedef struct worker_st {
|
||||
|
||||
/* the following are set only if authentication is complete */
|
||||
|
||||
|
||||
char username[MAX_USERNAME_SIZE];
|
||||
char groupname[MAX_GROUPNAME_SIZE];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user