working on multi-tenant server based upon oauth

This commit is contained in:
Oleg Moskalenko 2015-09-14 00:16:13 -07:00
parent a8ba79ff60
commit dbc9dee42b
24 changed files with 124 additions and 74 deletions

View File

@ -1,6 +1,7 @@
8/26/2015 Oleg Moskalenko <mom040267@gmail.com>
Version 4.4.5.5 'Ardee West':
- STUN attributes conflict resolution.
9/13/2015 Oleg Moskalenko <mom040267@gmail.com>
Version 4.5.0.0 'Ardee West':
- multiple realms based on oAuth (third-party authorization);
- STUN attributes conflict resolution;
- SIGHUP handler fixed.
7/18/2015 Oleg Moskalenko <mom040267@gmail.com>

View File

@ -744,6 +744,7 @@ CREATE TABLE oauth_key (
timestamp bigint default 0,
lifetime integer default 0,
as_rs_alg varchar(64) default '',
realm varchar(127) default '',
primary key (kid)
);
@ -764,6 +765,8 @@ The oauth_key table fields meanings are:
http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-5.1).
The default value is "A256GCM";
realm - (optional) can be used to set the user realm (if the field is not empty).
# Https access admin users.
# Leave this table empty if you do not want
# remote https access to the admin functions.

3
STATUS
View File

@ -124,5 +124,8 @@ supported in the client library).
54) native SCTP experimental support.
55) Multi-tenant implementation based upon third-party authorization
(oAuth).
Things to be implemented in future (the development roadmap)
are described in the TODO file.

Binary file not shown.

View File

@ -1,5 +1,5 @@
.\" Text automatically generated by txt2man
.TH TURN 1 "01 September 2015" "" ""
.TH TURN 1 "13 September 2015" "" ""
.SH GENERAL INFORMATION
\fIturnadmin\fP is a TURN administration tool. This tool can be used to manage

View File

@ -1,5 +1,5 @@
.\" Text automatically generated by txt2man
.TH TURN 1 "01 September 2015" "" ""
.TH TURN 1 "13 September 2015" "" ""
.SH GENERAL INFORMATION
The \fBTURN Server\fP project contains the source code of a TURN server and TURN client

View File

@ -1,5 +1,5 @@
.\" Text automatically generated by txt2man
.TH TURN 1 "01 September 2015" "" ""
.TH TURN 1 "13 September 2015" "" ""
.SH GENERAL INFORMATION
A set of turnutils_* programs provides some utility functionality to be used

View File

@ -2,7 +2,7 @@
# Common settings script.
TURNVERSION=4.4.5.5
TURNVERSION=4.5.0.0
BUILDDIR=~/rpmbuild
ARCH=`uname -p`
TURNSERVER_GIT_URL=https://github.com/coturn/coturn.git

View File

@ -1,5 +1,5 @@
Name: turnserver
Version: 4.4.5.5
Version: 4.5.0.0
Release: 0%{dist}
Summary: Coturn TURN Server
@ -289,8 +289,8 @@ fi
%{_includedir}/turn/client/TurnMsgLib.h
%changelog
* Wed Aug 26 2015 Oleg Moskalenko <mom040267@gmail.com>
- Sync to 4.4.5.5
* Sun Sep 13 2015 Oleg Moskalenko <mom040267@gmail.com>
- Sync to 4.5.0.0
* Sat Jul 18 2015 Oleg Moskalenko <mom040267@gmail.com>
- Sync to 4.4.5.4
* Sat Jun 20 2015 Oleg Moskalenko <mom040267@gmail.com>

View File

@ -142,6 +142,7 @@ struct _oauth_key_data_raw {
u64bits timestamp;
u32bits lifetime;
char as_rs_alg[OAUTH_ALG_SIZE+1];
char realm[STUN_MAX_REALM_SIZE+1];
};
typedef struct _oauth_key_data_raw oauth_key_data_raw;

View File

@ -255,6 +255,7 @@ static int mongo_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
BSON_APPEND_INT32(&fields, "lifetime", 1);
BSON_APPEND_INT32(&fields, "timestamp", 1);
BSON_APPEND_INT32(&fields, "as_rs_alg", 1);
BSON_APPEND_INT32(&fields, "realm", 1);
BSON_APPEND_INT32(&fields, "ikm_key", 1);
mongoc_cursor_t * cursor;
@ -277,6 +278,9 @@ static int mongo_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "as_rs_alg") && BSON_ITER_HOLDS_UTF8(&iter)) {
STRCPY(key->as_rs_alg,bson_iter_utf8(&iter, &length));
}
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "realm") && BSON_ITER_HOLDS_UTF8(&iter)) {
STRCPY(key->realm,bson_iter_utf8(&iter, &length));
}
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "ikm_key") && BSON_ITER_HOLDS_UTF8(&iter)) {
STRCPY(key->ikm_key,bson_iter_utf8(&iter, &length));
}
@ -341,6 +345,7 @@ static int mongo_set_oauth_key(oauth_key_data_raw *key) {
bson_init(&doc);
BSON_APPEND_UTF8(&doc, "kid", (const char *)key->kid);
BSON_APPEND_UTF8(&doc, "as_rs_alg", (const char *)key->as_rs_alg);
BSON_APPEND_UTF8(&doc, "realm", (const char *)key->realm);
BSON_APPEND_UTF8(&doc, "ikm_key", (const char *)key->ikm_key);
BSON_APPEND_INT64(&doc, "timestamp", (int64_t)key->timestamp);
BSON_APPEND_INT32(&doc, "lifetime", (int32_t)key->lifetime);
@ -477,7 +482,7 @@ static int mongo_list_users(u08bits *realm, secrets_list_t *users, secrets_list_
return ret;
}
static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts) {
static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms) {
const char * collection_name = "oauth_key";
mongoc_collection_t * collection = mongo_get_collection(collection_name);
@ -501,6 +506,7 @@ static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
BSON_APPEND_INT32(&fields, "lifetime", 1);
BSON_APPEND_INT32(&fields, "timestamp", 1);
BSON_APPEND_INT32(&fields, "as_rs_alg", 1);
BSON_APPEND_INT32(&fields, "realm", 1);
BSON_APPEND_INT32(&fields, "ikm_key", 1);
mongoc_cursor_t * cursor;
@ -525,6 +531,9 @@ static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "as_rs_alg") && BSON_ITER_HOLDS_UTF8(&iter)) {
STRCPY(key->as_rs_alg,bson_iter_utf8(&iter, &length));
}
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "realm") && BSON_ITER_HOLDS_UTF8(&iter)) {
STRCPY(key->realm,bson_iter_utf8(&iter, &length));
}
if (bson_iter_init(&iter, item) && bson_iter_find(&iter, "ikm_key") && BSON_ITER_HOLDS_UTF8(&iter)) {
STRCPY(key->ikm_key,bson_iter_utf8(&iter, &length));
}
@ -537,6 +546,7 @@ static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
if(kids) {
add_to_secrets_list(kids,key->kid);
add_to_secrets_list(teas,key->as_rs_alg);
add_to_secrets_list(realms,key->realm);
{
char ts[256];
snprintf(ts,sizeof(ts)-1,"%llu",(unsigned long long)key->timestamp);
@ -548,9 +558,9 @@ static int mongo_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
add_to_secrets_list(lts,lt);
}
} else {
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s\n",
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s, realm=%s\n",
key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime,
key->as_rs_alg);
key->as_rs_alg, key->realm);
}
}
mongoc_cursor_destroy(cursor);

View File

@ -345,7 +345,7 @@ static int mysql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
int ret = -1;
char statement[TURN_LONG_STRING_SIZE];
/* direct user input eliminated - there is no SQL injection problem (since version 4.4.5.3) */
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg from oauth_key where kid='%s'",(const char*)kid);
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm from oauth_key where kid='%s'",(const char*)kid);
MYSQL * myc = get_mydb_connection();
if(myc) {
@ -356,7 +356,7 @@ static int mysql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
MYSQL_RES *mres = mysql_store_result(myc);
if(!mres) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else if(mysql_field_count(myc)!=4) {
} else if(mysql_field_count(myc)!=5) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
} else {
MYSQL_ROW row = mysql_fetch_row(mres);
@ -380,6 +380,9 @@ static int mysql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
ns_bcopy(row[3],key->as_rs_alg,lengths[3]);
key->as_rs_alg[lengths[3]]=0;
ns_bcopy(row[4],key->realm,lengths[4]);
key->realm[lengths[4]]=0;
ret = 0;
}
}
@ -392,13 +395,13 @@ static int mysql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
return ret;
}
static int mysql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts) {
static int mysql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms) {
oauth_key_data_raw key_;
oauth_key_data_raw *key=&key_;
int ret = -1;
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,kid from oauth_key order by kid");
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm,kid from oauth_key order by kid");
MYSQL * myc = get_mydb_connection();
if(myc) {
@ -409,7 +412,7 @@ static int mysql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
MYSQL_RES *mres = mysql_store_result(myc);
if(!mres) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error retrieving MySQL DB information: %s\n",mysql_error(myc));
} else if(mysql_field_count(myc)!=5) {
} else if(mysql_field_count(myc)!=6) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Unknown error retrieving MySQL DB information: %s\n",statement);
} else {
MYSQL_ROW row = mysql_fetch_row(mres);
@ -433,12 +436,16 @@ static int mysql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
ns_bcopy(row[3],key->as_rs_alg,lengths[3]);
key->as_rs_alg[lengths[3]]=0;
ns_bcopy(row[4],key->kid,lengths[4]);
key->kid[lengths[4]]=0;
ns_bcopy(row[4],key->realm,lengths[4]);
key->realm[lengths[4]]=0;
ns_bcopy(row[5],key->kid,lengths[5]);
key->kid[lengths[5]]=0;
if(kids) {
add_to_secrets_list(kids,key->kid);
add_to_secrets_list(teas,key->as_rs_alg);
add_to_secrets_list(realms,key->realm);
{
char ts[256];
snprintf(ts,sizeof(ts)-1,"%llu",(unsigned long long)key->timestamp);
@ -450,9 +457,9 @@ static int mysql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
add_to_secrets_list(lts,lt);
}
} else {
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s\n",
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s, realm=%s\n",
key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime,
key->as_rs_alg);
key->as_rs_alg,key->realm);
}
}
row = mysql_fetch_row(mres);
@ -496,13 +503,13 @@ static int mysql_set_oauth_key(oauth_key_data_raw *key)
char statement[TURN_LONG_STRING_SIZE];
MYSQL * myc = get_mydb_connection();
if(myc) {
snprintf(statement,sizeof(statement),"insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg) values('%s','%s',%llu,%lu,'%s')",
snprintf(statement,sizeof(statement),"insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('%s','%s',%llu,%lu,'%s','%s')",
key->kid,key->ikm_key,(unsigned long long)key->timestamp,(unsigned long)key->lifetime,
key->as_rs_alg);
key->as_rs_alg,key->realm);
int res = mysql_query(myc, statement);
if(res) {
snprintf(statement,sizeof(statement),"update oauth_key set ikm_key='%s',timestamp=%lu,lifetime=%lu, as_rs_alg='%s' where kid='%s'",key->ikm_key,(unsigned long)key->timestamp,(unsigned long)key->lifetime,
key->as_rs_alg,key->kid);
snprintf(statement,sizeof(statement),"update oauth_key set ikm_key='%s',timestamp=%lu,lifetime=%lu, as_rs_alg='%s', realm='%s' where kid='%s'",key->ikm_key,(unsigned long)key->timestamp,(unsigned long)key->lifetime,
key->as_rs_alg,key->realm,key->kid);
res = mysql_query(myc, statement);
if(res) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating oauth key information: %s\n",mysql_error(myc));

View File

@ -160,7 +160,7 @@ static int pgsql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
char statement[TURN_LONG_STRING_SIZE];
/* direct user input eliminated - there is no SQL injection problem (since version 4.4.5.3) */
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg from oauth_key where kid='%s'",(const char*)kid);
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm from oauth_key where kid='%s'",(const char*)kid);
PGconn * pqc = get_pqdb_connection();
if(pqc) {
@ -173,6 +173,7 @@ static int pgsql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
key->timestamp = (u64bits)strtoll(PQgetvalue(res,0,1),NULL,10);
key->lifetime = (u32bits)strtol(PQgetvalue(res,0,2),NULL,10);
STRCPY(key->as_rs_alg,PQgetvalue(res,0,3));
STRCPY(key->realm,PQgetvalue(res,0,4));
STRCPY(key->kid,kid);
ret = 0;
}
@ -185,7 +186,7 @@ static int pgsql_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
return ret;
}
static int pgsql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts) {
static int pgsql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms) {
oauth_key_data_raw key_;
oauth_key_data_raw *key=&key_;
@ -193,7 +194,7 @@ static int pgsql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
int ret = -1;
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,kid from oauth_key order by kid");
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm,kid from oauth_key order by kid");
PGconn * pqc = get_pqdb_connection();
if(pqc) {
@ -209,11 +210,13 @@ static int pgsql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
key->timestamp = (u64bits)strtoll(PQgetvalue(res,i,1),NULL,10);
key->lifetime = (u32bits)strtol(PQgetvalue(res,i,2),NULL,10);
STRCPY(key->as_rs_alg,PQgetvalue(res,i,3));
STRCPY(key->kid,PQgetvalue(res,i,4));
STRCPY(key->realm,PQgetvalue(res,i,4));
STRCPY(key->kid,PQgetvalue(res,i,5));
if(kids) {
add_to_secrets_list(kids,key->kid);
add_to_secrets_list(teas,key->as_rs_alg);
add_to_secrets_list(realms,key->realm);
{
char ts[256];
snprintf(ts,sizeof(ts)-1,"%llu",(unsigned long long)key->timestamp);
@ -225,9 +228,9 @@ static int pgsql_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
add_to_secrets_list(lts,lt);
}
} else {
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s\n",
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s, realm=%s\n",
key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime,
key->as_rs_alg);
key->as_rs_alg,key->realm);
}
ret = 0;
@ -275,17 +278,17 @@ static int pgsql_set_oauth_key(oauth_key_data_raw *key) {
char statement[TURN_LONG_STRING_SIZE];
PGconn *pqc = get_pqdb_connection();
if(pqc) {
snprintf(statement,sizeof(statement),"insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg) values('%s','%s',%llu,%lu,'%s')",
snprintf(statement,sizeof(statement),"insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('%s','%s',%llu,%lu,'%s','%s')",
key->kid,key->ikm_key,(unsigned long long)key->timestamp,(unsigned long)key->lifetime,
key->as_rs_alg);
key->as_rs_alg,key->realm);
PGresult *res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
if(res) {
PQclear(res);
}
snprintf(statement,sizeof(statement),"update oauth_key set ikm_key='%s',timestamp=%lu,lifetime=%lu, as_rs_alg='%s' where kid='%s'",key->ikm_key,(unsigned long)key->timestamp,(unsigned long)key->lifetime,
key->as_rs_alg,key->kid);
snprintf(statement,sizeof(statement),"update oauth_key set ikm_key='%s',timestamp=%lu,lifetime=%lu, as_rs_alg='%s', realm='%s' where kid='%s'",key->ikm_key,(unsigned long)key->timestamp,(unsigned long)key->lifetime,
key->as_rs_alg,key->realm,key->kid);
res = PQexec(pqc, statement);
if(!res || (PQresultStatus(res) != PGRES_COMMAND_OK)) {
TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Error inserting/updating oauth_key information: %s\n",PQerrorMessage(pqc));

View File

@ -477,6 +477,8 @@ static int redis_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
if(kw) {
if(!strcmp(kw,"as_rs_alg")) {
STRCPY(key->as_rs_alg,val);
} else if(!strcmp(kw,"realm")) {
STRCPY(key->realm,val);
} else if(!strcmp(kw,"ikm_key")) {
STRCPY(key->ikm_key,val);
} else if(!strcmp(kw,"timestamp")) {
@ -512,8 +514,8 @@ static int redis_set_oauth_key(oauth_key_data_raw *key) {
redisContext *rc = get_redis_connection();
if(rc) {
char statement[TURN_LONG_STRING_SIZE];
snprintf(statement,sizeof(statement),"hmset turn/oauth/kid/%s ikm_key %s as_rs_alg %s timestamp %llu lifetime %lu",
key->kid,key->ikm_key,key->as_rs_alg,(unsigned long long)key->timestamp,(unsigned long)key->lifetime);
snprintf(statement,sizeof(statement),"hmset turn/oauth/kid/%s ikm_key %s as_rs_alg %s timestamp %llu lifetime %lu realm %s",
key->kid,key->ikm_key,key->as_rs_alg,(unsigned long long)key->timestamp,(unsigned long)key->lifetime,key->realm);
turnFreeRedisReply(redisCommand(rc, statement));
turnFreeRedisReply(redisCommand(rc, "save"));
ret = 0;
@ -629,7 +631,7 @@ static int redis_list_users(u08bits *realm, secrets_list_t *users, secrets_list_
return ret;
}
static int redis_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts) {
static int redis_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms) {
int ret = -1;
redisContext *rc = get_redis_connection();
secrets_list_t keys;
@ -668,6 +670,7 @@ static int redis_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
if(kids) {
add_to_secrets_list(kids,key->kid);
add_to_secrets_list(teas,key->as_rs_alg);
add_to_secrets_list(realms,key->realm);
{
char ts[256];
snprintf(ts,sizeof(ts)-1,"%llu",(unsigned long long)key->timestamp);
@ -679,9 +682,9 @@ static int redis_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secre
add_to_secrets_list(lts,lt);
}
} else {
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s\n",
printf(" kid=%s, ikm_key=%s, timestamp=%llu, lifetime=%lu, as_rs_alg=%s, realm=%s\n",
key->kid, key->ikm_key, (unsigned long long)key->timestamp, (unsigned long)key->lifetime,
key->as_rs_alg);
key->as_rs_alg,key->realm);
}
}
}

View File

@ -157,7 +157,7 @@ static void init_sqlite_database(sqlite3 *sqliteconnection) {
"CREATE TABLE denied_peer_ip (realm varchar(127) default '', ip_range varchar(256), primary key (realm,ip_range))",
"CREATE TABLE turn_origin_to_realm (origin varchar(127),realm varchar(127),primary key (origin))",
"CREATE TABLE turn_realm_option (realm varchar(127) default '', opt varchar(32), value varchar(128), primary key (realm,opt))",
"CREATE TABLE oauth_key (kid varchar(128),ikm_key varchar(256),timestamp bigint default 0,lifetime integer default 0,as_rs_alg varchar(64) default '',primary key (kid))",
"CREATE TABLE oauth_key (kid varchar(128),ikm_key varchar(256),timestamp bigint default 0,lifetime integer default 0,as_rs_alg varchar(64) default '',realm varchar(127) default '',primary key (kid))",
"CREATE TABLE admin_user (name varchar(32), realm varchar(127), password varchar(127), primary key (name))",
NULL
};
@ -299,7 +299,7 @@ static int sqlite_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
int rc = 0;
/* direct user input eliminated - there is no SQL injection problem (since version 4.4.5.3) */
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg from oauth_key where kid='%s'",(const char*)kid);
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm from oauth_key where kid='%s'",(const char*)kid);
sqlite3 *sqliteconnection = get_sqlite_connection();
if(sqliteconnection) {
@ -315,6 +315,7 @@ static int sqlite_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
key->timestamp = (u64bits)strtoll((const char*)sqlite3_column_text(st, 1),NULL,10);
key->lifetime = (u32bits)strtol((const char*)sqlite3_column_text(st, 2),NULL,10);
STRCPY(key->as_rs_alg,sqlite3_column_text(st, 3));
STRCPY(key->realm,sqlite3_column_text(st, 4));
STRCPY(key->kid,kid);
ret = 0;
}
@ -331,7 +332,7 @@ static int sqlite_get_oauth_key(const u08bits *kid, oauth_key_data_raw *key) {
return ret;
}
static int sqlite_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts) {
static int sqlite_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms) {
oauth_key_data_raw key_;
oauth_key_data_raw *key=&key_;
@ -343,7 +344,7 @@ static int sqlite_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secr
char statement[TURN_LONG_STRING_SIZE];
sqlite3_stmt *st = NULL;
int rc = 0;
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,kid from oauth_key order by kid");
snprintf(statement,sizeof(statement),"select ikm_key,timestamp,lifetime,as_rs_alg,realm,kid from oauth_key order by kid");
sqlite3 *sqliteconnection = get_sqlite_connection();
if(sqliteconnection) {
@ -361,11 +362,13 @@ static int sqlite_list_oauth_keys(secrets_list_t *kids,secrets_list_t *teas,secr
key->timestamp = (u64bits)strtoll((const char*)sqlite3_column_text(st, 1),NULL,10);
key->lifetime = (u32bits)strtol((const char*)sqlite3_column_text(st, 2),NULL,10);
STRCPY(key->as_rs_alg,sqlite3_column_text(st, 3));
STRCPY(key->kid,sqlite3_column_text(st, 4));
STRCPY(key->realm,sqlite3_column_text(st, 4));
STRCPY(key->kid,sqlite3_column_text(st, 5));
if(kids) {
add_to_secrets_list(kids,key->kid);
add_to_secrets_list(teas,key->as_rs_alg);
add_to_secrets_list(realms,key->realm);
{
char ts[256];
snprintf(ts,sizeof(ts)-1,"%llu",(unsigned long long)key->timestamp);
@ -449,8 +452,8 @@ static int sqlite_set_oauth_key(oauth_key_data_raw *key)
snprintf(
statement,
sizeof(statement),
"insert or replace into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg) values('%s','%s',%llu,%lu,'%s')",
key->kid, key->ikm_key, (unsigned long long) key->timestamp, (unsigned long) key->lifetime, key->as_rs_alg);
"insert or replace into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('%s','%s',%llu,%lu,'%s','%s')",
key->kid, key->ikm_key, (unsigned long long) key->timestamp, (unsigned long) key->lifetime, key->as_rs_alg, key->realm);
sqlite_lock(1);

View File

@ -68,7 +68,7 @@ typedef struct _turn_dbdriver_t {
int (*set_oauth_key)(oauth_key_data_raw *key);
int (*get_oauth_key)(const u08bits *kid, oauth_key_data_raw *key);
int (*del_oauth_key)(const u08bits *kid);
int (*list_oauth_keys)(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts);
int (*list_oauth_keys)(secrets_list_t *kids,secrets_list_t *teas,secrets_list_t *tss,secrets_list_t *lts,secrets_list_t *realms);
int (*get_admin_user)(const u08bits *usname, u08bits *realm, password_t pwd);
int (*set_admin_user)(const u08bits *usname, const u08bits *realm, const password_t pwd);
int (*del_admin_user)(const u08bits *usname);

View File

@ -2773,12 +2773,13 @@ static size_t https_print_oauth_keys(struct str_buffer* sb)
size_t ret = 0;
const turn_dbdriver_t * dbd = get_dbdriver();
if (dbd && dbd->list_oauth_keys) {
secrets_list_t kids,teas,tss,lts;
secrets_list_t kids,teas,tss,lts,realms;
init_secrets_list(&kids);
init_secrets_list(&teas);
init_secrets_list(&tss);
init_secrets_list(&lts);
dbd->list_oauth_keys(&kids,&teas,&tss,&lts);
init_secrets_list(&realms);
dbd->list_oauth_keys(&kids,&teas,&tss,&lts,&realms);
size_t sz = get_secrets_list_size(&kids);
size_t i;
@ -2824,6 +2825,9 @@ static size_t https_print_oauth_keys(struct str_buffer* sb)
clean_secrets_list(&kids);
clean_secrets_list(&teas);
clean_secrets_list(&tss);
clean_secrets_list(&lts);
clean_secrets_list(&realms);
}
return ret;

View File

@ -102,9 +102,9 @@ int oauth = 0;
oauth_key okey_array[3];
static oauth_key_data_raw okdr_array[3] = {
{"north","MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK",0,0,"A256GCM"},
{"union","MTIzNDU2Nzg5MDEyMzQ1Ngo=",0,0,"A128GCM"},
{"oldempire","MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK",0,0,"A256GCM"}
{"north","MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK",0,0,"A256GCM","crinna.org"},
{"union","MTIzNDU2Nzg5MDEyMzQ1Ngo=",0,0,"A128GCM","north.gov"},
{"oldempire","MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK",0,0,"A256GCM",""}
};
//////////////// local definitions /////////////////
@ -137,7 +137,7 @@ static char Usage[] =
" -G Generate extra requests (create permissions, channel bind).\n"
" -B Random disconnect after a few initial packets.\n"
" -Z Dual allocation (implies -c).\n"
" -J Use oAuth with default test key kid='north' or 'oldempire'.\n"
" -J Use oAuth with default test keys kid='north', 'union' or 'oldempire'.\n"
"Options:\n"
" -l Message length (Default: 100 Bytes).\n"
" -i Certificate file (for secure connections only, optional).\n"

View File

@ -31,7 +31,7 @@
#ifndef __IOADEFS__
#define __IOADEFS__
#define TURN_SERVER_VERSION "4.4.5.5"
#define TURN_SERVER_VERSION "4.5.0.0"
#define TURN_SERVER_VERSION_NAME "Ardee West"
#define TURN_SOFTWARE "Coturn-" TURN_SERVER_VERSION " '" TURN_SERVER_VERSION_NAME "'"

View File

@ -43,6 +43,7 @@ CREATE TABLE oauth_key (
timestamp bigint default 0,
lifetime integer default 0,
as_rs_alg varchar(64) default '',
realm varchar(127),
primary key (kid)
);

View File

@ -47,6 +47,9 @@ and they will be almost immediately "seen" by the turnserver process.
http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-5.1).
The default value is "A256GCM".
realm - optionally, a kid can be assigned to a realm that is different
from the default realm.
5) admin users (over https interface) are maintained as keys of form:
"turn/admin_user/<username> with hash members "password" and,
optionally, "realm".
@ -54,7 +57,13 @@ optionally, "realm".
II. Extra realms data in the database
We can use more than one realm with the same instance of the TURN server.
This is done through the ORIGIN mechanism - users with different ORIGINS
This is done in two ways:
1) through the third-party authentication option. An oAuth kid can be optionally
assigned to a realm. When the user provides kid, and the database record
for that kid contains a non-empty non-default realm, then the user is treated
as belonging to that realm.
2) the ORIGIN mechanism - users with different ORIGINS
are placed into different realms. The database includes information about the
relationships between the ORIGIN and realms, and about the extra realms
database numbers.
@ -82,7 +91,7 @@ This example sets user database for:
"total_quota" and "user_quota" (same names as the turnserver
configuration options, with the same meanings).
* The oAuth data for the key with kid "oldempire" and key value
"12345678901234567890123456789012".
"12345678901234567890123456789012", and default realm.
* The admin user 'skarling', realm 'north.gov', with password 'hoodless';
* The global admin user 'bayaz' with password 'magi';

View File

@ -28,8 +28,8 @@ db.turn_secret.insert({ realm: 'north.gov', value: 'bloody9' });
db.turn_secret.insert({ realm: 'crinna.org', value: 'north' });
db.turn_secret.insert({ realm: 'crinna.org', value: 'library' });
db.admin_user.insert({ name: 'skarling', realm: 'north.gov', password: '$5$6fc35c3b0c7d4633$27fca7574f9b79d0cb93ae03e45379470cbbdfcacdd6401f97ebc620f31f54f2' });
db.admin_user.insert({ name: 'bayaz', realm: '', password: '$5$e018513e9de69e73$5cbdd2e29e04ca46aeb022268a7460d3a3468de193dcb2b95f064901769f455f' });
db.admin_user.insert({ name: 'skarling', realm: 'north.gov', password: '\$5\$6fc35c3b0c7d4633\$27fca7574f9b79d0cb93ae03e45379470cbbdfcacdd6401f97ebc620f31f54f2' });
db.admin_user.insert({ name: 'bayaz', realm: '', password: '\$5\$e018513e9de69e73\$5cbdd2e29e04ca46aeb022268a7460d3a3468de193dcb2b95f064901769f455f' });
db.realm.insert({
realm: 'north.gov',
@ -56,10 +56,12 @@ db.realm.insert({
db.oauth_key.insert({ kid: 'north',
ikm_key: 'MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK',
as_rs_alg: 'A256GCM'});
as_rs_alg: 'A256GCM',
realm: 'crinna.org'});
db.oauth_key.insert({ kid: 'union',
ikm_key: 'MTIzNDU2Nzg5MDEyMzQ1Ngo=',
as_rs_alg: 'A128GCM'});
as_rs_alg: 'A128GCM',
realm: 'north.gov'});
db.oauth_key.insert({ kid: 'oldempire',
ikm_key: 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK',
as_rs_alg: 'A256GCM'});

View File

@ -38,8 +38,8 @@ sadd turn/realm/crinna.org/allowed-peer-ip "172.17.13.202"
sadd turn/realm/north.gov/denied-peer-ip "172.17.13.133-172.17.14.56" "172.17.17.133-172.17.19.56" "123::45"
sadd turn/realm/crinna.org/denied-peer-ip "123::77"
hmset turn/oauth/kid/north ikm_key 'MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK' as_rs_alg 'A256GCM'
hmset turn/oauth/kid/union ikm_key 'MTIzNDU2Nzg5MDEyMzQ1Ngo=' as_rs_alg 'A128GCM'
hmset turn/oauth/kid/north ikm_key 'MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK' as_rs_alg 'A256GCM' realm 'crinna.org'
hmset turn/oauth/kid/union ikm_key 'MTIzNDU2Nzg5MDEyMzQ1Ngo=' as_rs_alg 'A128GCM' realm 'north.gov'
hmset turn/oauth/kid/oldempire ikm_key 'MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK' as_rs_alg 'A256GCM'
hmset turn/admin_user/skarling realm 'north.gov' password '\$5\$6fc35c3b0c7d4633\$27fca7574f9b79d0cb93ae03e45379470cbbdfcacdd6401f97ebc620f31f54f2'

View File

@ -31,6 +31,6 @@ insert into denied_peer_ip (ip_range) values('123::45');
insert into denied_peer_ip (realm,ip_range) values('north.gov','172.17.17.133-172.17.19.56');
insert into denied_peer_ip (realm,ip_range) values('crinna.org','123::77');
insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg) values('north','MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK',0,0,'A256GCM');
insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg) values('union','MTIzNDU2Nzg5MDEyMzQ1Ngo=',0,0,'A128GCM');
insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg) values('oldempire','MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK',0,0,'A256GCM');
insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('north','MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEK',0,0,'A256GCM','crinna.org');
insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('union','MTIzNDU2Nzg5MDEyMzQ1Ngo=',0,0,'A128GCM','north.gov');
insert into oauth_key (kid,ikm_key,timestamp,lifetime,as_rs_alg,realm) values('oldempire','MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIK',0,0,'A256GCM','');