Fix authenticated role permissions, now it also has all anonymous permissions.

Added permissions on basic auth, to have more control on who can authenticate with basic auth.
Use webapi version of basic auth filter.
For webapi, when authenticated /api/user/ is the same as /api/user/{uid} where uid is the id of current logged in user.
This commit is contained in:
Jocelyn Fiat
2017-09-21 12:49:17 +02:00
parent 9d7d43073d
commit bc561b1a48
10 changed files with 135 additions and 61 deletions

View File

@@ -16,7 +16,9 @@ inherit
redefine
make,
filters,
setup_hooks
setup_hooks,
install,
permissions
end
CMS_WITH_WEBAPI
@@ -35,6 +37,17 @@ feature {NONE} -- Initialization
description := "Service to manage basic authentication"
end
feature {CMS_API} -- Module management
install (a_api: CMS_API)
do
Precursor (a_api)
if attached a_api.user_api.anonymous_user_role as ano then
ano.add_permission (perm_use_basic_auth)
a_api.user_api.save_user_role (ano)
end
end
feature {CMS_EXECUTION} -- Administration
webapi: CMS_BASIC_AUTH_MODULE_WEBAPI
@@ -46,6 +59,15 @@ feature -- Access
name: STRING = "basic_auth"
permissions: LIST [READABLE_STRING_8]
-- List of permission ids, used by this module, and declared.
do
Result := Precursor
Result.force ("use basic_auth")
end
perm_use_basic_auth: STRING = "use basic_auth"
feature -- Access: auth strategy
login_title: STRING = "Basic Auth"

View File

@@ -28,7 +28,7 @@ feature -- Access: filter
-- Possibly list of Filter's module.
do
create {ARRAYED_LIST [WSF_FILTER]} Result.make (1)
Result.extend (create {CMS_BASIC_AUTH_FILTER}.make (a_api))
Result.extend (create {CMS_BASIC_WEBAPI_AUTH_FILTER}.make (a_api))
end
note
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others"

View File

@@ -38,12 +38,14 @@ feature -- Basic operations
api.user_api.is_valid_credential (l_auth_login, l_auth_password) and then
attached api.user_api.user_by_name (l_auth_login) as l_user
then
debug ("refactor_fixme")
fixme ("Maybe we need to store in the credentials in a shared context SECURITY_CONTEXT")
-- req.set_execution_variable ("security_content", create SECURITY_CONTEXT.make (l_user))
-- other authentication filters (OpenID, etc) should implement the same approach.
if api.user_has_permission (l_user, {CMS_BASIC_AUTH_MODULE}.perm_use_basic_auth) then
debug ("refactor_fixme")
fixme ("Maybe we need to store in the credentials in a shared context SECURITY_CONTEXT")
-- req.set_execution_variable ("security_content", create SECURITY_CONTEXT.make (l_user))
-- other authentication filters (OpenID, etc) should implement the same approach.
end
set_current_user (l_user)
end
set_current_user (l_user)
else
api.logger.put_error (generator + ".execute login_valid failed for: " + l_auth_login, Void)
end

View File

@@ -29,7 +29,9 @@ feature -- Basic operations
api.user_api.is_valid_credential (l_auth_login, l_auth_password) and then
attached api.user_api.user_by_name (l_auth_login) as l_user
then
api.set_user (l_user)
if api.user_has_permission (l_user, {CMS_BASIC_AUTH_MODULE}.perm_use_basic_auth) then
api.set_user (l_user)
end
else
-- not authenticated due to bad login or password.
end

View File

@@ -247,15 +247,16 @@ feature -- Status report
do
if a_permission = Void then
Result := True
elseif a_user = Void then
Result := user_role_has_permission (anonymous_user_role, a_permission)
else
if is_admin_user (a_user) then
Result := True
else
Result := user_role_has_permission (authenticated_user_role, a_permission)
if not Result then
Result := across user_roles (a_user) as ic some user_role_has_permission (ic.item, a_permission) end
Result := user_role_has_permission (anonymous_user_role, a_permission)
if not Result and a_user /= Void then
if is_admin_user (a_user) then
Result := True
else
Result := user_role_has_permission (authenticated_user_role, a_permission)
if not Result then
Result := across user_roles (a_user) as ic some user_role_has_permission (ic.item, a_permission) end
end
end
end
end

View File

@@ -51,7 +51,7 @@ feature -- Request execution
do
if attached user_by_uid (a_uid) as l_user then
if attached api.user as u then
if u.same_as (l_user) or api.user_api.is_admin_user (u) then
if u.same_as (l_user) and api.has_permission ("use access_token") then
rep := new_access_token_response (l_user, user_access_token (l_user), req, res)
if attached {WSF_STRING} req.item ("destination") as dest then
rep.set_redirection (dest.url_encoded_value)
@@ -77,18 +77,13 @@ feature -- Request execution
do
if attached user_by_uid (a_uid) as l_user then
if attached api.user as u then
if u.same_as (l_user) or api.user_api.is_admin_user (u) then
if
u.same_as (l_user) and api.has_permission ("use access_token")
then
if attached req.path_parameter ("application") then
end
-- l_access_token := user_access_token (l_user)
l_access_token := new_key (40)
-- if l_access_token /= Void then
-- l_access_token := "Updated-" + (create {UUID_GENERATOR}).generate_uuid.out
-- else
-- l_access_token := "New-" + (create {UUID_GENERATOR}).generate_uuid.out
-- end
set_user_access_token (l_user, l_access_token)
rep := new_access_token_response (l_user, l_access_token, req, res)

View File

@@ -1,6 +1,5 @@
note
description: "Summary description for {CMS_CORE_MODULE_WEBAPI}."
author: ""
date: "$Date$"
revision: "$Revision$"
@@ -25,6 +24,7 @@ feature -- Security
Result := Precursor
Result.force ("admin users")
Result.force ("view users")
Result.force ("use access_token")
end
feature {NONE} -- Router/administration
@@ -35,11 +35,13 @@ feature {NONE} -- Router/administration
l_root: CMS_ROOT_WEBAPI_HANDLER
do
create l_root.make (a_api)
l_root.set_router (a_router)
a_router.handle ("", l_root, a_router.methods_get)
a_router.handle ("/", l_root, a_router.methods_get)
a_router.handle ("/user/{uid}/access_token", create {CMS_ACCESS_TOKEN_WEBAPI_HANDLER}.make (a_api), a_router.methods_get_post)
a_router.handle ("/user/{uid}", create {CMS_USER_WEBAPI_HANDLER}.make (a_api), a_router.methods_get)
a_router.handle ("/user/", create {CMS_USERS_WEBAPI_HANDLER}.make (a_api), a_router.methods_get_post)
a_router.handle ("/user/", create {CMS_USER_WEBAPI_HANDLER}.make (a_api), a_router.methods_get)
a_router.handle ("/users/", create {CMS_USERS_WEBAPI_HANDLER}.make (a_api), a_router.methods_get_post)
end
feature -- Access: filter
@@ -49,7 +51,6 @@ feature -- Access: filter
do
create {ARRAYED_LIST [WSF_FILTER]} Result.make (2)
Result.extend (create {CMS_ACCESS_TOKEN_WEBAPI_AUTH_FILTER}.make (a_api))
Result.extend (create {CMS_BASIC_WEBAPI_AUTH_FILTER}.make (a_api))
end
note

View File

@@ -14,12 +14,25 @@ inherit
create
make
feature -- Access
router: detachable WSF_ROUTER
feature -- Element change
set_router (a_router: like router)
do
router := a_router
end
feature -- Execution
execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute handler for `req' and respond in `res'.
local
rep: HM_WEBAPI_RESPONSE
vis: WSF_ROUTER_AGENT_ITERATOR
j: JSON_ARRAY
do
rep := new_response (req, res)
rep.add_string_field ("site_name", api.setup.site_name)
@@ -28,6 +41,44 @@ feature -- Execution
elseif api.has_permission ("account register") then
rep.add_link ("register", Void, api.webapi_path ("/account/register"))
end
-- If query has "router=yes", display basic information about router mapping.
-- Note: this may change in the future
if
attached router as l_router and then
attached req.query_parameter ("router") as p_router and then
p_router.same_string ("yes")
then
create j.make_empty
create vis
vis.on_item_actions.extend (agent (i_item: WSF_ROUTER_ITEM; i_json: JSON_ARRAY)
local
jo: JSON_OBJECT
s: STRING
do
create jo.make_with_capacity (3)
jo.put_string (i_item.mapping.associated_resource, "resource")
create s.make_empty
if attached i_item.request_methods as methds and then not methds.is_empty then
across
methds as ic
loop
if not s.is_empty then
s.extend (',')
end
s.append (ic.item)
end
jo.put_string (s, "request_methods")
else
s.append ("*")
end
jo.put_string (i_item.mapping.description, "description")
i_json.extend (jo)
end(?, j))
vis.process_router (l_router)
rep.add_string_field ("routing", j.representation)
end
rep.add_self (req.percent_encoded_path_info)
rep.execute
end

View File

@@ -41,41 +41,41 @@ feature -- Execution
else
l_user := api.user_api.user_by_name (p_uid.value)
end
-- if l_user = Void and p_uid.is_case_insensitive_equal ("me") then
-- l_user := u
-- end
if l_user /= Void then
if l_user.same_as (u) or api.has_permissions (<<"admin users", "view users">>) then
rep := new_response (req, res)
rep.add_string_field ("uid", l_user.id.out)
rep.add_string_field ("name", l_user.name)
if attached l_user.email as l_email then
rep.add_string_field ("email", l_email)
end
if not l_user.is_active then
rep.add_boolean_field ("is_active", False)
end
if attached l_user.profile_name as l_profile_name then
rep.add_string_field ("profile_name", l_profile_name)
end
if attached l_user.creation_date as dt then
rep.add_string_field ("creation_date", date_time_to_string (dt))
end
if attached l_user.last_login_date as dt then
rep.add_string_field ("last_login_date", date_time_to_string (dt))
end
add_user_links_to (l_user, rep)
else
rep := new_error_response ("denied", req, res)
rep.set_status_code ({HTTP_STATUS_CODE}.user_access_denied)
else
-- if uid is not give, use current user if any
l_user := u
end
-- if l_user = Void and p_uid.is_case_insensitive_equal ("me") then
-- l_user := u
-- end
if l_user /= Void then
if l_user.same_as (u) or api.has_permissions (<<"admin users", "view users">>) then
rep := new_response (req, res)
rep.add_string_field ("uid", l_user.id.out)
rep.add_string_field ("name", l_user.name)
if attached l_user.email as l_email then
rep.add_string_field ("email", l_email)
end
if not l_user.is_active then
rep.add_boolean_field ("is_active", False)
end
if attached l_user.profile_name as l_profile_name then
rep.add_string_field ("profile_name", l_profile_name)
end
if attached l_user.creation_date as dt then
rep.add_string_field ("creation_date", date_time_to_string (dt))
end
if attached l_user.last_login_date as dt then
rep.add_string_field ("last_login_date", date_time_to_string (dt))
end
add_user_links_to (l_user, rep)
else
rep := new_error_response ("Not found", req, res)
rep.set_status_code ({HTTP_STATUS_CODE}.not_found)
rep := new_error_response ("denied", req, res)
rep.set_status_code ({HTTP_STATUS_CODE}.user_access_denied)
end
else
rep := new_error_response ("Bad request", req, res)
rep.set_status_code ({HTTP_STATUS_CODE}.bad_request)
rep := new_error_response ("Not found", req, res)
rep.set_status_code ({HTTP_STATUS_CODE}.not_found)
end
else
-- FIXME: use specific Web API response!

View File

@@ -51,13 +51,13 @@ feature {CMS_API, CMS_MODULE_ADMINISTRATION, CMS_MODULE_WEBAPI} -- Access: API
feature -- Status
is_initialized: BOOLEAN
frozen is_initialized: BOOLEAN
-- Is Current module initialized?
do
Result := module.is_initialized
end
is_enabled: BOOLEAN
frozen is_enabled: BOOLEAN
-- Is Current module enabled?
do
Result := module.is_enabled