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; }; /*! -- _____________________________________________________________________ -- Bandwidth and Colocation Provided by http://www.api-digital.com -- svn-commits mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/svn-commits