1
0
mirror of https://github.com/coturn/coturn.git synced 2025-10-24 12:31:00 +02:00

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)
);
@ -763,6 +764,8 @@ The oauth_key table fields meanings are:
"A256GCM", "A128GCM" (see
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

3
STATUS
View File

@ -123,6 +123,9 @@ supported in the client library).
53) SHA384 and SHA512 support added (experimental).
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

@ -46,6 +46,9 @@ and they will be almost immediately "seen" by the turnserver process.
"A256GCM", "A128GCM" (see
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,
@ -54,15 +57,21 @@ 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
are placed into different realms. The database includes information about the
relationships between the ORIGIN and realms, and about the extra realms
database numbers.
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.
The relationship between ORIGIN and realm is set as keys of form:
"turn/origin/<origin>" with the realm-names as the value. Many different
ORIGIN keys may have the same realm. If the ORIGIN value is not found in
the database or the ORIGIN field is missed in the initial allocate
request, then the default realm is assumed.
"turn/origin/<origin>" with the realm-names as the value. Many different
ORIGIN keys may have the same realm. If the ORIGIN value is not found in
the database or the ORIGIN field is missed in the initial allocate
request, then the default realm is assumed.
III) Example of a Redis default user database setup.
@ -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','');