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

Improve Authentication object structure #233

Closed
andreysubbotin opened this issue Sep 6, 2021 · 6 comments · Fixed by #2209
Closed

Improve Authentication object structure #233

andreysubbotin opened this issue Sep 6, 2021 · 6 comments · Fixed by #2209
Assignees
Labels
breaking changes Fix brings breaking changes in code or behavior in: security size: L
Milestone

Comments

@andreysubbotin
Copy link
Contributor

andreysubbotin commented Sep 6, 2021

Currently, authentication objects represent a complex object structure.
The object structure contains:

  • Resource roles with their policies.
  • Row-level roles with in-memory predicates (that are represented as java lambdas)

Possible problems due to the given structure of objects:

  • Serialization problems. Spring mechanisms like Sessions/OAuth2 serialize/deserialize authentication objects. It's hard to serialize/deserialize the Java lambda function and restore the Spring Application context during deserialization.
  • Integration with external authentication providers like OAuth2 Keycloak provider. Typically OAuth2 JWT token contains only role names or scopes of a user. Jmix security subsystem should convert JWT token to authentication object and map role names to resource/row level roles. Mapping from role names to resource/row level is a customization that doesn't allow to use of standard Spring Security functionality: Oauth Resource Server.
  • Memory. Resource/row level roles are stored for each user session.

Solution:
Store only role names on an authentication object. This will solve the problems described above.
The authorization process should load resource/row level roles from the in-memory cache (for performance reasons) by their names and checks permissions for objects by roles from cache.

@andreysubbotin andreysubbotin added this to the 1.1.0 milestone Sep 6, 2021
@knstvk knstvk removed this from the 1.1.0 milestone Sep 13, 2021
@knstvk
Copy link
Contributor

knstvk commented Nov 14, 2021

See also jmix-projects/jmix-security#117

@knstvk knstvk added the size: L label Mar 19, 2022
@knstvk knstvk added the candidate Possible candidate for future releases label Jul 5, 2023
@gorbunkov gorbunkov removed the candidate Possible candidate for future releases label Jul 24, 2023
gorbunkov added a commit that referenced this issue Sep 11, 2023
Role names are stored as strings in the Authentication object;
RoleGrantedAuthorityUtils class must be used for role granted authorities creation;
BaseRoleRepository inheritance is replaced by delegating to new RoleRepositoryProviderUtils;
Spring cache is used for resource and row-level roles;
Add jmix-security-starter to build.gradle in project templates;
@gorbunkov gorbunkov linked a pull request Sep 11, 2023 that will close this issue
@gorbunkov
Copy link
Contributor

gorbunkov commented Sep 11, 2023

Implementation details

Previously, the Authentication object contained roles and policies inside it. A special RoleGrantedAuthority object was put into the Authentication.

Now we store just role names in the Authentication object. Roles are stored as instances of SimpleGrantedAuthority class.
Jmix resource roles are represented as strings consisting of the ROLE_ prefix and resource role code, e.g. ROLE_system-full-access.
Row-level roles are represented as strings consisting of the ROW_LEVEL_ROLE_ prefix and row-level role code, e.g. ROW_LEVEL_ROLE_my-role-code.

To create an instance of granted authority for resource or row-level role a io.jmix.security.role.RoleGrantedAuthorityUtils bean may be used. See:

  • io.jmix.security.role.RoleGrantedAuthorityUtils#createResourceRoleGrantedAuthority(java.lang.String)
  • io.jmix.security.role.RoleGrantedAuthorityUtils#createRowLevelRoleGrantedAuthority(java.lang.String)

A prefix for resource role authority may be set using standard spring mechanism: by the org.springframework.security.config.core.GrantedAuthorityDefaults bean.

A prefix for row-level role authority may be set using the jmix.security.default-row-level-role-prefix application property.

The fact that Authentication now only stores role names makes us request role policies each time we need to check any grant. Because of this RowLevelRepository and ResourceRoleRepository now use roles cache. Roles cache is cleared when any role is updated in the database (using views for runtime roles editing) or when annotated role is hot-deployed.

ResourceRole and RowLevelRole together with their policies are now serializable. Roles store policies in a special data structure (ResourcePoliciesIndex and RowLevelPoliciesIndex) that speeds up a search for policies based on some criterion, e.g. "give me resource policies with the type "entity" and the resource "sec_User".

Breaking Changes

A jmix-security-starter must be added to build.gradle of existing project. This is required because the io.jmix.autoconfigure.security.SecurityAutoConfiguration now contains roles caches initialization.

implementation 'io.jmix.security:jmix-security-starter'

Jmix Studio issue for adding the starter on project migration: https://youtrack.jmix.io/issue/JST-4328

A RoleGrantedAuthority class has been removed. If users created authentication authorities manually they will have to use the RoleGrantedAuthorityUtils or create Spring's SimpleGrantedAuthority instances.

@gorbunkov gorbunkov added breaking changes Fix brings breaking changes in code or behavior in: security labels Sep 11, 2023
@gorbunkov
Copy link
Contributor

For QA.

Do the smoke test of security:

  • Resource and row-level roles
  • Annotated and database roles
  • All policies (entity, attributes, specific, etc.) types
  • Changes of database roles
  • Hot deploy of annotated roles
  • Roles in REST API and OIDC add-ons

@rusiaikinat rusiaikinat self-assigned this Oct 16, 2023
@rusiaikinat
Copy link

rusiaikinat commented Oct 18, 2023

  • Resource and row-level roles
  • Annotated and database roles
  • All policies (entity, attributes, specific, etc.) types
  • Changes of database roles
  • Hot deploy of annotated roles
  • Roles in REST API and OIDC add-ons

@rusiaikinat
Copy link

rusiaikinat commented Oct 18, 2023

Reopened
OIDC add-ons

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'oidc_OAuthLoginSecurityFilterChain' defined in class path resource [io/jmix/autoconfigure/oidc/OidcAutoConfiguration$OAuth2LoginSecurityConfiguration.class]: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'securityFilterChain' threw exception with message: This method cannot decide whether these patterns are Spring MVC patterns or not. If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); otherwise, please use requestMatchers(AntPathRequestMatcher).

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'securityFilterChain' threw exception with message: This method cannot decide whether these patterns are Spring MVC patterns or not. If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); otherwise, please use requestMatchers(AntPathRequestMatcher).

Caused by: java.lang.IllegalArgumentException: This method cannot decide whether these patterns are Spring MVC patterns or not. If this endpoint is a Spring MVC endpoint, please use requestMatchers(MvcRequestMatcher); otherwise, please use requestMatchers(AntPathRequestMatcher).

@gorbunkov
Copy link
Contributor

OIDC issue fixed in commit aedef92

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking changes Fix brings breaking changes in code or behavior in: security size: L
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

4 participants