mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
Feature: Allow client altering on auth fail and acl deny
This adds the following tags to the config file below <role>: * <on-failed-action>: Action to take on auth fail * <on-failed-argument>: Argument for action on auth fail * <on-deny-action>: Action to take on acl deny * <on-deny-argument>: Argument for action on acl deny All client alter actions are supported. The corresponding auth does not need to have the permission for those operations. Notes: Likely <on-deny-*> should be moved below <acl>, See: #2351 Closes: #1272
This commit is contained in:
parent
d245b0261b
commit
355d7e976b
@ -594,7 +594,7 @@ void admin_handle_request(client_t *client, const char *uri)
|
||||
"client because it is allowed to do SOURCE or PUT.");
|
||||
} else {
|
||||
ICECAST_LOG_DEBUG("Client needs to authenticate.");
|
||||
client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE);
|
||||
auth_reject_client_on_deny(client);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
90
src/auth.c
90
src/auth.c
@ -212,6 +212,10 @@ void auth_release (auth_t *authenticator) {
|
||||
xmlFree (authenticator->role);
|
||||
if (authenticator->management_url)
|
||||
xmlFree (authenticator->management_url);
|
||||
if (authenticator->failed_arg)
|
||||
xmlFree (authenticator->failed_arg);
|
||||
if (authenticator->deny_arg)
|
||||
xmlFree (authenticator->deny_arg);
|
||||
thread_mutex_unlock(&authenticator->lock);
|
||||
thread_mutex_destroy(&authenticator->lock);
|
||||
if (authenticator->mount)
|
||||
@ -311,23 +315,18 @@ static auth_result auth_remove_client(auth_t *auth, auth_client *auth_user)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int __handle_auth_client_alter(auth_t *auth, auth_client *auth_user)
|
||||
static inline int __handle_auth_client_alter(client_t *client, auth_alter_t action, const char *arg)
|
||||
{
|
||||
client_t *client = auth_user->client;
|
||||
const char *uuid = NULL;
|
||||
const char *location = NULL;
|
||||
int http_status = 0;
|
||||
|
||||
void client_send_redirect(client_t *client, const char *uuid, int status, const char *location);
|
||||
|
||||
switch (auth_user->alter_client_action) {
|
||||
switch (action) {
|
||||
case AUTH_ALTER_NOOP:
|
||||
return 0;
|
||||
break;
|
||||
case AUTH_ALTER_REWRITE:
|
||||
free(client->uri);
|
||||
client->uri = auth_user->alter_client_arg;
|
||||
auth_user->alter_client_arg = NULL;
|
||||
util_replace_string(&(client->uri), arg);
|
||||
return 0;
|
||||
break;
|
||||
case AUTH_ALTER_REDIRECT:
|
||||
@ -335,20 +334,20 @@ static inline int __handle_auth_client_alter(auth_t *auth, auth_client *auth_use
|
||||
case AUTH_ALTER_REDIRECT_SEE_OTHER:
|
||||
uuid = "be7fac90-54fb-4673-9e0d-d15d6a4963a2";
|
||||
http_status = 303;
|
||||
location = auth_user->alter_client_arg;
|
||||
location = arg;
|
||||
break;
|
||||
case AUTH_ALTER_REDIRECT_TEMPORARY:
|
||||
uuid = "4b08a03a-ecce-4981-badf-26b0bb6c9d9c";
|
||||
http_status = 307;
|
||||
location = auth_user->alter_client_arg;
|
||||
location = arg;
|
||||
break;
|
||||
case AUTH_ALTER_REDIRECT_PERMANENT:
|
||||
uuid = "36bf6815-95cb-4cc8-a7b0-6b4b0c82ac5d";
|
||||
http_status = 308;
|
||||
location = auth_user->alter_client_arg;
|
||||
location = arg;
|
||||
break;
|
||||
case AUTH_ALTER_SEND_ERROR:
|
||||
client_send_error_by_uuid(client, auth_user->alter_client_arg);
|
||||
client_send_error_by_uuid(client, arg);
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
@ -360,6 +359,7 @@ static inline int __handle_auth_client_alter(auth_t *auth, auth_client *auth_use
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void __handle_auth_client (auth_t *auth, auth_client *auth_user) {
|
||||
auth_result result;
|
||||
|
||||
@ -381,7 +381,7 @@ static void __handle_auth_client (auth_t *auth, auth_client *auth_user) {
|
||||
}
|
||||
|
||||
if (result != AUTH_NOMATCH) {
|
||||
if (__handle_auth_client_alter(auth, auth_user) == 1)
|
||||
if (__handle_auth_client_alter(auth_user->client, auth_user->alter_client_action, auth_user->alter_client_arg) == 1)
|
||||
return;
|
||||
}
|
||||
|
||||
@ -817,6 +817,8 @@ auth_t *auth_get_authenticator(xmlNodePtr node)
|
||||
auth->management_url = (char*)xmlGetProp(node, XMLSTR("management-url"));
|
||||
auth->filter_web_policy = AUTH_MATCHTYPE_MATCH;
|
||||
auth->filter_admin_policy = AUTH_MATCHTYPE_MATCH;
|
||||
auth->failed_arg = AUTH_ALTER_NOOP;
|
||||
auth->deny_arg = AUTH_ALTER_NOOP;
|
||||
|
||||
for (i = 0; i < (sizeof(auth->filter_admin)/sizeof(*(auth->filter_admin))); i++) {
|
||||
auth->filter_admin[i].type = AUTH_MATCHTYPE_UNUSED;
|
||||
@ -936,6 +938,32 @@ auth_t *auth_get_authenticator(xmlNodePtr node)
|
||||
} else {
|
||||
ICECAST_LOG_ERROR("More than one ACL defined in role! Not supported (yet).");
|
||||
}
|
||||
} else if (xmlStrcmp (child->name, XMLSTR("on-failed-action")) == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(child->doc, child->xmlChildrenNode, 1);
|
||||
if (tmp) {
|
||||
auth->failed_action = auth_str2alter(tmp);
|
||||
if (auth->failed_action == AUTH_ALTER_NOOP) {
|
||||
ICECAST_LOG_WARN("Can not parse <on-failed-action> with value: %s", tmp);
|
||||
}
|
||||
xmlFree(tmp);
|
||||
}
|
||||
} else if (xmlStrcmp (child->name, XMLSTR("on-failed-argument")) == 0) {
|
||||
if (auth->failed_arg)
|
||||
xmlFree(auth->failed_arg);
|
||||
auth->failed_arg = (char *)xmlNodeListGetString(child->doc, child->xmlChildrenNode, 1);
|
||||
} else if (xmlStrcmp (child->name, XMLSTR("on-deny-action")) == 0) {
|
||||
tmp = (char *)xmlNodeListGetString(child->doc, child->xmlChildrenNode, 1);
|
||||
if (tmp) {
|
||||
auth->deny_action = auth_str2alter(tmp);
|
||||
if (auth->deny_action == AUTH_ALTER_NOOP) {
|
||||
ICECAST_LOG_WARN("Can not parse <on-deny-action> with value: %s", tmp);
|
||||
}
|
||||
xmlFree(tmp);
|
||||
}
|
||||
} else if (xmlStrcmp (child->name, XMLSTR("on-deny-argument")) == 0) {
|
||||
if (auth->deny_arg)
|
||||
xmlFree(auth->deny_arg);
|
||||
auth->deny_arg = (char *)xmlNodeListGetString(child->doc, child->xmlChildrenNode, 1);
|
||||
} else {
|
||||
ICECAST_LOG_WARN("unknown auth setting (%H)", child->name);
|
||||
}
|
||||
@ -1213,3 +1241,39 @@ acl_t *auth_stack_get_anonymous_acl(auth_stack_t *stack, httpp_request_ty
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void auth_reject_client(client_t *client, int fail)
|
||||
{
|
||||
auth_t *auth;
|
||||
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
auth = client->auth;
|
||||
if (auth) {
|
||||
if (fail) {
|
||||
if (__handle_auth_client_alter(client, auth->failed_action, auth->failed_arg) == 1)
|
||||
return;
|
||||
} else {
|
||||
if (__handle_auth_client_alter(client, auth->deny_action, auth->deny_arg) == 1)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (client->protocol == ICECAST_PROTOCOL_SHOUTCAST) {
|
||||
client_destroy(client);
|
||||
} else {
|
||||
client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE);
|
||||
}
|
||||
}
|
||||
|
||||
void auth_reject_client_on_fail(client_t *client)
|
||||
{
|
||||
auth_reject_client(client, 1);
|
||||
}
|
||||
|
||||
void auth_reject_client_on_deny(client_t *client)
|
||||
{
|
||||
auth_reject_client(client, 0);
|
||||
}
|
||||
|
12
src/auth.h
12
src/auth.h
@ -124,6 +124,14 @@ struct auth_tag
|
||||
size_t filter_origin_len;
|
||||
auth_matchtype_t filter_origin_policy;
|
||||
|
||||
/* Action on failed if any */
|
||||
auth_alter_t failed_action;
|
||||
char *failed_arg;
|
||||
|
||||
/* Action on deny if any */
|
||||
auth_alter_t deny_action;
|
||||
char *deny_arg;
|
||||
|
||||
/* permissions */
|
||||
auth_matchtype_t permission_alter[AUTH_ALTER_SEND_ERROR+1];
|
||||
|
||||
@ -203,4 +211,8 @@ auth_t *auth_stack_get(auth_stack_t *stack);
|
||||
auth_t *auth_stack_getbyid(auth_stack_t *stack, unsigned long id);
|
||||
acl_t *auth_stack_get_anonymous_acl(auth_stack_t *stack, httpp_request_type_e method);
|
||||
|
||||
/* Rejects a client based on auth results. */
|
||||
void auth_reject_client_on_fail(client_t *client);
|
||||
void auth_reject_client_on_deny(client_t *client);
|
||||
|
||||
#endif
|
||||
|
@ -1030,11 +1030,7 @@ static void _handle_get_request(client_t *client) {
|
||||
/* this is a web/ request. let's check if we are allowed to do that. */
|
||||
if (acl_test_web(client->acl) != ACL_POLICY_ALLOW) {
|
||||
/* doesn't seem so, sad client :( */
|
||||
if (client->protocol == ICECAST_PROTOCOL_SHOUTCAST) {
|
||||
client_destroy(client);
|
||||
} else {
|
||||
client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE);
|
||||
}
|
||||
auth_reject_client_on_deny(client);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1334,13 +1330,13 @@ static void _handle_authed_client(client_t *client, void *userdata, auth_result
|
||||
fastevent_emit(FASTEVENT_TYPE_CLIENT_AUTHED, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
|
||||
|
||||
if (result != AUTH_OK) {
|
||||
client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE);
|
||||
auth_reject_client_on_fail(client);
|
||||
return;
|
||||
}
|
||||
|
||||
if (acl_test_method(client->acl, client->parser->req_type) != ACL_POLICY_ALLOW) {
|
||||
ICECAST_LOG_ERROR("Client (role=%s, acl=%s, username=%s) not allowed to use this request method on %H", client->role, acl_get_name(client->acl), client->username, client->uri);
|
||||
client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE);
|
||||
auth_reject_client_on_deny(client);
|
||||
return;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user