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:
Nikos Mavrogiannopoulos
2014-09-24 12:04:28 +02:00
parent 16cde4dc10
commit 365ca267d4
10 changed files with 53 additions and 24 deletions

View File

@@ -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;

View File

@@ -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;
}
/*

View File

@@ -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);

View File

@@ -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.
#

View File

@@ -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) {

View File

@@ -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_ */

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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];