Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CHEF-1685] WIP - allow org-admins to modify organizations #3927

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def bootstrap
@superuser_authz_id = create_actor_in_authz(bifrost_superuser_id)
users_authz_id = create_container_in_authz(superuser_authz_id)
orgs_authz_id = create_container_in_authz(superuser_authz_id)
create_server_admins_global_group_in_bifrost(users_authz_id)
create_server_admins_global_group_in_bifrost(orgs_authz_id, users_authz_id)

# put pivotal in server-admins global group
insert_authz_actor_into_group(server_admins_authz_id, superuser_authz_id)
Expand All @@ -61,13 +61,19 @@ def bootstrap
private

# Create and set up permissions for the server admins group.
def create_server_admins_global_group_in_bifrost(users_authz_id)
def create_server_admins_global_group_in_bifrost(orgs_container_authz_id, users_container_authz_id)
@server_admins_authz_id = create_group_in_authz(bifrost_superuser_id)
%w(create read update delete).each do |permission|
# grant server admins group permission on the users container,
# as the erchef superuser.
grant_authz_object_permission(permission, 'groups', 'containers', users_authz_id,
grant_authz_object_permission(permission, 'groups', 'containers', users_container_authz_id,
server_admins_authz_id, superuser_authz_id)

# grant server admins group permission on the organizations container,
# as the erchef superuser.
grant_authz_object_permission(permission, 'groups', 'containers', orgs_container_authz_id,
server_admins_authz_id, superuser_authz_id)

# grant superuser actor permissions on the server admin group,
# as the bifrost superuser
grant_authz_object_permission(permission, 'actors', 'groups', server_admins_authz_id,
Expand Down
20 changes: 19 additions & 1 deletion src/oc_erchef/apps/oc_chef_wm/src/oc_chef_wm_base.erl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
content_types_provided/2,
finish_request/2,
forbidden/2,
is_authorized_no_membership/2, %% verify request signature only
is_authorized_no_membership/3, %% verify request signature only with custom extractor
is_authorized/2, %% verify request signature and org membership if appropriate
is_authorized/3, %% verify request signature and org membership if appropriate, with custom extractor fun
malformed_request/2, %% verify request headers and size requirements, call module verify_request
Expand Down Expand Up @@ -441,7 +443,23 @@ is_authorized(Req, State, Extractor) ->
end;
{false, ReqOther, StateOther} ->
%% FIXME: the supported version is determined by the chef_authn application
%% also, see: https://wiki.corp.chef.io/display/CORP/RFC+Authentication+Version+Negotiation
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ removed because this link is dead, and I can find no replacement for it in the new wiki.

{"X-Ops-Sign version=\"1.0\" version=\"1.1\"", ReqOther, StateOther};
{{halt, _Code}, _Req, _State} = Halt -> Halt
end.

is_authorized_no_membership(Req, State) ->
is_authorized_no_membership(Req, State, fun authorization_data_extractor/3).

%% Verify request signature but do not verify org membership. Modules
%% can invoke this directly instead of mixing in the default is_verified/2
%% if they rely only on permissions for authorization and not org membership.
-spec is_authorized_no_membership(wm_req(), #base_state{}, extractor()) -> any().
is_authorized_no_membership(Req, State, Extractor) ->
case verify_request_signature(Req, State, Extractor) of
{true, _, _} = Result ->
Result;
{false, ReqOther, StateOther} ->
%% FIXME: the supported version is determined by the chef_authn application
{"X-Ops-Sign version=\"1.0\" version=\"1.1\"", ReqOther, StateOther};
{{halt, _Code}, _Req, _State} = Halt -> Halt
end.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
malformed_request/2,
ping/2,
forbidden/2,
is_authorized/2,
service_available/2]}]).

-export([allowed_methods/2,
Expand All @@ -28,6 +27,7 @@
-export([auth_info/2,
init/1,
init_resource_state/1,
is_authorized/2,
malformed_request_message/3,
request_type/0,
validate_request/3]).
Expand All @@ -47,6 +47,13 @@ request_type() ->
allowed_methods(Req, State) ->
{['GET', 'PUT', 'DELETE'], Req, State}.


is_authorized(Req, State) ->
%% To support management of multi-tenant installations by users w/ appropriate permissions
%% who are not the superuser, the user does not need to be a member of the organization
%% to operate on the organization.
oc_chef_wm_base:is_authorized_no_membership(Req, State).

-spec validate_request(chef_wm:http_verb(), wm_req(), chef_wm:base_state()) ->
{wm_req(), chef_wm:base_state()}.
validate_request(Method, Req, State = #base_state{organization_guid = OrgId}) when Method == 'GET';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
malformed_request/2,
ping/2,
forbidden/2,
is_authorized/2,
service_available/2]}]).

-export([allowed_methods/2,
Expand All @@ -43,6 +42,7 @@
-export([auth_info/2,
init/1,
init_resource_state/1,
is_authorized/2,
malformed_request_message/3,
create_path/2,
request_type/0,
Expand All @@ -67,6 +67,13 @@ allowed_methods(Req, State) ->
end,
{Allowed, Req, State}.

is_authorized(Req, State) ->
% To support management of multi-tenant installations by users w/ appropriate permissions
% who are not superusers, a user with appropriate ACLs does not need to be a member of
% the organization to operate on the organization - that includes the operations of this endpoint,
% CRD against org members.
chef_wm_base:is_authorized_no_membership(Req, State).

-spec validate_request(chef_wm:http_verb(), wm_req(), chef_wm:base_state()) ->
{wm_req(), chef_wm:base_state()}.
validate_request('POST', Req, #base_state{chef_db_context = DbContext} = State) ->
Expand Down Expand Up @@ -117,14 +124,11 @@ auth_info(Req, #base_state{organization_name = OrgName,
auth_info(Req, #base_state{requestor_id = RequestorAuthzId,
organization_authz_id = OrgAuthzId,
resource_state = #association_state{user = User} } = State) ->
case wrq:method(Req) of
'POST' ->
% Only the superuser can force-create an org-user association
{superuser_only, Req, State};
Method ->
{auth_type_for_method(Method, User, OrgAuthzId, RequestorAuthzId), Req, State}
end.
{auth_type_for_method(wrq:method(req), User, OrgAuthzId, RequestorAuthzId), Req, State}.

auth_type_for_method('POST', #chef_user{ authz_id = UserAuthzId }, OrgAuthzId, RequestorAuthzId) ->
%% requestor must have: update permissions in org and read permissions on user
[{object, OrgAuthzId, update}, {actor, UserAuthzId, read}];
auth_type_for_method('DELETE', #chef_user{ authz_id = UserAuthzId }, _OrgAuthzId, UserAuthzId) ->
%% permissions-wise, user can always disassociate his or her own org association
%% though we'll have additional safety checks below as well.
Expand Down
16 changes: 11 additions & 5 deletions src/oc_erchef/habitat/config/chef_server_data_bootstrap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def self.with_connection(database = 'template1', opts = {})
postgres['db_superuser']="{{cfg.sql_user}}"
postgres['db_superuser_password']="{{cfg.sql_password}}"
{{/if}}

connection = nil

# Some callers expect failure - this gives the option to suppress
Expand Down Expand Up @@ -118,7 +118,7 @@ def bootstrap

users_authz_id = create_container_in_authz(superuser_authz_id)
orgs_authz_id = create_container_in_authz(superuser_authz_id)
create_server_admins_global_group_in_bifrost(users_authz_id)
create_server_admins_global_group_in_bifrost(orgs_authz_id, users_authz_id)

# put pivotal in server-admins global group
insert_authz_actor_into_group(server_admins_authz_id, superuser_authz_id)
Expand All @@ -142,13 +142,19 @@ def bootstrap
private

# Create and set up permissions for the server admins group.
def create_server_admins_global_group_in_bifrost(users_authz_id)
def create_server_admins_global_group_in_bifrost(orgs_container_authz_id, users_container_authz_id)
@server_admins_authz_id = create_group_in_authz(bifrost_superuser_id)
%w{create read update delete}.each do |permission|
# grant server admins group permission on the users container,
# as the erchef superuser.
grant_authz_object_permission(permission, "groups", "containers", users_authz_id,
grant_authz_object_permission(permission, "groups", "containers", users_container_authz_id,
server_admins_authz_id, superuser_authz_id)

# grant server admins group permission on the organizations container,
# as the erchef superuser.
grant_authz_object_permission(permission, 'groups', 'containers', orgs_container_authz_id,
server_admins_authz_id, superuser_authz_id)

# grant superuser actor permissions on the server admin group,
# as the bifrost superuser
grant_authz_object_permission(permission, "actors", "groups", server_admins_authz_id,
Expand Down Expand Up @@ -381,7 +387,7 @@ def load_superuser_public_key()
@superuser_public_key = "DUMMY KEY FROM BOOTSTRAP"
{{/if}}
end

def load_bifrost()
bifrost={}
{{#if bind.oc_bifrost}}
Expand Down
Loading