mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-10-14 02:22:03 +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:
+3
-1
@@ -389,6 +389,8 @@ unsigned force_cert_auth;
|
|||||||
config->auth_types |= AUTH_TYPE_PLAIN;
|
config->auth_types |= AUTH_TYPE_PLAIN;
|
||||||
} else if (c_strcasecmp(auth[j], "certificate") == 0) {
|
} else if (c_strcasecmp(auth[j], "certificate") == 0) {
|
||||||
config->auth_types |= AUTH_TYPE_CERTIFICATE;
|
config->auth_types |= AUTH_TYPE_CERTIFICATE;
|
||||||
|
} else if (c_strcasecmp(auth[j], "optional-certificate") == 0) {
|
||||||
|
config->auth_types |= AUTH_TYPE_CERTIFICATE_OPT;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unknown auth method: %s\n", auth[j]);
|
fprintf(stderr, "Unknown auth method: %s\n", auth[j]);
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -652,7 +654,7 @@ static void check_cfg(struct cfg_st *config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config->auth_types & AUTH_TYPE_CERTIFICATE) {
|
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;
|
config->cert_req = GNUTLS_CERT_REQUIRE;
|
||||||
else
|
else
|
||||||
config->cert_req = GNUTLS_CERT_REQUEST;
|
config->cert_req = GNUTLS_CERT_REQUEST;
|
||||||
|
|||||||
+2
-2
@@ -4,6 +4,7 @@
|
|||||||
* main worker
|
* main worker
|
||||||
* <------ AUTH_COOKIE_REQ
|
* <------ AUTH_COOKIE_REQ
|
||||||
* AUTH_REP(OK/FAILED) ------>
|
* AUTH_REP(OK/FAILED) ------>
|
||||||
|
* +user config
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -17,7 +18,6 @@ enum AUTH_REP {
|
|||||||
message auth_cookie_request_msg
|
message auth_cookie_request_msg
|
||||||
{
|
{
|
||||||
required bytes cookie = 1;
|
required bytes cookie = 1;
|
||||||
required bool tls_auth_ok = 2 [default = false];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AUTH_REP */
|
/* AUTH_REP */
|
||||||
@@ -127,7 +127,6 @@ message session_info_msg
|
|||||||
/* SEC_AUTH_INIT */
|
/* SEC_AUTH_INIT */
|
||||||
message sec_auth_init_msg
|
message sec_auth_init_msg
|
||||||
{
|
{
|
||||||
required bool user_present = 1;
|
|
||||||
required bool tls_auth_ok = 2 [default = false];
|
required bool tls_auth_ok = 2 [default = false];
|
||||||
required string user_name = 3;
|
required string user_name = 3;
|
||||||
optional string group_name = 4; /* selected group name */
|
optional string group_name = 4; /* selected group name */
|
||||||
@@ -174,6 +173,7 @@ message cookie
|
|||||||
required uint32 expiration = 6;
|
required uint32 expiration = 6;
|
||||||
required uint32 ipv4_seed = 7;
|
required uint32 ipv4_seed = 7;
|
||||||
required bytes sid = 8;
|
required bytes sid = 8;
|
||||||
|
required bool tls_auth_ok = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -265,6 +265,12 @@ struct cookie_entry_st *old;
|
|||||||
return -1;
|
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)
|
if (cmsg->groupname)
|
||||||
snprintf(proc->groupname, sizeof(proc->groupname), "%s", cmsg->groupname);
|
snprintf(proc->groupname, sizeof(proc->groupname), "%s", cmsg->groupname);
|
||||||
|
|
||||||
|
|||||||
+9
-2
@@ -75,8 +75,10 @@ An example configuration file follows.
|
|||||||
|
|
||||||
# User authentication method. Could be set multiple times and in
|
# User authentication method. Could be set multiple times and in
|
||||||
# that case all should succeed. To enable multiple methods use
|
# 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 = "certificate"
|
||||||
|
#auth = "optional-certificate"
|
||||||
#auth = "pam"
|
#auth = "pam"
|
||||||
|
|
||||||
# The gid-min option is used by auto-select-group option, in order to
|
# 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.
|
# or the groupname.
|
||||||
# The options allowed in the configuration files are dns, nbns,
|
# The options allowed in the configuration files are dns, nbns,
|
||||||
# ipv?-network, ipv4-netmask, ipv6-prefix, rx/tx-per-sec, iroute, route,
|
# 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
|
# 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
|
# 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-user-config = /etc/ocserv/defaults/user.conf
|
||||||
#default-group-config = /etc/ocserv/defaults/group.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
|
# The system command to use to setup a route. %{R} will be replaced with the
|
||||||
# route/mask and %{D} with the (tun) device.
|
# route/mask and %{D} with the (tun) device.
|
||||||
#
|
#
|
||||||
|
|||||||
+9
-1
@@ -83,6 +83,7 @@ static int generate_cookie(sec_mod_st * sec, client_entry_st * entry)
|
|||||||
msg.groupname = entry->groupname;
|
msg.groupname = entry->groupname;
|
||||||
msg.hostname = entry->hostname;
|
msg.hostname = entry->hostname;
|
||||||
msg.ip = entry->ip;
|
msg.ip = entry->ip;
|
||||||
|
msg.tls_auth_ok = entry->tls_auth_ok;
|
||||||
|
|
||||||
/* Fixme: possibly we should allow for completely random seeds */
|
/* Fixme: possibly we should allow for completely random seeds */
|
||||||
if (sec->config->predictable_ips != 0) {
|
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 cert_groups_size)
|
||||||
{
|
{
|
||||||
unsigned found, i;
|
unsigned found, i;
|
||||||
|
unsigned need_cert = 1;
|
||||||
|
|
||||||
|
|
||||||
if (sec->config->auth_types & AUTH_TYPE_CERTIFICATE) {
|
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",
|
seclog(LOG_INFO, "user '%s' presented no certificate",
|
||||||
e->username);
|
e->username);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e->tls_auth_ok = tls_auth_ok;
|
||||||
if (tls_auth_ok != 0) {
|
if (tls_auth_ok != 0) {
|
||||||
if (e->username[0] == 0 && sec->config->cert_user_oid != NULL) {
|
if (e->username[0] == 0 && sec->config->cert_user_oid != NULL) {
|
||||||
if (cert_user == NULL) {
|
if (cert_user == NULL) {
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ typedef struct client_entry_st {
|
|||||||
uint8_t sid[SID_SIZE];
|
uint8_t sid[SID_SIZE];
|
||||||
void * auth_ctx; /* the context of authentication */
|
void * auth_ctx; /* the context of authentication */
|
||||||
unsigned have_session; /* whether an auth session is initialized */
|
unsigned have_session; /* whether an auth session is initialized */
|
||||||
|
unsigned tls_auth_ok;
|
||||||
|
|
||||||
unsigned status; /* PS_AUTH_ */
|
unsigned status; /* PS_AUTH_ */
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ struct cfg_options {
|
|||||||
static struct cfg_options available_options[] = {
|
static struct cfg_options available_options[] = {
|
||||||
{ .name = "no-udp", .type = OPTION_BOOLEAN },
|
{ .name = "no-udp", .type = OPTION_BOOLEAN },
|
||||||
{ .name = "deny-roaming", .type = OPTION_BOOLEAN },
|
{ .name = "deny-roaming", .type = OPTION_BOOLEAN },
|
||||||
|
{ .name = "require-cert", .type = OPTION_BOOLEAN },
|
||||||
{ .name = "route", .type = OPTION_MULTI_LINE },
|
{ .name = "route", .type = OPTION_MULTI_LINE },
|
||||||
{ .name = "iroute", .type = OPTION_MULTI_LINE },
|
{ .name = "iroute", .type = OPTION_MULTI_LINE },
|
||||||
{ .name = "dns", .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("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("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("route", sconfig->routes, sconfig->routes_size);
|
||||||
READ_RAW_MULTI_LINE("iroute", sconfig->iroutes, sconfig->iroutes_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 */
|
/* the first is generic, for the methods that require a username password */
|
||||||
#define AUTH_TYPE_USERNAME_PASS (1<<0)
|
#define AUTH_TYPE_USERNAME_PASS (1<<0)
|
||||||
#define AUTH_TYPE_PAM (1<<1 | AUTH_TYPE_USERNAME_PASS)
|
#define AUTH_TYPE_PAM (1<<1 | AUTH_TYPE_USERNAME_PASS)
|
||||||
#define AUTH_TYPE_CERTIFICATE (1<<2)
|
#define AUTH_TYPE_PLAIN (1<<2 | AUTH_TYPE_USERNAME_PASS)
|
||||||
#define AUTH_TYPE_PLAIN (1<<3 | 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_SUCCESS 0
|
||||||
#define ERR_BAD_COMMAND -2
|
#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 deny_roaming; /* whether the user is allowed to re-use cookies from another IP */
|
||||||
unsigned net_priority;
|
unsigned net_priority;
|
||||||
unsigned no_udp; /* whether to disable UDP for this user */
|
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 {
|
struct vpn_st {
|
||||||
|
|||||||
+17
-15
@@ -805,19 +805,19 @@ int auth_cookie(worker_st * ws, void *cookie, size_t cookie_size)
|
|||||||
|
|
||||||
if ((ws->config->auth_types & AUTH_TYPE_CERTIFICATE)
|
if ((ws->config->auth_types & AUTH_TYPE_CERTIFICATE)
|
||||||
&& ws->config->cisco_client_compat == 0) {
|
&& 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,
|
oclog(ws, LOG_INFO,
|
||||||
"no certificate provided for cookie authentication");
|
"no certificate provided for cookie authentication");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = get_cert_info(ws);
|
if (ws->cert_auth_ok != 0) {
|
||||||
if (ret < 0) {
|
ret = get_cert_info(ws);
|
||||||
oclog(ws, LOG_INFO, "cannot obtain certificate info");
|
if (ret < 0) {
|
||||||
return -1;
|
oclog(ws, LOG_INFO, "cannot obtain certificate info");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.tls_auth_ok = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.cookie.data = cookie;
|
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->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;
|
reason = MSG_NO_CERT_ERROR;
|
||||||
oclog(ws, LOG_INFO,
|
oclog(ws, LOG_INFO,
|
||||||
"no certificate provided for authentication");
|
"no certificate provided for authentication");
|
||||||
goto auth_fail;
|
goto auth_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = get_cert_info(ws);
|
if (ws->cert_auth_ok != 0) {
|
||||||
if (ret < 0) {
|
ret = get_cert_info(ws);
|
||||||
reason = MSG_CERT_READ_ERROR;
|
if (ret < 0) {
|
||||||
oclog(ws, LOG_ERR,
|
reason = MSG_CERT_READ_ERROR;
|
||||||
"failed reading certificate info");
|
oclog(ws, LOG_ERR,
|
||||||
goto auth_fail;
|
"failed reading certificate info");
|
||||||
|
goto auth_fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def_group == 0 && ws->cert_groups_size > 0 && ws->groupname[0] == 0) {
|
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");
|
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_user_name = ws->cert_username;
|
||||||
ireq.cert_group_names = ws->cert_groups;
|
ireq.cert_group_names = ws->cert_groups;
|
||||||
ireq.n_cert_group_names = ws->cert_groups_size;
|
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 */
|
/* the following are set only if authentication is complete */
|
||||||
|
|
||||||
|
|
||||||
char username[MAX_USERNAME_SIZE];
|
char username[MAX_USERNAME_SIZE];
|
||||||
char groupname[MAX_GROUPNAME_SIZE];
|
char groupname[MAX_GROUPNAME_SIZE];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user