2
0
Эх сурвалжийг харах

modules/auth_ephemeral: new module for ephemeral credential based authentication

Peter Dunkley 12 жил өмнө
parent
commit
0bea7f63af

+ 41 - 0
modules/auth_ephemeral/Makefile

@@ -0,0 +1,41 @@
+# $Id$
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=auth_ephemeral.so
+
+ifeq ($(CROSS_COMPILE),)
+SSL_BUILDER=$(shell \
+	if pkg-config --exists libssl; then \
+		echo 'pkg-config libssl'; \
+	fi)
+endif
+
+ifneq ($(SSL_BUILDER),)
+	DEFS += $(shell $(SSL_BUILDER) --cflags)
+	LIBS += $(shell $(SSL_BUILDER) --libs)
+else
+	DEFS += -I$(LOCALBASE)/ssl/include
+	LIBS += -L$(LOCALBASE)/lib -L$(LOCALBASE)/ssl/lib \
+			-L$(LOCALBASE)/lib64 -L$(LOCALBASE)/ssl/lib64 \
+			-lssl -lcrypto
+	# NOTE: depending on the way in which libssl was compiled you might
+	#       have to add -lz -lkrb5   (zlib and kerberos5).
+	#       E.g.: make TLS_HOOKS=1 TLS_EXTRA_LIBS="-lz -lkrb5"
+endif
+
+LIBS+= $(TLS_EXTRA_LIBS)
+
+# Static linking, if you'd like to use TLS and AUTH_EPHEMERAL at the same time
+#
+#LIBS+= /usr/lib/libcurl.a /usr/lib/libssl.a /usr/lib/libcrypto.a -lkrb5 -lidn -lz -lgssapi_krb5 -lrt
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
+
+include ../../Makefile.modules

+ 250 - 0
modules/auth_ephemeral/README

@@ -0,0 +1,250 @@
+Auth_ephemeral Module
+
+Peter Dunkley
+
+   Crocodile RCS Ltd
+   <[email protected]>
+
+   Copyright © 2013 Crocdile RCS Ltd
+     __________________________________________________________________
+
+   Table of Contents
+
+   1. Admin Guide
+
+        1. Overview
+
+              1.1. How ephemeral credentials work
+
+                    1.1.1. Request
+                    1.1.2. Response
+
+        2. Dependencies
+
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
+
+        3. Parameters
+
+              3.1. secret (string)
+
+        4. Functions
+
+              4.1. autheph_proxy(realm)
+              4.2. autheph_www(realm[, method])
+              4.3. autheph_check(realm)
+
+   List of Examples
+
+   1.1.
+   1.2.
+   1.3. secret parameter usage
+   1.4. autheph_proxy usage
+   1.5. autheph_www usage
+   1.6. autheph_check usage
+
+Chapter 1. Admin Guide
+
+   Table of Contents
+
+   1. Overview
+
+        1.1. How ephemeral credentials work
+
+              1.1.1. Request
+              1.1.2. Response
+
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Parameters
+
+        3.1. secret (string)
+
+   4. Functions
+
+        4.1. autheph_proxy(realm)
+        4.2. autheph_www(realm[, method])
+        4.3. autheph_check(realm)
+
+1. Overview
+
+   1.1. How ephemeral credentials work
+
+        1.1.1. Request
+        1.1.2. Response
+
+   This module contains all authentication related functions that can work
+   with ephemeral credentials. This module should be used together with
+   the auth module - it cannot be used independently because it depends on
+   the auth module. Use this module if you want to use ephemeral
+   credentials instead of ordinary usernames and passwords.
+
+1.1. How ephemeral credentials work
+
+   Ephemeral credentials are generated by a web-service and enforced on
+   Kamailio. This usage of ephemeral credentials ensures that access to
+   Kamailio is controlled even if the credentials cannot be kept secret,
+   as can be the case in WebRTC where the credentials may be specified in
+   Javascript.
+
+   To use this mechanism, the only interaction needed between the
+   web-service and Kamailio is to share a secret key.
+
+   Typically, credentials will be requested from the web-service using an
+   HTTP GET and provided in a JSON response. To prevent unauthorised use
+   the HTTP requests can be ACLd by various means.
+
+   This mechanism is based on the Google proposal for a "TURN Server REST
+   API".
+
+1.1.1. Request
+
+   The request should contain the following parameters:
+     * service - specifies the desired service (msrp, sip, etc)
+     * username - a user identifier for the service
+     * ttl - an optional TTL request for the lifetime of the credentials,
+       in seconds.
+
+   Example 1.1.
+GET /?service=sip&username=foobar;&ttl=86400;
+
+1.1.2. Response
+
+   The response should include the following parameters:
+     * username - the username to use, which is a combination of the
+       username parameter from the request, with a timestamp in time_t
+       format, colon-separated.
+     * password - the password to use; this value is computed from the
+       secret key and the returned username value, by performing
+       base64(hmac-sha1(secret key, returned username)).
+     * ttl - the duration for which the username and password are valid,
+       in seconds. This number will be less than or equal to the requested
+       TTL.
+     * uris - an array of URIs indicating servers that the username and
+       password are valid for.
+
+   Example 1.2.
+{
+  "username" : "foobar:1234567890",
+  "password" : "asdfghjklauio=",
+  "ttl" : 86400,
+  "uris" : [
+    "sip:1.2.3.4;transport=ws",
+    "sip:5.6.7.8;transport=ws"
+  ]
+}
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
+
+   The module must be loaded before this module:
+     * auth.
+
+2.2. External Libraries or Applications
+
+   The following libraries must be installed before running Kamailio with
+   this module loaded:
+     * OpenSSL.
+
+3. Parameters
+
+   3.1. secret (string)
+
+3.1. secret (string)
+
+   The shared secret to use for generating credentials. This parameter can
+   be set multiple times - this enables the secret used for new
+   credentials to be changed without causing existing credentials to stop
+   working. The last secret set is the first that will be tried.
+
+   Example 1.3. secret parameter usage
+...
+modparam("auth_ephemeral", "secret", "kamailio_rules")
+...
+
+4. Functions
+
+   4.1. autheph_proxy(realm)
+   4.2. autheph_www(realm[, method])
+   4.3. autheph_check(realm)
+
+4.1.  autheph_proxy(realm)
+
+   This function performs proxy authentication. the rest.
+
+   The meaning of the parameters are as follows:
+     * realm - Realm is an opaque string that the user agent should
+       present to the user so that he can decide what username and
+       password to use. Usually this is domain of the host the server is
+       running on.
+       It must not be an empty string “”. Apart from a static string, a
+       typical value is the From-URI domain (i.e., $fd).
+       The string may contain pseudo variables.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.4. autheph_proxy usage
+...
+if (!autheph_proxy("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...
+
+4.2.  autheph_www(realm[, method])
+
+   This function performs WWW digest authentication.
+
+   The meaning of the parameters are as follows:
+     * realm - Realm is an opaque string that the user agent should
+       present to the user so that he can decide what username and
+       password to use. Usually this is domain of the host the server is
+       running on.
+       It must not be an empty string “”. Apart from a static string, a
+       typical value is the From-URI domain (i.e., $fd).
+       The string may contain pseudo variables.
+     * method - the method to be used for authentication. This parameter
+       is optional and if not set the first "word" on the request-line is
+       used.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.5. autheph_www usage
+...
+if (!autheph_www("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...
+
+4.3.  autheph_check(realm)
+
+   This function combines the functionalities of autheph_www and
+   autheph_proxy, the first being exectuted if the SIP request is a
+   REGISTER, the second for the rest.
+
+   The meaning of the parameters are as follows:
+     * realm - Realm is an opaque string that the user agent should
+       present to the user so that he can decide what username and
+       password to use. Usually this is domain of the host the server is
+       running on.
+       It must not be an empty string “”. Apart from a static string, a
+       typical value is the From-URI domain (i.e., $fd).
+       The string may contain pseudo variables.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.6. autheph_check usage
+...
+if (!autheph_check("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...

+ 168 - 0
modules/auth_ephemeral/autheph_mod.c

@@ -0,0 +1,168 @@
+/* 
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+#include "../../sr_module.h"
+#include "../../str.h"
+#include "../../modules/auth/api.h"
+
+#include "autheph_mod.h"
+#include "authorize.h"
+
+MODULE_VERSION
+
+static int mod_init(void);
+static void destroy(void);
+
+static int secret_param(modparam_t type, void* param);
+struct secret *secret_list = NULL;
+
+auth_api_s_t eph_auth_api;
+
+static cmd_export_t cmds[]=
+{
+	{ "autheph_check", (cmd_function) autheph_check,
+	  1, fixup_var_str_1, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_www", (cmd_function) autheph_www,
+	  1, fixup_var_str_1, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_www", (cmd_function) autheph_www2,
+	  2, fixup_var_str_12, 0,
+	  REQUEST_ROUTE },
+	{ "autheph_proxy", (cmd_function) autheph_proxy,
+	  1, fixup_var_str_1, 0,
+	  REQUEST_ROUTE },
+
+	{0, 0, 0, 0, 0, 0}
+};
+
+static param_export_t params[]=
+{
+	{ "secret",		STR_PARAM|USE_FUNC_PARAM,
+	  (void *) secret_param },
+	{0, 0, 0}
+};
+
+struct module_exports exports=
+{
+	"auth_ephemeral", 
+	DEFAULT_DLFLAGS,	/* dlopen flags */
+	cmds,			/* Exported functions */
+	params,			/* Exported parameters */
+	0,			/* exported statistics */
+	0,			/* exported MI functions */
+	0,			/* exported pseudo-variables */
+	0,			/* extra processes */
+	mod_init,		/* module initialization function */
+	0,			/* response function */
+	destroy,		/* destroy function */
+	0			/* child initialization function */
+};
+
+static int mod_init(void)
+{
+	bind_auth_s_t bind_auth;
+
+	if (secret_list == NULL)
+	{
+		LM_ERR("secret modparam not set\n");
+		return -1;
+	}
+
+	bind_auth = (bind_auth_s_t) find_export("bind_auth_s", 0, 0);
+	if (!bind_auth)
+	{
+		LM_ERR("unable to find bind_auth function. Check if you have"
+			" loaded the auth module.\n");
+		return -2;
+	}
+
+	if (bind_auth(&eph_auth_api) < 0)
+	{
+		LM_ERR("unable to bind to auth module\n");
+		return -3;
+	}
+
+	return 0;
+}
+
+static void destroy(void)
+{
+	struct secret *secret_struct;
+
+	while (secret_list != NULL)
+	{
+		secret_struct = secret_list;
+		secret_list = secret_struct->next;
+
+		if (secret_struct->secret_key.s != NULL)
+		{
+			shm_free(secret_struct->secret_key.s);
+		}
+		shm_free(secret_struct);
+	}
+}
+
+static int add_secret(str secret_key)
+{
+	struct secret *secret_struct;
+
+	secret_struct = (struct secret *) shm_malloc(sizeof(struct secret));
+	if (secret_struct == NULL)
+	{
+		LM_ERR("unable to allocate shared memory\n");
+		return -1;
+	}
+
+	memset(secret_struct, 0, sizeof (struct secret));
+	secret_struct->next = secret_list;
+	secret_list = secret_struct;
+	secret_struct->secret_key = secret_key;
+
+	return 0;
+}
+
+static int secret_param(modparam_t type, void *val)
+{
+	str sval;
+
+	if (val == NULL)
+	{
+		LM_ERR("bad parameter\n");
+		return -1;
+	}
+
+	LM_INFO("adding %s to secret list\n", (char *) val);
+
+	sval.len = strlen((char *) val);
+	sval.s = (char *) shm_malloc(sizeof(char) * sval.len);
+	if (sval.s == NULL)
+	{
+		LM_ERR("unable to allocate shared memory\n");
+		return -1;
+	}
+	memcpy(sval.s, (char *) val, sval.len);
+
+	return add_secret(sval);
+}

+ 31 - 0
modules/auth_ephemeral/autheph_mod.h

@@ -0,0 +1,31 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef AUTHEPH_MOD_H
+#define AUTHEPH_MOD_H
+
+#include "../../str.h"
+#include "../../modules/auth/api.h"
+
+extern auth_api_s_t eph_auth_api;
+
+#endif /* AUTHEPH_MOD_H */

+ 346 - 0
modules/auth_ephemeral/authorize.c

@@ -0,0 +1,346 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <openssl/hmac.h>
+
+#include "../../basex.h"
+#include "../../dprint.h"
+#include "../../mod_fix.h"
+#include "../../str.h"
+#include "../../ut.h"
+#include "../../parser/digest/digest.h"
+#include "../../parser/hf.h"
+#include "../../mod_fix.h"
+
+#include "autheph_mod.h"
+#include "authorize.h"
+
+#if !defined(SHA_DIGEST_LENGTH)
+#define SHA_DIGEST_LENGTH (20)
+#endif
+
+static inline int get_ha1(struct username* _username, str* _domain,
+				str* _secret, char* _ha1)
+{
+	unsigned int hmac_len = SHA_DIGEST_LENGTH;
+	unsigned char hmac_sha1[hmac_len];
+	unsigned char password[base64_enc_len(hmac_len)];
+	str spassword;
+
+	LM_INFO("using secret: %.*s\n", _secret->len, _secret->s);
+	if (HMAC(EVP_sha1(), _secret->s, _secret->len,
+			(unsigned char *) _username->whole.s,
+			_username->whole.len, hmac_sha1, &hmac_len) == NULL) {
+		LM_ERR("HMAC-SHA1 failed\n");
+		return -1;
+	}
+
+	spassword.len = base64_enc(hmac_sha1, hmac_len, password,
+					base64_enc_len(hmac_len));
+	spassword.s = (char *) password;
+	LM_INFO("calculated password: %.*s\n", spassword.len, spassword.s);
+
+	eph_auth_api.calc_HA1(HA_MD5, &_username->whole, _domain, &spassword,
+				0, 0, _ha1);
+	LM_INFO("HA1 string calculated: %s\n", _ha1);
+
+	return 0;
+}
+
+static int do_auth(struct sip_msg* msg, struct hdr_field *h, str *realm,
+			str *method, str* secret)
+{
+	int ret;
+	char ha1[256];
+	auth_body_t *cred = (auth_body_t*) h->parsed;
+
+	ret = get_ha1(&cred->digest.username, realm, secret, ha1);
+	if (ret < 0)
+	{
+		return AUTH_ERROR;
+	}
+
+	ret = eph_auth_api.check_response(&(cred->digest), method, ha1);
+	if (ret == AUTHENTICATED)
+	{
+		if (eph_auth_api.post_auth(msg, h) != AUTHENTICATED)
+		{
+			return AUTH_ERROR;
+		}
+	}
+	else if (ret == NOT_AUTHENTICATED)
+	{
+		return AUTH_INVALID_PASSWORD;
+	}
+	else
+	{
+		ret = AUTH_ERROR;
+	}
+
+	return AUTH_OK;
+}
+
+static int verify_timestamp(str* username)
+{
+	int pos = 0;
+	unsigned int expires;
+	str time_str = {0, 0};
+
+	LM_INFO("username: %.*s\n", username->len, username->s);
+
+	while (pos < username->len && username->s[pos] != ':')
+		pos++;
+
+	if (pos < username->len - 1)
+	{
+		time_str.s = username->s + pos + 1;
+		time_str.len = username->len - pos - 1;
+	}
+	else
+	{
+		LM_ERR("unable to extract timestamp from username\n");
+		return -1;
+	}
+
+	LM_INFO("username timestamp: %.*s\n", time_str.len, time_str.s);
+
+	if (str2int(&time_str, &expires) < 0)
+	{
+		LM_ERR("unable to convert timestamp to int\n");
+		return -1;
+	}
+
+	if ((int) time(NULL) > expires)
+	{
+		LM_WARN("username has expired\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int digest_authenticate(struct sip_msg* msg, str *realm,
+				hdr_types_t hftype, str *method)
+{
+	struct hdr_field* h;
+	int ret;
+	struct secret *secret_struct = secret_list;
+
+	ret = eph_auth_api.pre_auth(msg, realm, hftype, &h, NULL);
+	switch(ret) {
+		case NONCE_REUSED:
+			LM_DBG("nonce reused\n");
+			return AUTH_NONCE_REUSED;
+		case STALE_NONCE:
+			LM_DBG("stale nonce\n");
+			return AUTH_STALE_NONCE;
+		case NO_CREDENTIALS:
+			LM_DBG("no credentials\n");
+			return AUTH_NO_CREDENTIALS;
+		case ERROR:
+		case BAD_CREDENTIALS:
+			LM_DBG("error or bad credentials\n");
+			return AUTH_ERROR;
+		case CREATE_CHALLENGE:
+			LM_ERR("CREATE_CHALLENGE is not a valid state\n");
+			return AUTH_ERROR;
+		case DO_RESYNCHRONIZATION:
+			LM_ERR("DO_RESYNCHRONIZATION is not a valid state\n");
+			return AUTH_ERROR;
+		case NOT_AUTHENTICATED:
+			LM_DBG("not authenticated\n");
+			return AUTH_ERROR;
+		case DO_AUTHENTICATION:
+			break;
+		case AUTHENTICATED:
+			return AUTH_OK;
+	}
+
+	if (verify_timestamp(&((auth_body_t*) h->parsed)->digest.username.whole)
+			< 0)
+	{
+		LM_ERR("invalid timestamp in username\n");
+		return AUTH_ERROR;
+	}
+
+	while (secret_struct != NULL)
+	{
+		ret = do_auth(msg, h, realm, method,
+				&secret_struct->secret_key);
+		if (ret == AUTH_OK)
+		{
+			break;
+		}
+		secret_struct = secret_struct->next;
+	}
+
+	return ret;
+}
+
+int autheph_check(struct sip_msg* _m, char* _realm)
+{
+	str srealm;
+
+	if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL))
+	{
+		return AUTH_OK;
+	}
+
+	if(_m==NULL || _realm==NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
+	{
+		LM_ERR("failed to get realm value\n");
+		return AUTH_ERROR;
+	}
+
+	if (srealm.len==0)
+	{
+		LM_ERR("invalid realm parameter - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	LM_DBG("realm [%.*s]\n", srealm.len, srealm.s);
+
+	if(_m->REQ_METHOD==METHOD_REGISTER)
+		return digest_authenticate(_m, &srealm, HDR_AUTHORIZATION_T,
+					&_m->first_line.u.request.method);
+	else
+		return digest_authenticate(_m, &srealm, HDR_PROXYAUTH_T,
+					&_m->first_line.u.request.method);
+}
+
+int autheph_www(struct sip_msg* _m, char* _realm)
+{
+	str srealm;
+
+	if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL))
+	{
+		return AUTH_OK;
+	}
+
+	if(_m==NULL || _realm==NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
+	{
+		LM_ERR("failed to get realm value\n");
+		return AUTH_ERROR;
+	}
+
+	if (srealm.len==0)
+	{
+		LM_ERR("invalid realm parameter - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	LM_DBG("realm [%.*s]\n", srealm.len, srealm.s);
+
+	return digest_authenticate(_m, &srealm, HDR_AUTHORIZATION_T,
+					&_m->first_line.u.request.method);
+}
+
+int autheph_www2(struct sip_msg* _m, char* _realm, char *_method)
+{
+	str srealm;
+	str smethod;
+
+	if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL))
+	{
+		return AUTH_OK;
+	}
+
+	if(_m==NULL || _realm==NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
+	{
+		LM_ERR("failed to get realm value\n");
+		return AUTH_ERROR;
+	}
+
+	if (srealm.len==0)
+	{
+		LM_ERR("invalid realm parameter - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&smethod, _m, (fparam_t*)_method) < 0)
+	{
+		LM_ERR("failed to get method value\n");
+		return AUTH_ERROR;
+	}
+
+	if (smethod.len == 0)
+	{
+		LM_ERR("invalid method value - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	LM_DBG("realm [%.*s] method [%.*s]\n", srealm.len, srealm.s,
+		smethod.len, smethod.s);
+
+	return digest_authenticate(_m, &srealm, HDR_AUTHORIZATION_T, &smethod);
+}
+
+int autheph_proxy(struct sip_msg* _m, char* _realm)
+{
+	str srealm;
+
+	if ((_m->REQ_METHOD == METHOD_ACK) || (_m->REQ_METHOD == METHOD_CANCEL))
+	{
+		return AUTH_OK;
+	}
+
+	if(_m==NULL || _realm==NULL)
+	{
+		LM_ERR("invalid parameters\n");
+		return AUTH_ERROR;
+	}
+
+	if (get_str_fparam(&srealm, _m, (fparam_t*)_realm) < 0)
+	{
+		LM_ERR("failed to get realm value\n");
+		return AUTH_ERROR;
+	}
+
+	if (srealm.len==0)
+	{
+		LM_ERR("invalid realm parameter - empty value\n");
+		return AUTH_ERROR;
+	}
+
+	LM_DBG("realm [%.*s]\n", srealm.len, srealm.s);
+
+	return digest_authenticate(_m, &srealm, HDR_PROXYAUTH_T,
+					&_m->first_line.u.request.method);
+}

+ 42 - 0
modules/auth_ephemeral/authorize.h

@@ -0,0 +1,42 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2013 Crocodile RCS Ltd
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef AUTHORIZE_H
+#define AUTHORIZE_H
+
+#include "../../str.h"
+#include "../../parser/msg_parser.h"
+
+struct secret
+{
+	str secret_key;
+	struct secret *next;
+};
+
+extern struct secret *secret_list;
+
+int autheph_check(struct sip_msg* _m, char* _realm);
+int autheph_www(struct sip_msg* _m, char* _realm);
+int autheph_www2(struct sip_msg* _m, char* _realm, char *_method);
+int autheph_proxy(struct sip_msg* _m, char* _realm);
+
+#endif /* AUTHORIZE_H */

+ 4 - 0
modules/auth_ephemeral/doc/Makefile

@@ -0,0 +1,4 @@
+docs = auth_ephemeral.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 30 - 0
modules/auth_ephemeral/doc/auth_ephemeral.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+	<bookinfo>
+	<title>Auth_ephemeral Module</title>
+	<authorgroup>
+		<author>
+		<firstname>Peter</firstname>
+		<surname>Dunkley</surname>
+		<affiliation><orgname>Crocodile RCS Ltd</orgname></affiliation>
+		<email>[email protected]</email>
+		</author>
+	</authorgroup>
+	<copyright>
+		<year>2013</year>
+		<holder>Crocdile RCS Ltd</holder>
+	</copyright>
+	</bookinfo>
+	<toc></toc>
+
+	<xi:include href="auth_ephemeral_admin.xml"/>
+</book>

+ 306 - 0
modules/auth_ephemeral/doc/auth_ephemeral_admin.xml

@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding='ISO-8859-1'?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+
+]>
+
+<!-- Auth_ephemeral Module User's Guide -->
+
+<chapter>
+	
+	<title>&adminguide;</title>
+	
+	<section>
+	<title>Overview</title>
+	<para>
+	This module contains all authentication related functions that can work
+	with ephemeral credentials. This module should be used together with the
+	auth module - it cannot be used independently because it depends on the
+	auth module. Use this module if you want to use ephemeral credentials
+	instead of ordinary usernames and passwords.
+	</para>
+
+	<section>
+	<title>How ephemeral credentials work</title>
+	<para>
+	Ephemeral credentials are generated by a web-service and enforced on
+	Kamailio. This usage of ephemeral credentials ensures that access to
+	Kamailio is controlled even if the credentials cannot be kept secret,
+	as can be the case in WebRTC where the credentials may be specified in
+	Javascript.
+	</para>
+	<para>
+	To use this mechanism, the only interaction needed between the
+	web-service and Kamailio is to share a secret key.
+	</para>
+	<para>
+	Typically, credentials will be requested from the web-service using an
+	HTTP GET and provided in a JSON response. To prevent unauthorised use
+	the HTTP requests can be ACLd by various means.
+	</para>
+	<para>
+	This mechanism is based on the Google proposal for a &quot;TURN Server
+	REST API&quot;.
+	</para>
+	<section>
+	<title>Request</title>
+	<para>
+	The request should contain the following parameters:
+	<itemizedlist>
+	<listitem>
+	<para><emphasis>service</emphasis> - specifies the desired service
+	(msrp, sip, etc)</para>
+	</listitem>
+	<listitem>
+	<para><emphasis>username</emphasis> - a user identifier for the
+	service</para>
+	</listitem>
+	<listitem>
+	<para><emphasis>ttl</emphasis> - an optional TTL request for the
+	lifetime of the credentials, in seconds.</para>
+	</listitem>
+	</itemizedlist>
+	</para>
+	<example>
+	<programlisting format="linespecific">
+GET /?service=sip&amp;username=foobar;&amp;ttl=86400;
+</programlisting>
+	</example>
+	</section>
+	<section>
+	<title>Response</title>
+	<para>
+	The response should include the following parameters:
+	<itemizedlist>
+	<listitem>
+	<para><emphasis>username</emphasis> - the username to use, which is a
+	combination of the username parameter from the request, with a timestamp
+	in time_t format, colon-separated.</para>
+	</listitem>
+	<listitem>
+	<para><emphasis>password</emphasis> - the password to use; this value is
+	computed from the secret key and the returned username value, by
+	performing base64(hmac-sha1(secret key, returned username)).</para>
+	</listitem>
+	<listitem>
+	<para><emphasis>ttl</emphasis> - the duration for which the username and
+	password are valid, in seconds. This number will be less than or equal
+	to the requested TTL.</para>
+	</listitem>
+	<listitem>
+	<para><emphasis>uris</emphasis> - an array of URIs indicating servers that
+	the username and password are valid for.</para>
+	</listitem>
+	</itemizedlist>
+	</para>
+	<example>
+	<programlisting format="linespecific">
+{
+  "username" : "foobar:1234567890",
+  "password" : "asdfghjklauio=",
+  "ttl" : 86400,
+  "uris" : [
+    "sip:1.2.3.4;transport=ws",
+    "sip:5.6.7.8;transport=ws"
+  ]
+}
+</programlisting>
+	</example>
+	</section>
+	</section>
+	</section>
+
+	<section>
+	<title>Dependencies</title>
+	<section>
+		<title>&kamailio; Modules</title>
+		<para>
+		The module must be loaded before this module:
+		<itemizedlist>
+		<listitem>
+		<para><emphasis>auth</emphasis>.</para>
+		</listitem>
+		</itemizedlist>
+		</para>
+	</section>
+
+	<section>
+		<title>External Libraries or Applications</title>
+		<para>
+		The following libraries must be installed before running
+		&kamailio; with this module loaded:
+		<itemizedlist>
+		<listitem>
+		<para><emphasis>OpenSSL</emphasis>.</para>
+		</listitem>
+		</itemizedlist>
+		</para>
+	</section>
+	</section>
+
+
+	<section>
+	<title>Parameters</title>
+	<section>
+		<title><varname>secret</varname> (string)</title>
+		<para>
+		The shared secret to use for generating credentials. This
+		parameter can be set multiple times - this enables the secret
+		used for new credentials to be changed without causing existing
+		credentials to stop working. The last secret set is the first
+		that will be tried.
+		</para>
+		<example>
+		<title><varname>secret</varname> parameter usage</title>
+		<programlisting format="linespecific">
+...
+modparam("auth_ephemeral", "secret", "kamailio_rules")
+...
+</programlisting>
+		</example>
+	</section>
+	</section>
+
+	<section>
+	<title>Functions</title>
+	<section>
+		<title>
+			<function moreinfo="none">autheph_proxy(realm)</function>
+		</title>
+		<para>This function performs proxy authentication.
+		the rest.
+		</para>
+		<para>The meaning of the parameters are as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>realm</emphasis> - Realm is an opaque
+			string that the user agent should present to the user so
+			that he can decide what username and password to use.
+			Usually this is domain of the host the server is running
+			on.
+			</para>
+			<para>
+			It must not be an empty string <quote></quote>. Apart
+			from a static string, a typical value is the From-URI
+			domain (i.e., $fd).
+			</para>
+			<para>
+			The string may contain pseudo variables.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title>autheph_proxy usage</title>
+		<programlisting format="linespecific">
+...
+if (!autheph_proxy("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section>
+		<title>
+			<function moreinfo="none">autheph_www(realm[, method])</function>
+		</title>
+		<para>This function performs WWW digest authentication.
+		</para>
+		<para>The meaning of the parameters are as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>realm</emphasis> - Realm is an opaque
+			string that the user agent should present to the user so
+			that he can decide what username and password to use.
+			Usually this is domain of the host the server is running
+			on.
+			</para>
+			<para>
+			It must not be an empty string <quote></quote>. Apart
+			from a static string, a typical value is the From-URI
+			domain (i.e., $fd).
+			</para>
+			<para>
+			The string may contain pseudo variables.
+			</para>
+		</listitem>
+		<listitem>
+			<para><emphasis>method</emphasis> - the method to be
+			used for authentication. This parameter is optional and
+			if not set the first "word" on the request-line is used.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title>autheph_www usage</title>
+		<programlisting format="linespecific">
+...
+if (!autheph_www("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...
+</programlisting>
+		</example>
+	</section>
+
+
+	<section>
+		<title>
+			<function moreinfo="none">autheph_check(realm)</function>
+		</title>
+		<para>This function combines the functionalities of
+		<function moreinfo="none">autheph_www</function> and
+		<function moreinfo="none">autheph_proxy</function>, the first
+		being exectuted if the SIP request is a REGISTER, the second for
+		the rest.
+		</para>
+		<para>The meaning of the parameters are as follows:</para>
+		<itemizedlist>
+		<listitem>
+			<para><emphasis>realm</emphasis> - Realm is an opaque
+			string that the user agent should present to the user so
+			that he can decide what username and password to use.
+			Usually this is domain of the host the server is running
+			on.
+			</para>
+			<para>
+			It must not be an empty string <quote></quote>. Apart
+			from a static string, a typical value is the From-URI
+			domain (i.e., $fd).
+			</para>
+			<para>
+			The string may contain pseudo variables.
+			</para>
+		</listitem>
+		</itemizedlist>
+		<para>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+		<example>
+		<title>autheph_check usage</title>
+		<programlisting format="linespecific">
+...
+if (!autheph_check("$fd")) {
+    auth_challenge("$fd", "1");
+    exit;
+}
+...
+</programlisting>
+		</example>
+	</section>
+	</section>
+</chapter>
+