REST API - Anonymous Access

HI,
As per the document I setup REST API ‘add on’.
Then created new entity…
Updated application.properties file with jmix.rest.anonymousUrlPatterns=/rest/entities/Country
And also set up initAnonymousUser() with rest-minimal role .
Still I getting issue while hitting REST API - Reading forbidden

Hi
Have you assigned the rest API role to the user?

Yes, In DatabaseUserRepository I updated initAnonymousUser() with rest-minimal role.

I see you are trying to access Entity Country, did you also give REST user access to this entity?

I am trying to set AnonymousUser access.Is there any way to setup Anonymous user access to on Entity. Can you please let us know the steps

Apart from setting the jmix.rest.anonymousUrlPatterns=/rest/entities/Country property, you should give the anonymous user rights to the Country entity. For example, create a resource role:

package com.company.demo.security;

import com.company.demo.entity.Country;
import io.jmix.security.model.EntityAttributePolicyAction;
import io.jmix.security.model.EntityPolicyAction;
import io.jmix.security.role.annotation.EntityAttributePolicy;
import io.jmix.security.role.annotation.EntityPolicy;
import io.jmix.security.role.annotation.ResourceRole;

@ResourceRole(name = "AnonymousRestRole", code = AnonymousRestRole.CODE, scope = "API")
public interface AnonymousRestRole {

    String CODE = "anonymous-rest-role";

    @EntityAttributePolicy(entityClass = Country.class, attributes = "*", action = EntityAttributePolicyAction.VIEW)
    @EntityPolicy(entityClass = Country.class, actions = EntityPolicyAction.READ)
    void country();
}

The assign it to the anonymous user:

@Primary
@Component("UserRepository")
public class DatabaseUserRepository extends AbstractDatabaseUserRepository<User> {
    // ...
    @Override
    protected void initAnonymousUser(User anonymousUser) {
        Collection<GrantedAuthority> authorities = getGrantedAuthoritiesBuilder()
                .addResourceRole(AnonymousRestRole.CODE)
                .build();
        anonymousUser.setAuthorities(authorities);
    }
}
1 Like

Hi, the example provided, as the one reported in the documentation, isn’t complete about the class DatabaseUserRepository.

Can you provide a working example, replacing the … dots with the missing part, and giving some hints on the package required for this class?

It would be very helpful.

To be more clear, I’m trying to update an entity, with the following PUT call:

http://localhost:8080/rest/entities/PTT_JobLog/5

Here is the configuration of application.properties, you can find duplicated properties, because it is not clear which property is used:

jmix.rest.anonymousUrlPatterns=/rest/entities/PTT_JobLog
jmix.rest.anonymous-url-patterns=/rest/entities/PTT_JobLog
jmix.rest.anonymousEnabled=true
jmix.rest.anonymous-enabled=true

Here is the entity definition. I understood that the REST endpoint uses the entity name, not the class name:

@JmixEntity
@Table(name="job_log_entries", schema="pto")
@Entity(name = "PTT_JobLog")
public class JobLog {
      ....

I have created an annotated interface to add the UPDATE permission on all the attributes of the entity:

@ResourceRole(name = "AnonymousRestRole", code = AnonymousRestRole.CODE, scope = "API")
public interface AnonymousRestRole {

    String CODE = "anonymous-rest-role";

    @EntityAttributePolicy(entityClass = JobLog.class,
            attributes = "*",
            action = EntityAttributePolicyAction.MODIFY)
    @EntityPolicy(entityClass = JobLog.class,
            actions = EntityPolicyAction.UPDATE)
    void jobLog();
}

The void method is named as the class name, with the first letter in lowercase.

Finally I have updated the DatabaseUserRepository in order to implement the required methods:

@Primary
@Component("PTT_UserRepository")
public class DatabaseUserRepository extends AbstractDatabaseUserRepository<User> {

    @Override
    protected Class<User> getUserClass() {
        return User.class;
    }

    @Override
    protected void initSystemUser(User systemUser) {
        Collection<GrantedAuthority> authorities = getGrantedAuthoritiesBuilder()
                .addResourceRole(FullAccessRole.CODE)
                .build();
        systemUser.setAuthorities(authorities);
    }

    @Override
    protected void initAnonymousUser(User anonymousUser) {
        Collection<GrantedAuthority> authorities = getGrantedAuthoritiesBuilder()
                .addResourceRole(AnonymousRestRole.CODE)
                .addResourceRole(RestMinimalRole.CODE)
                .build();
        anonymousUser.setAuthorities(authorities);
    }
}

Executing the PUT, I receive the following error:

{
    "error": "unauthorized",
    "error_description": "Full authentication is required to access this resource"
}

It seems that the anonymous configuration is ignored. I tried also a call using OAuth authentication and a named user, and everything works.

When you see the “Full authentication is required to access this resource” it most probably means that the URL of the request doesn’t match the patterns specified for anonymous access.

In your case, the following patterns are required (because the PUT request has id part):

jmix.rest.anonymous-url-patterns=/rest/entities/PTT_JobLog,\
  /rest/entities/PTT_JobLog/*

Also, you need the READ permission for the entity (it isn’t assumed when you enable UPDATE):

@EntityAttributePolicy(entityClass = JobLog.class,
        attributes = "*",
        action = EntityAttributePolicyAction.MODIFY)
@EntityPolicy(entityClass = JobLog.class,
        actions = {EntityPolicyAction.READ, EntityPolicyAction.UPDATE})
void jobLog();
1 Like

Many thanks. The missing part was the final ‘/*’ in the allowed path. Also the clarification on READ permission was very helpful.