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

GraphQL - Support admin per domain #3633

Merged
merged 13 commits into from
Apr 29, 2022

Conversation

Premwoik
Copy link
Contributor

@Premwoik Premwoik commented Apr 21, 2022

This PR addresses MIM-1639 and adds support for admin per domain. It introduces the third GraphQL listener that exposes the admin schema, but queries are restricted to the authorized domain admin. That means that the admin authorized for the localhost domain cannot execute queries for other domains (e.g. localhost2).

The domain admin credentials are stored in the new table domain_admin. Currently, the password is stored in plain form. The logic to manage domain admin was added to the mongoose_domain_api module.

The permissions, whether the given domain admin can execute queries are checked in the mongoose_graphql_permissions module. This module ensures that domain-protected field arguments cannot contain unauthorized domains.

The domain-protected field has to contain the following directive in the admin schema:

field(argA: String): String @protected(type: DOMAIN, args: ["argA"])

The directive type argument value DOMAIN means that the field must be domain checked, and the args argument stores field arguments to check.

The domain admin request authorization basic token should be encoded from the patternadmin@$domain:$password.

Fix the field() type

The field() type from the graphql core library was incorrect and to fix the dialyzer it had to be changed. I change the graphql dependency to the branch with the fix. It should be changed back after we merge the fix.
Premwoik/graphql-erlang#2

Next steps

  • Store the domain admin credentials in a more secure way.
  • Allow restricting fields to be executable only by global admin (not by domain admins).
  • Extend domain check for the domain-protected fields to support subdomains, JIDs, and input types.
  • Decide and mark fields that should be domain protected or executable only by global admin.
  • Add other missing test cases.

Questions

  • Make it possible to use domain admin not only for the RDBMS backends?
    Answer: There is no such need for now.

@Premwoik Premwoik force-pushed the graphql/support-admin-per-domain branch from 4809fd0 to 6127638 Compare April 25, 2022 21:34
@mongoose-im

This comment was marked as outdated.

@codecov
Copy link

codecov bot commented Apr 26, 2022

Codecov Report

Merging #3633 (2bf7c82) into feature/graphql (e85c138) will increase coverage by 0.05%.
The diff coverage is 95.61%.

@@                 Coverage Diff                 @@
##           feature/graphql    #3633      +/-   ##
===================================================
+ Coverage            81.64%   81.70%   +0.05%     
===================================================
  Files                  478      479       +1     
  Lines                33126    33226     +100     
===================================================
+ Hits                 27047    27146      +99     
- Misses                6079     6080       +1     
Impacted Files Coverage Δ
src/graphql/mongoose_graphql_permissions.erl 89.41% <88.63%> (-1.07%) ⬇️
src/domain/mongoose_domain_api.erl 100.00% <100.00%> (ø)
src/domain/mongoose_domain_sql.erl 94.16% <100.00%> (+1.24%) ⬆️
...graphql/admin/mongoose_graphql_admin_auth_info.erl 100.00% <100.00%> (ø)
src/graphql/admin/mongoose_graphql_admin_query.erl 100.00% <100.00%> (ø)
...l/admin/mongoose_graphql_domain_admin_mutation.erl 92.30% <100.00%> (+1.83%) ⬆️
src/graphql/mongoose_graphql.erl 91.30% <100.00%> (+0.19%) ⬆️
src/graphql/mongoose_graphql_cowboy_handler.erl 93.97% <100.00%> (+0.55%) ⬆️
src/graphql/mongoose_graphql_enum.erl 68.96% <100.00%> (+5.63%) ⬆️
src/graphql/mongoose_graphql_errors.erl 86.95% <100.00%> (+0.91%) ⬆️
... and 11 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e85c138...2bf7c82. Read the comment docs.

@mongoose-im

This comment was marked as outdated.

@Premwoik Premwoik force-pushed the graphql/support-admin-per-domain branch from 661ab1f to 995f125 Compare April 26, 2022 14:14
@mongoose-im

This comment was marked as outdated.

@mongoose-im

This comment was marked as outdated.

@mongoose-im

This comment was marked as outdated.

@Premwoik Premwoik force-pushed the graphql/support-admin-per-domain branch from d5d4198 to 5d40435 Compare April 26, 2022 21:55
@mongoose-im

This comment was marked as outdated.

@Premwoik Premwoik force-pushed the graphql/support-admin-per-domain branch from 5d40435 to 7a9c450 Compare April 26, 2022 22:20
@mongoose-im
Copy link
Collaborator

mongoose-im commented Apr 26, 2022

small_tests_24 / small_tests / 7a9c450
Reports root / small


small_tests_23 / small_tests / 7a9c450
Reports root / small


dynamic_domains_pgsql_mnesia_24 / pgsql_mnesia / 7a9c450
Reports root/ big
OK: 3045 / Failed: 1 / User-skipped: 133 / Auto-skipped: 0

bosh_SUITE:essential:accept_higher_hold_value
{error,
  {{assertEqual,
     [{module,bosh_SUITE},
      {line,251},
      {expression,"get_bosh_sessions ( )"},
      {expected,[]},
      {value,
        [{bosh_session,<<"4028267dfa18447ee7428e067c8d76e06d81aadb">>,
           <8641.6029.0>}]}]},
   [{bosh_SUITE,accept_higher_hold_value,1,
      [{file,"/home/circleci/project/big_tests/tests/bosh_SUITE.erl"},
       {line,251}]},
    {test_server,ts_tc,3,[{file,"test_server.erl"},{line,1783}]},
    {test_server,run_test_case_eval1,6,
      [{file,"test_server.erl"},{line,1292}]},
    {test_server,run_test_case_eval,9,
      [{file,"test_server.erl"},{line,1224}]}]}}

Report log


dynamic_domains_pgsql_mnesia_23 / pgsql_mnesia / 7a9c450
Reports root/ big
OK: 3046 / Failed: 0 / User-skipped: 133 / Auto-skipped: 0


dynamic_domains_mysql_redis_24 / mysql_redis / 7a9c450
Reports root/ big
OK: 3029 / Failed: 0 / User-skipped: 150 / Auto-skipped: 0


dynamic_domains_mssql_mnesia_24 / odbc_mssql_mnesia / 7a9c450
Reports root/ big
OK: 3058 / Failed: 1 / User-skipped: 133 / Auto-skipped: 0

muc_SUITE:hibernation:hibernated_room_can_be_queried_for_archive
{error,{{assertion_failed,assert,is_groupchat_message,
              [<<"Restorable message">>],
              undefined,"undefined"},
    [{escalus_new_assert,assert_true,2,
               [{file,"/home/circleci/project/big_tests/_build/default/lib/escalus/src/escalus_new_assert.erl"},
                {line,84}]},
     {muc_SUITE,wait_for_mam_result,3,
          [{file,"/home/circleci/project/big_tests/tests/muc_SUITE.erl"},
           {line,4383}]},
     {muc_SUITE,'-hibernated_room_can_be_queried_for_archive/1-fun-0-',3,
          [{file,"/home/circleci/project/big_tests/tests/muc_SUITE.erl"},
           {line,4124}]},
     {escalus_story,story,4,
            [{file,"/home/circleci/project/big_tests/_build/default/lib/escalus/src/escalus_story.erl"},
             {line,72}]},
     {muc_SUITE,hibernated_room_can_be_queried_for_archive,1,
          [{file,"/home/circleci/project/big_tests/tests/muc_SUITE.erl"},
           {line,4120}]},
     {test_server,ts_tc,3,[{file,"test_server.erl"},{line,1783}]},
     {test_server,run_test_case_eval1,6,
            [{file,"test_server.erl"},{line,1292}]},
     {test_server,run_test_case_eval,9,
            [{file,"test_server.erl"},{line,1224}]}]}}

Report log


ldap_mnesia_23 / ldap_mnesia / 7a9c450
Reports root/ big
OK: 1656 / Failed: 0 / User-skipped: 437 / Auto-skipped: 0


ldap_mnesia_24 / ldap_mnesia / 7a9c450
Reports root/ big
OK: 1656 / Failed: 0 / User-skipped: 437 / Auto-skipped: 0


internal_mnesia_24 / internal_mnesia / 7a9c450
Reports root/ big
OK: 1702 / Failed: 0 / User-skipped: 391 / Auto-skipped: 0


pgsql_mnesia_24 / pgsql_mnesia / 7a9c450
Reports root/ big
OK: 3420 / Failed: 0 / User-skipped: 142 / Auto-skipped: 0


elasticsearch_and_cassandra_24 / elasticsearch_and_cassandra_mnesia / 7a9c450
Reports root/ big
OK: 2016 / Failed: 0 / User-skipped: 392 / Auto-skipped: 0


pgsql_mnesia_23 / pgsql_mnesia / 7a9c450
Reports root/ big
OK: 3420 / Failed: 0 / User-skipped: 142 / Auto-skipped: 0


mysql_redis_24 / mysql_redis / 7a9c450
Reports root/ big
OK: 3415 / Failed: 0 / User-skipped: 147 / Auto-skipped: 0


mssql_mnesia_24 / odbc_mssql_mnesia / 7a9c450
Reports root/ big
OK: 3420 / Failed: 0 / User-skipped: 142 / Auto-skipped: 0


riak_mnesia_24 / riak_mnesia / 7a9c450
Reports root/ big
OK: 1863 / Failed: 0 / User-skipped: 387 / Auto-skipped: 0


dynamic_domains_pgsql_mnesia_24 / pgsql_mnesia / 7a9c450
Reports root/ big
OK: 3046 / Failed: 0 / User-skipped: 133 / Auto-skipped: 0

@Premwoik Premwoik marked this pull request as ready for review April 27, 2022 06:31
@Premwoik Premwoik removed the WIP 🚧 label Apr 27, 2022
Copy link
Member

@chrzaszcz chrzaszcz left a comment

Choose a reason for hiding this comment

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

Looks good in general, I added a few comments.

big_tests/tests/graphql_SUITE.erl Outdated Show resolved Hide resolved
priv/graphql/schemas/admin/admin_auth_status.gql Outdated Show resolved Hide resolved
src/domain/mongoose_domain_sql.erl Outdated Show resolved Hide resolved
transaction(fun(Pool) ->
case select_domain_admin(Domain) of
{ok, _} ->
update_domain_admin(Pool, Domain, Password),
Copy link
Member

Choose a reason for hiding this comment

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

Please cover with tests as there is a bug here - it would swap domain and password.

Comment on lines 159 to 160
%acc_path(Field, Acc) ->
%Acc#{path => [Field]}.
Copy link
Member

Choose a reason for hiding this comment

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

Some leftovers here?

acc([], Type) when is_atom(Type) -> false;
acc(Invalid, Type) when is_atom(Type) -> {true, #{type => Type, path => [], invalid => Invalid}}.

acc_path(_Field, false) -> false;
Copy link
Member

Choose a reason for hiding this comment

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

This function is hard to understand because it accepts too many different types: boolean, tuple, map. Function name does not help either.

test/mongoose_graphql_SUITE.erl Show resolved Hide resolved
test/mongoose_graphql_SUITE_data/listener_schema.gql Outdated Show resolved Hide resolved
@@ -3,11 +3,20 @@ schema{
mutation: UserMutation
}

directive @protected on FIELD_DEFINITION | OBJECT | INTERFACE
#directive @protected on FIELD_DEFINITION | OBJECT | INTERFACE
Copy link
Member

Choose a reason for hiding this comment

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

Remove this?

This upgrade graphql to version with field() type fix.
-spec check_fields(map(), map(), [field()]) -> [fail_acc()].
check_fields(Ctx, Params, Fields) ->
% Return empty list when permissions are valid.
lists:flatten(lists:filtermap(fun(F) -> check_field(F, Ctx, Params) end, Fields)).
Copy link
Member

Choose a reason for hiding this comment

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

Just an idea: maybe it would be cleaner to use lists:flatmap instead and always return a list form check_field?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed it completely. Now it stops checking at the first error that occurred. Previously only the first error was thrown anyway.

@Premwoik Premwoik force-pushed the graphql/support-admin-per-domain branch from 7a9c450 to d602b0a Compare April 29, 2022 09:00
@mongoose-im

This comment was marked as outdated.

@mongoose-im

This comment was marked as outdated.

…omain_admin

Minor changes:
- rename "domain_admin" table to "domain_admins",
- fix password update operation.
@Premwoik Premwoik force-pushed the graphql/support-admin-per-domain branch from c54e3c6 to 2bf7c82 Compare April 29, 2022 11:03
@mongoose-im
Copy link
Collaborator

mongoose-im commented Apr 29, 2022

small_tests_24 / small_tests / 2bf7c82
Reports root / small


small_tests_23 / small_tests / 2bf7c82
Reports root / small


dynamic_domains_pgsql_mnesia_24 / pgsql_mnesia / 2bf7c82
Reports root/ big
OK: 3052 / Failed: 0 / User-skipped: 133 / Auto-skipped: 0


dynamic_domains_pgsql_mnesia_23 / pgsql_mnesia / 2bf7c82
Reports root/ big
OK: 3052 / Failed: 0 / User-skipped: 133 / Auto-skipped: 0


dynamic_domains_mysql_redis_24 / mysql_redis / 2bf7c82
Reports root/ big
OK: 3035 / Failed: 0 / User-skipped: 150 / Auto-skipped: 0


ldap_mnesia_24 / ldap_mnesia / 2bf7c82
Reports root/ big
OK: 1656 / Failed: 0 / User-skipped: 443 / Auto-skipped: 0


ldap_mnesia_23 / ldap_mnesia / 2bf7c82
Reports root/ big
OK: 1656 / Failed: 0 / User-skipped: 443 / Auto-skipped: 0


dynamic_domains_mssql_mnesia_24 / odbc_mssql_mnesia / 2bf7c82
Reports root/ big
OK: 3052 / Failed: 0 / User-skipped: 133 / Auto-skipped: 0


internal_mnesia_24 / internal_mnesia / 2bf7c82
Reports root/ big
OK: 1702 / Failed: 0 / User-skipped: 397 / Auto-skipped: 0


pgsql_mnesia_24 / pgsql_mnesia / 2bf7c82
Reports root/ big
OK: 3426 / Failed: 0 / User-skipped: 142 / Auto-skipped: 0


pgsql_mnesia_23 / pgsql_mnesia / 2bf7c82
Reports root/ big
OK: 3426 / Failed: 0 / User-skipped: 142 / Auto-skipped: 0


mysql_redis_24 / mysql_redis / 2bf7c82
Reports root/ big
OK: 3421 / Failed: 0 / User-skipped: 147 / Auto-skipped: 0


elasticsearch_and_cassandra_24 / elasticsearch_and_cassandra_mnesia / 2bf7c82
Reports root/ big
OK: 2015 / Failed: 1 / User-skipped: 398 / Auto-skipped: 0

bosh_SUITE:essential_https:accept_higher_hold_value
{error,
  {{assertEqual,
     [{module,bosh_SUITE},
      {line,251},
      {expression,"get_bosh_sessions ( )"},
      {expected,[]},
      {value,
        [{bosh_session,<<"45a58ea2e708060fc49497662cd24303a9f4e06c">>,
           <8653.5525.0>}]}]},
   [{bosh_SUITE,accept_higher_hold_value,1,
      [{file,"/home/circleci/project/big_tests/tests/bosh_SUITE.erl"},
       {line,251}]},
    {test_server,ts_tc,3,[{file,"test_server.erl"},{line,1783}]},
    {test_server,run_test_case_eval1,6,
      [{file,"test_server.erl"},{line,1292}]},
    {test_server,run_test_case_eval,9,
      [{file,"test_server.erl"},{line,1224}]}]}}

Report log


mssql_mnesia_24 / odbc_mssql_mnesia / 2bf7c82
Reports root/ big
OK: 3426 / Failed: 0 / User-skipped: 142 / Auto-skipped: 0


riak_mnesia_24 / riak_mnesia / 2bf7c82
Reports root/ big
OK: 1863 / Failed: 0 / User-skipped: 393 / Auto-skipped: 0


elasticsearch_and_cassandra_24 / elasticsearch_and_cassandra_mnesia / 2bf7c82
Reports root/ big
OK: 2016 / Failed: 0 / User-skipped: 398 / Auto-skipped: 0

@Premwoik Premwoik requested a review from chrzaszcz April 29, 2022 12:06
Copy link
Member

@chrzaszcz chrzaszcz left a comment

Choose a reason for hiding this comment

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

Looks good 👍

@chrzaszcz chrzaszcz merged commit a6a323b into feature/graphql Apr 29, 2022
@chrzaszcz chrzaszcz deleted the graphql/support-admin-per-domain branch April 29, 2022 13:50
@chrzaszcz chrzaszcz added this to the 6.0.0 milestone Dec 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants