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:41:31 +02:00
parent 16cde4dc10
commit 365ca267d4
10 changed files with 53 additions and 24 deletions
+3 -1
View File
@@ -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
View File
@@ -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;
} }
/* /*
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+1
View File
@@ -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_ */
+2
View File
@@ -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);
+4 -2
View File
@@ -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
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) 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;
-1
View File
@@ -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];