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 redefine
make, make,
filters, filters,
setup_hooks setup_hooks,
install,
permissions
end end
CMS_WITH_WEBAPI CMS_WITH_WEBAPI
@@ -35,6 +37,17 @@ feature {NONE} -- Initialization
description := "Service to manage basic authentication" description := "Service to manage basic authentication"
end 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 feature {CMS_EXECUTION} -- Administration
webapi: CMS_BASIC_AUTH_MODULE_WEBAPI webapi: CMS_BASIC_AUTH_MODULE_WEBAPI
@@ -46,6 +59,15 @@ feature -- Access
name: STRING = "basic_auth" 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 feature -- Access: auth strategy
login_title: STRING = "Basic Auth" login_title: STRING = "Basic Auth"

View File

@@ -28,7 +28,7 @@ feature -- Access: filter
-- Possibly list of Filter's module. -- Possibly list of Filter's module.
do do
create {ARRAYED_LIST [WSF_FILTER]} Result.make (1) 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 end
note note
copyright: "2011-2017, Jocelyn Fiat, Javier Velilla, Eiffel Software and others" 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 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 attached api.user_api.user_by_name (l_auth_login) as l_user
then then
if api.user_has_permission (l_user, {CMS_BASIC_AUTH_MODULE}.perm_use_basic_auth) then
debug ("refactor_fixme") debug ("refactor_fixme")
fixme ("Maybe we need to store in the credentials in a shared context SECURITY_CONTEXT") 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)) -- req.set_execution_variable ("security_content", create SECURITY_CONTEXT.make (l_user))
-- other authentication filters (OpenID, etc) should implement the same approach. -- other authentication filters (OpenID, etc) should implement the same approach.
end end
set_current_user (l_user) set_current_user (l_user)
end
else else
api.logger.put_error (generator + ".execute login_valid failed for: " + l_auth_login, Void) api.logger.put_error (generator + ".execute login_valid failed for: " + l_auth_login, Void)
end end

View File

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

View File

@@ -247,9 +247,9 @@ feature -- Status report
do do
if a_permission = Void then if a_permission = Void then
Result := True Result := True
elseif a_user = Void then
Result := user_role_has_permission (anonymous_user_role, a_permission)
else else
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 if is_admin_user (a_user) then
Result := True Result := True
else else
@@ -260,6 +260,7 @@ feature -- Status report
end end
end end
end end
end
is_admin_user (u: CMS_USER): BOOLEAN is_admin_user (u: CMS_USER): BOOLEAN
do do

View File

@@ -51,7 +51,7 @@ feature -- Request execution
do do
if attached user_by_uid (a_uid) as l_user then if attached user_by_uid (a_uid) as l_user then
if attached api.user as u 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) rep := new_access_token_response (l_user, user_access_token (l_user), req, res)
if attached {WSF_STRING} req.item ("destination") as dest then if attached {WSF_STRING} req.item ("destination") as dest then
rep.set_redirection (dest.url_encoded_value) rep.set_redirection (dest.url_encoded_value)
@@ -77,18 +77,13 @@ feature -- Request execution
do do
if attached user_by_uid (a_uid) as l_user then if attached user_by_uid (a_uid) as l_user then
if attached api.user as u 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 if attached req.path_parameter ("application") then
end end
-- l_access_token := user_access_token (l_user)
l_access_token := new_key (40) 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) set_user_access_token (l_user, l_access_token)
rep := new_access_token_response (l_user, l_access_token, req, res) rep := new_access_token_response (l_user, l_access_token, req, res)

View File

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

View File

@@ -14,12 +14,25 @@ inherit
create create
make make
feature -- Access
router: detachable WSF_ROUTER
feature -- Element change
set_router (a_router: like router)
do
router := a_router
end
feature -- Execution feature -- Execution
execute (req: WSF_REQUEST; res: WSF_RESPONSE) execute (req: WSF_REQUEST; res: WSF_RESPONSE)
-- Execute handler for `req' and respond in `res'. -- Execute handler for `req' and respond in `res'.
local local
rep: HM_WEBAPI_RESPONSE rep: HM_WEBAPI_RESPONSE
vis: WSF_ROUTER_AGENT_ITERATOR
j: JSON_ARRAY
do do
rep := new_response (req, res) rep := new_response (req, res)
rep.add_string_field ("site_name", api.setup.site_name) rep.add_string_field ("site_name", api.setup.site_name)
@@ -28,6 +41,44 @@ feature -- Execution
elseif api.has_permission ("account register") then elseif api.has_permission ("account register") then
rep.add_link ("register", Void, api.webapi_path ("/account/register")) rep.add_link ("register", Void, api.webapi_path ("/account/register"))
end 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.add_self (req.percent_encoded_path_info)
rep.execute rep.execute
end end

View File

@@ -41,6 +41,10 @@ feature -- Execution
else else
l_user := api.user_api.user_by_name (p_uid.value) l_user := api.user_api.user_by_name (p_uid.value)
end end
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 -- if l_user = Void and p_uid.is_case_insensitive_equal ("me") then
-- l_user := u -- l_user := u
-- end -- end
@@ -73,10 +77,6 @@ feature -- Execution
rep := new_error_response ("Not found", req, res) rep := new_error_response ("Not found", req, res)
rep.set_status_code ({HTTP_STATUS_CODE}.not_found) rep.set_status_code ({HTTP_STATUS_CODE}.not_found)
end end
else
rep := new_error_response ("Bad request", req, res)
rep.set_status_code ({HTTP_STATUS_CODE}.bad_request)
end
else else
-- FIXME: use specific Web API response! -- FIXME: use specific Web API response!
rep := new_access_denied_error_response (Void, req, res) rep := new_access_denied_error_response (Void, req, res)

View File

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