[asterisk-commits] dlee: branch dlee/ari-authn r393061 - in /team/dlee/ari-authn: configs/ main/...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Jun 27 13:59:08 CDT 2013
Author: dlee
Date: Thu Jun 27 13:59:06 2013
New Revision: 393061
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=393061
Log:
Clean ups; removed allow_api_key option, because it was silly to have in the first place
Modified:
team/dlee/ari-authn/configs/stasis_http.conf.sample
team/dlee/ari-authn/main/features_config.c
team/dlee/ari-authn/main/http.c
team/dlee/ari-authn/res/res_stasis_http.c
team/dlee/ari-authn/res/stasis_http/cli.c
team/dlee/ari-authn/res/stasis_http/config.c
team/dlee/ari-authn/res/stasis_http/internal.h
Modified: team/dlee/ari-authn/configs/stasis_http.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/configs/stasis_http.conf.sample?view=diff&rev=393061&r1=393060&r2=393061
==============================================================================
--- team/dlee/ari-authn/configs/stasis_http.conf.sample (original)
+++ team/dlee/ari-authn/configs/stasis_http.conf.sample Thu Jun 27 13:59:06 2013
@@ -12,9 +12,6 @@
;read_only = no ; When set to yes, user is only authorized for
; ; read-only requests.
;
-;allow_api_key = no ; When set to yes, user may authenticate by appending
-; ; ?api_key=username:password to their requests.
-;
;password = ; Crypted or plaintext password (see password_format).
;
; password_format may be set to plain (the default) or crypt. When set to crypt,
Modified: team/dlee/ari-authn/main/features_config.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/main/features_config.c?view=diff&rev=393061&r1=393060&r2=393061
==============================================================================
--- team/dlee/ari-authn/main/features_config.c (original)
+++ team/dlee/ari-authn/main/features_config.c Thu Jun 27 13:59:06 2013
@@ -1792,26 +1792,23 @@
ast_custom_function_unregister(&featuremap_function);
ast_custom_function_unregister(&feature_function);
ast_cli_unregister_multiple(cli_features_config, ARRAY_LEN(cli_features_config));
- //aco_info_destroy(&cfg_info);
+ aco_info_destroy(&cfg_info);
ao2_global_obj_release(globals);
}
int ast_features_config_reload(void)
{
- //if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
- // return -1;
- //}
+ if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
+ return -1;
+ }
return 0;
}
-static int (*nowarn)(void);
-
int ast_features_config_init(void)
{
- int res = 0;
-
- //res = load_config();
- nowarn = load_config;
+ int res;
+
+ res = load_config();
res |= __ast_custom_function_register(&feature_function, NULL);
res |= __ast_custom_function_register(&featuremap_function, NULL);
res |= ast_cli_register_multiple(cli_features_config, ARRAY_LEN(cli_features_config));
Modified: team/dlee/ari-authn/main/http.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/main/http.c?view=diff&rev=393061&r1=393060&r2=393061
==============================================================================
--- team/dlee/ari-authn/main/http.c (original)
+++ team/dlee/ari-authn/main/http.c Thu Jun 27 13:59:06 2013
@@ -900,7 +900,8 @@
return auth;
}
-#define BASIC_LEN 6 /*!< "Basic " */
+#define BASIC_PREFIX "Basic "
+#define BASIC_LEN 6 /*!< strlen(BASIC_PREFIX) */
struct ast_http_auth *ast_http_get_auth(struct ast_variable *headers)
{
@@ -908,7 +909,7 @@
for (v = headers; v; v = v->next) {
const char *base64;
- char decoded[256];
+ char decoded[256] = {};
int cnt;
char *colon;
@@ -916,18 +917,30 @@
continue;
}
- if (strncasecmp("Basic ", v->value, BASIC_LEN) != 0) {
- ast_log(LOG_WARNING, "Unsuppored Authorization scheme\n");
+ if (!ast_begins_with(v->value, BASIC_PREFIX)) {
+ ast_log(LOG_DEBUG,
+ "Unsupported Authorization scheme\n");
continue;
}
+ /* Basic auth header parsing. RFC 2617, section 2.
+ * credentials = "Basic" basic-credentials
+ * basic-credentials = base64-user-pass
+ * base64-user-pass = <base64 encoding of user-pass,
+ * except not limited to 76 char/line>
+ * user-pass = userid ":" password
+ */
+
base64 = v->value + BASIC_LEN;
+ /* This will truncate "userid:password" lines to
+ * sizeof(decoded). The array is long enough that this shouldn't
+ * be a problem */
cnt = ast_base64decode((unsigned char*)decoded, base64,
sizeof(decoded) - 1);
ast_assert(cnt < sizeof(decoded));
- decoded[cnt] = '\0';
-
+
+ /* Split the string at the colon */
colon = strchr(decoded, ':');
if (!colon) {
ast_log(LOG_WARNING, "Invalid Authorization header\n");
Modified: team/dlee/ari-authn/res/res_stasis_http.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/res/res_stasis_http.c?view=diff&rev=393061&r1=393060&r2=393061
==============================================================================
--- team/dlee/ari-authn/res/res_stasis_http.c (original)
+++ team/dlee/ari-authn/res/res_stasis_http.c Thu Jun 27 13:59:06 2013
@@ -97,9 +97,6 @@
<configOption name="read_only">
<synopsis>When set to yes, user is only authorized for read-only requests</synopsis>
</configOption>
- <configOption name="allow_api_key">
- <synopsis>When set to yes, user may authenticate by appending ?api_key=username+password to their requests.</synopsis>
- </configOption>
<configOption name="password">
<synopsis>Crypted or plaintext password (see password_format)</synopsis>
</configOption>
@@ -129,13 +126,7 @@
static int is_enabled(void)
{
RAII_VAR(struct ari_conf *, cfg, ari_config_get(), ao2_cleanup);
- return cfg->general->enabled;
-}
-
-static enum ast_json_encoding_format json_format(void)
-{
- RAII_VAR(struct ari_conf *, cfg, ari_config_get(), ao2_cleanup);
- return cfg->general->format;
+ return cfg && cfg->general && cfg->general->enabled;
}
/*! Lock for \ref root_handler */
@@ -700,6 +691,37 @@
}
/*!
+ * \brief Authenticate a <code>?api_key=userid:password</code>
+ *
+ * \param api_key API key query parameter
+ * \return User object for the authenticated user.
+ * \return \c NULL if authentication failed.
+ */
+static struct ari_conf_user *authenticate_api_key(const char *api_key)
+{
+ RAII_VAR(char *, username, NULL, ast_free);
+ RAII_VAR(struct ari_conf_user *, user, NULL, ao2_cleanup);
+ char *colon;
+
+ username = ast_strdup(api_key);
+ if (!username) {
+ return NULL;
+ }
+
+ /* Split the string */
+ colon = strchr(username, ':');
+ if (!colon) {
+ return NULL;
+ }
+ *colon = '\0';
+
+ user = ari_config_validate_user(username, colon + 1);
+
+ ao2_ref(user, +1);
+ return user;
+}
+
+/*!
* \brief Authenticate an HTTP request.
*
* \param get_params GET parameters of the request.
@@ -723,21 +745,7 @@
/* ?api_key authentication */
for (v = get_params; v; v = v->next) {
if (strcasecmp("api_key", v->name) == 0) {
- RAII_VAR(char *, username, NULL, ast_free);
- char *colon;
-
- username = ast_strdup(v->value);
- if (!username) {
- return NULL;
- }
-
- colon = strchr(username, ':');
- if (!colon) {
- return NULL;
- }
-
- *colon = '\0';
- return ari_config_validate_user(username, colon + 1);
+ return authenticate_api_key(v->value);
}
}
@@ -782,7 +790,7 @@
}
conf = ari_config_get();
- if (!conf) {
+ if (!conf || !conf->general) {
return -1;
}
@@ -790,13 +798,26 @@
user = authenticate_user(get_params, headers);
if (!user) {
- response.message = ast_json_pack("{s: s}",
- "error", "Authentication required");
+ /* Per RFC 2617, section 1.2: The 401 (Unauthorized) response
+ * message is used by an origin server to challenge the
+ * authorization of a user agent. This response MUST include a
+ * WWW-Authenticate header field containing at least one
+ * challenge applicable to the requested resource.
+ */
response.response_code = 401;
response.response_text = "Unauthorized";
+
+ /* Section 1.2:
+ * realm = "realm" "=" realm-value
+ * realm-value = quoted-string
+ * Section 2:
+ * challenge = "Basic" realm
+ */
ast_str_append(&response.headers, 0,
"WWW-Authenticate: Basic realm=\"%s\"\r\n",
conf->general->auth_realm);
+ response.message = ast_json_pack("{s: s}",
+ "error", "Authentication required");
} else if (user->read_only && method != AST_HTTP_GET && method != AST_HTTP_OPTIONS) {
response.message = ast_json_pack("{s: s}",
"error", "Write access denied");
@@ -837,7 +858,7 @@
ast_str_append(&response_headers, 0,
"Content-type: application/json\r\n");
if (ast_json_dump_str_format(response.message, &response_body,
- json_format()) != 0) {
+ conf->general->format) != 0) {
/* Error encoding response */
response.response_code = 500;
response.response_text = "Internal Server Error";
Modified: team/dlee/ari-authn/res/stasis_http/cli.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/res/stasis_http/cli.c?view=diff&rev=393061&r1=393060&r2=393061
==============================================================================
--- team/dlee/ari-authn/res/stasis_http/cli.c (original)
+++ team/dlee/ari-authn/res/stasis_http/cli.c Thu Jun 27 13:59:06 2013
@@ -80,9 +80,8 @@
struct ari_conf_user *user = obj;
struct ast_cli_args *a = arg;
- ast_cli(a->fd, "%-*s %-*s %s\n",
- 4, AST_CLI_YESNO(user->read_only),
- 7, AST_CLI_YESNO(user->allow_api_key),
+ ast_cli(a->fd, "%-4s %s\n",
+ AST_CLI_YESNO(user->read_only),
user->username);
return 0;
}
@@ -115,8 +114,8 @@
return CLI_FAILURE;
}
- ast_cli(a->fd, "r/o? API key Username\n");
- ast_cli(a->fd, "---- ------- --------\n");
+ ast_cli(a->fd, "r/o? Username\n");
+ ast_cli(a->fd, "---- --------\n");
ao2_callback(conf->users, OBJ_NODATA, show_users_cb, a);
@@ -208,8 +207,6 @@
ast_cli(a->fd, "Username: %s\n", user->username);
ast_cli(a->fd, "Read only?: %s\n", AST_CLI_YESNO(user->read_only));
- ast_cli(a->fd, "Allow api_key?: %s\n",
- AST_CLI_YESNO(user->allow_api_key));
return CLI_SUCCESS;
}
@@ -241,6 +238,8 @@
return CLI_FAILURE;
}
+ ast_cli(a->fd,
+ "; Copy the following two lines into stasis_http.conf\n");
ast_cli(a->fd, "password_format = crypt\n");
ast_cli(a->fd, "password = %s\n", crypted);
Modified: team/dlee/ari-authn/res/stasis_http/config.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/res/stasis_http/config.c?view=diff&rev=393061&r1=393060&r2=393061
==============================================================================
--- team/dlee/ari-authn/res/stasis_http/config.c (original)
+++ team/dlee/ari-authn/res/stasis_http/config.c Thu Jun 27 13:59:06 2013
@@ -77,6 +77,7 @@
return 0;
}
+/*! \brief Destructor for \ref ari_conf_user */
static void user_dtor(void *obj)
{
struct ari_conf_user *user = obj;
@@ -84,10 +85,17 @@
ast_free(user->username);
}
+/*! \brief Allocate an \ref ari_conf_user for config parsing */
static void *user_alloc(const char *cat)
{
RAII_VAR(struct ari_conf_user *, user, NULL, ao2_cleanup);
- const char *username = strchr(cat, '-') + 1;
+ const char *username;
+
+ if (!cat) {
+ return NULL;
+ }
+
+ username = strchr(cat, '-') + 1;
if (!username) {
ast_log(LOG_ERROR, "Invalid user category '%s'\n", cat);
@@ -110,6 +118,7 @@
return user;
}
+/*! \brief Sorting function for use with red/black tree */
static int user_sort_cmp(const void *obj_left, const void *obj_right, int flags)
{
const struct ari_conf_user *user_left = obj_left;
@@ -128,10 +137,17 @@
}
}
-static void *user_find(struct ao2_container *tmp_container,
- const char *category)
-{
- return ao2_find(tmp_container, category, OBJ_KEY);
+/*! \brief \ref aco_type item_find function */
+static void *user_find(struct ao2_container *tmp_container, const char *cat)
+{
+ const char *username;
+
+ if (!cat) {
+ return NULL;
+ }
+
+ username = strchr(cat, '-') + 1;
+ return ao2_find(tmp_container, username, OBJ_KEY);
}
static struct aco_type user_option = {
@@ -146,7 +162,7 @@
static struct aco_type *user[] = ACO_TYPES(&user_option);
-/*! \brief Disposes of the stasis http conf object */
+/*! \brief \ref ari_conf destructor. */
static void conf_destructor(void *obj)
{
struct ari_conf *cfg = obj;
@@ -154,7 +170,7 @@
ao2_cleanup(cfg->users);
}
-/*! \brief Creates the statis http conf object. */
+/*! \brief Allocate an \ref ari_conf for config parsing */
static void *conf_alloc(void)
{
RAII_VAR(struct ari_conf *, cfg, NULL, ao2_cleanup);
@@ -189,7 +205,11 @@
struct ari_conf *ari_config_get(void)
{
- return ao2_global_obj_ref(confs);
+ struct ari_conf *res = ao2_global_obj_ref(confs);
+ if (!res) {
+ ast_log(LOG_ERROR, "Error accessing configuration\n");
+ }
+ return res;
}
struct ari_conf_user *ari_config_validate_user(const char *username,
@@ -233,7 +253,8 @@
return user;
}
-static int check_passwords_cb(void *obj, void *arg, int flags)
+/*! \brief Callback to validate a user object */
+static int validate_user_cb(void *obj, void *arg, int flags)
{
struct ari_conf_user *user = obj;
@@ -245,6 +266,7 @@
return 0;
}
+/*! \brief Load (or reload) configuration. */
static int process_config(int reload)
{
RAII_VAR(struct ari_conf *, conf, NULL, ao2_cleanup);
@@ -267,7 +289,7 @@
ast_log(LOG_ERROR, "No configured users for ARI\n");
}
- ao2_callback(conf->users, OBJ_NODATA, check_passwords_cb, NULL);
+ ao2_callback(conf->users, OBJ_NODATA, validate_user_cb, NULL);
return 0;
}
@@ -292,9 +314,6 @@
aco_option_register(&cfg_info, "read_only", ACO_EXACT, user,
"no", OPT_BOOL_T, 1,
FLDSET(struct ari_conf_user, read_only));
- aco_option_register(&cfg_info, "allow_api_key", ACO_EXACT, user,
- "no", OPT_BOOL_T, 1,
- FLDSET(struct ari_conf_user, allow_api_key));
aco_option_register(&cfg_info, "password", ACO_EXACT, user,
"", OPT_CHAR_ARRAY_T, 0,
FLDSET(struct ari_conf_user, password), ARI_PASSWORD_LEN);
Modified: team/dlee/ari-authn/res/stasis_http/internal.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/res/stasis_http/internal.h?view=diff&rev=393061&r1=393060&r2=393061
==============================================================================
--- team/dlee/ari-authn/res/stasis_http/internal.h (original)
+++ team/dlee/ari-authn/res/stasis_http/internal.h Thu Jun 27 13:59:06 2013
@@ -94,8 +94,6 @@
enum ari_password_format password_format;
/*! If true, user cannot execute change operations */
int read_only;
- /*! If true, user allowed to authenticate with ?api_key=user+password */
- int allow_api_key;
};
/*!
More information about the asterisk-commits
mailing list